pull/310/head
Konrad Weiss 7 years ago
commit 5763ebf1e6
  1. 81
      .circleci/config.yml
  2. 13
      .coveragerc
  3. 3
      .editorconfig
  4. 16
      .github/ISSUE_TEMPLATE/analysis-module.md
  5. 28
      .github/ISSUE_TEMPLATE/bug_report.md
  6. 182
      .gitignore
  7. 16
      CONTRIBUTING.md
  8. 26
      Dockerfile
  9. 2
      MANIFEST.in
  10. 20
      Pipfile
  11. 716
      Pipfile.lock
  12. 26
      README.md
  13. 33
      all_tests.sh
  14. 9
      coverage_report.sh
  15. 15
      docker_build_and_deploy.sh
  16. 19
      mythril/analysis/callgraph.py
  17. 57
      mythril/analysis/modules/delegatecall.py
  18. 4
      mythril/analysis/modules/deprecated_ops.py
  19. 2
      mythril/analysis/modules/integer.py
  20. 59
      mythril/analysis/modules/multiple_sends.py
  21. 2
      mythril/analysis/modules/transaction_order_independence.py
  22. 2
      mythril/analysis/modules/unchecked_retval.py
  23. 2
      mythril/analysis/ops.py
  24. 94
      mythril/analysis/report.py
  25. 2
      mythril/analysis/symbolic.py
  26. 0
      mythril/analysis/templates/callgraph.html
  27. 37
      mythril/analysis/templates/report_as_markdown.jinja2
  28. 29
      mythril/analysis/templates/report_as_text.jinja2
  29. 2
      mythril/analysis/traceexplore.py
  30. 1
      mythril/disassembler/disassembly.py
  31. 157
      mythril/ether/contractstorage.py
  32. 4
      mythril/ether/soliditycontract.py
  33. 46
      mythril/interfaces/cli.py
  34. 0
      mythril/laser/__init__.py
  35. 0
      mythril/laser/ethereum/__init__.py
  36. 74
      mythril/laser/ethereum/gascost.py
  37. 122
      mythril/laser/ethereum/helper.py
  38. 0
      mythril/laser/ethereum/modules/__init__.py
  39. 88
      mythril/laser/ethereum/natives.py
  40. 1206
      mythril/laser/ethereum/svm.py
  41. 309
      mythril/laser/ethereum/taint_analysis.py
  42. 48
      mythril/leveldb/client.py
  43. 8
      mythril/leveldb/state.py
  44. 92
      mythril/mythril.py
  45. 2
      mythril/support/signatures.py
  46. 6
      mythril/support/truffle.py
  47. 31
      requirements.txt
  48. 62
      setup.py
  49. 3
      solidity_examples/ether_send.sol
  50. 3
      tests/__init__.py
  51. 0
      tests/analysis/__init__.py
  52. 249
      tests/analysis/test_delegatecall.py
  53. 32
      tests/contractstorage_test.py
  54. 117
      tests/native_test.py
  55. 166
      tests/native_tests.sol
  56. 56
      tests/report_test.py
  57. 86
      tests/svm_test.py
  58. 29
      tests/taint_mutate_stack_test.py
  59. 36
      tests/taint_record_test.py
  60. 36
      tests/taint_result_test.py
  61. 94
      tests/taint_runner_test.py
  62. 3
      tests/testdata/input_contracts/ether_send.sol
  63. 6
      tests/testdata/input_contracts/nonascii.sol
  64. 152
      tests/testdata/input_contracts/rubixi.sol
  65. 2
      tests/testdata/inputs/ether_send.sol.o
  66. 1
      tests/testdata/inputs/nonascii.sol.o
  67. 70
      tests/testdata/outputs_expected/calls.sol.o.markdown
  68. 58
      tests/testdata/outputs_expected/calls.sol.o.text
  69. 716
      tests/testdata/outputs_expected/ether_send.sol.o.easm
  70. 4
      tests/testdata/outputs_expected/ether_send.sol.o.graph.html
  71. 4
      tests/testdata/outputs_expected/ether_send.sol.o.json
  72. 4
      tests/testdata/outputs_expected/ether_send.sol.o.markdown
  73. 4
      tests/testdata/outputs_expected/ether_send.sol.o.text
  74. 167
      tests/testdata/outputs_expected/nonascii.sol.o.easm
  75. 56
      tests/testdata/outputs_expected/nonascii.sol.o.graph.html
  76. 1
      tests/testdata/outputs_expected/nonascii.sol.o.json
  77. 3
      tests/testdata/outputs_expected/nonascii.sol.o.markdown
  78. 1
      tests/testdata/outputs_expected/nonascii.sol.o.text
  79. 2
      tests/testdata/outputs_expected/origin.sol.o.json
  80. 2
      tests/testdata/outputs_expected/origin.sol.o.markdown
  81. 2
      tests/testdata/outputs_expected/origin.sol.o.text
  82. 18
      tests/testdata/outputs_expected/overflow.sol.o.markdown
  83. 18
      tests/testdata/outputs_expected/overflow.sol.o.text
  84. 18
      tests/testdata/outputs_expected/underflow.sol.o.markdown
  85. 18
      tests/testdata/outputs_expected/underflow.sol.o.text
  86. 57499
      tests/testdata/outputs_expected_laser_result/calls.sol.json
  87. 61845
      tests/testdata/outputs_expected_laser_result/ether_send.sol.json
  88. 59235
      tests/testdata/outputs_expected_laser_result/exceptions.sol.json
  89. 73258
      tests/testdata/outputs_expected_laser_result/kinds_of_calls.sol.json
  90. 40884
      tests/testdata/outputs_expected_laser_result/metacoin.sol.json
  91. 11621
      tests/testdata/outputs_expected_laser_result/multi_contracts.sol.json
  92. 42097
      tests/testdata/outputs_expected_laser_result/nonascii.sol.json
  93. 24336
      tests/testdata/outputs_expected_laser_result/origin.sol.json
  94. 52771
      tests/testdata/outputs_expected_laser_result/overflow.sol.json
  95. 17652
      tests/testdata/outputs_expected_laser_result/returnvalue.sol.json
  96. 1141641
      tests/testdata/outputs_expected_laser_result/rubixi.sol.json
  97. 8420
      tests/testdata/outputs_expected_laser_result/suicide.sol.json
  98. 52771
      tests/testdata/outputs_expected_laser_result/underflow.sol.json
  99. 41
      tox.ini

@ -1,11 +1,12 @@
version: 2
defaults: &defaults
docker:
- image: mythril/dev_test_environment:latest
version: 2
jobs:
# Basic testing of a new commit to any branch.
test:
docker:
- image: birdofpreyru/mythril:0.0.1
<<: *defaults
steps:
- checkout:
path: /home/mythril
@ -14,13 +15,23 @@ jobs:
# path param in checkout command, and this symlink compenstates for that.
# - run: ln -s /root/project /home/mythril
- run:
name: Installing mythril tools
command: cd /home && ./install-mythril-tools.sh laser-ethereum
- restore-cache:
keys:
- tox-env-{{ checksum "/home/mythril/setup.py" }}
- run:
name: Install dependencies, in case any are missing in Docker image
command: pip3 install -r /home/mythril/requirements.txt
name: Install tox envs
command: tox -vv --notest
working_directory: /home/mythril
environment:
LC_ALL: en_US.ASCII
LANG: en_US.ASCII
- save_cache:
key: tox-env-{{ checksum "/home/mythril/setup.py" }}
paths:
- .tox/py*
- /root/.cache/pip/wheels/
- run:
background: true
@ -29,33 +40,55 @@ jobs:
- run:
name: Unit-testing
command: cd /home/mythril && ./all_tests.sh
command: tox
working_directory: /home/mythril
environment:
LC_ALL: en_US.ASCII
LANG: en_US.ASCII
- store_test_results:
path: /tmp/test-reports
path: /home/mythril/.tox/output
- store_artifacts:
path: /tmp/test-reports
path: /home/mythril/.tox/output
- run:
name: Ensuring that setup script is functional
command: cd /home/mythril && python3 setup.py install
command: python3 setup.py install
working_directory: /home/mythril
deploy:
docker:
- image: birdofpreyru/mythril:0.0.1
- run:
name: Integration tests
command: if [ -z "$CIRCLE_PR_NUMBER" ]; then ./run-integration-tests.sh; fi
working_directory: /home
pypi_release:
<<: *defaults
steps:
- checkout:
path: /home/mythril
- run:
name: Verify Git tag vs. version
command: cd /home/mythril && python3 setup.py verify
command: python3 setup.py verify
working_directory: /home/mythril
- run:
name: Build
command: cd /home/mythril && python3 setup.py sdist
command: python3 setup.py sdist
working_directory: /home/mythril
- run:
name: Deploy
command: cd /home/mythril && twine upload dist/*
command: twine upload dist/*
working_directory: /home/mythril
dockerhub_release:
docker:
- image: docker:stable
steps:
- checkout
- setup_remote_docker
- run:
name: Building Docker Image
command: ./docker_build_and_deploy.sh
workflows:
version: 2
@ -65,7 +98,15 @@ workflows:
filters:
tags:
only: /.*/
- deploy:
- pypi_release:
filters:
branches:
ignore: /.*/
tags:
only: /v[0-9]+(\.[0-9]+)*/
requires:
- test
- dockerhub_release:
filters:
branches:
ignore: /.*/

@ -1,13 +0,0 @@
[run]
source =
.
[report]
omit =
*__init__.py
/usr/*
*_test.py
setup.py
[html]
directory = coverage_html_report

@ -8,3 +8,6 @@ insert_final_newline = true
indent_style = space
indent_size = 4
charset = utf-8
[*.jinja2]
insert_final_newline = false

@ -0,0 +1,16 @@
---
name: Analysis module
about: Create an analysis module feature request
---
# Detection issue:
Name the issue that should be detected using the analysis module
## Description:
Provide a detailed description of the vulnerabiltity that should be detected
## Link
Provide resources that can help with implementing the analysis module
## Implementation details:Initial implementation ideas/instruction

@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

182
.gitignore vendored

@ -1,20 +1,182 @@
.DS_Store
# Created by https://www.gitignore.io/api/linux,macos,python,windows
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
.pytest_cache/
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
__pycache__
*.pyc
# celery beat schedule file
celerybeat-schedule.*
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/linux,macos,python,windows
*.asm
mythril.egg-info
build
dist
*.rst
*.lock
!Pipfile.lock
*.svg
laser*
lol*
.idea*
coverage_html_report/
.coverage
.pytest_cache
tests/testdata/outputs_current/
tests/testdata/outputs_current_laser_result/
tests/mythril_dir/signatures.json
# VSCode
.vscode

@ -0,0 +1,16 @@
# Contributing to Mythril
Hi, if you are reading this that means that you probably want to contribute to Mythril, awesome! If not, then this file might not contain much useful information for you.
## Creating an issue
If you have found a problem with Mythril or want to propose a new feature then you can do this using GitHub issues.
We already created some templates to make this process easier, but if your issue/feature request does not fit within the template then feel free to deviate.
If you have a small question or aren't sure if you should create an issue for your problem/suggestion then you can always hop by on our [Gitter channel](https://gitter.im/ConsenSys/mythril).
# Coding
If you want to help out with the development of Mythril then you can take a look at our issues or [Waffle board](https://waffle.io/ConsenSys/mythril).
Before you start working on an issue pkease stop by on Gitter to message a collaborator, this way we can assign you to the issue making sure nobody does double work. We can also provide you with support through Gitter if there are any questions during the development process.
## New ideas
Before you start working on a new idea, it's useful to create an issue on GitHub, that way we know what you want to implement and that you are working on it. Additionally, it might happen that your feature does not fit with our roadmap, in which case it would be unfortunate if you have already spent some time working on it.

@ -1,19 +1,25 @@
FROM ubuntu:rolling
FROM ubuntu:bionic
COPY . .
COPY . /opt/mythril
RUN apt-get update \
&& apt-get install -y software-properties-common \
&& apt-get install -y \
build-essential \
python-pip-whl=9.0.1-2 \
python3-pip=9.0.1-2 \
python3-setuptools \
software-properties-common \
&& add-apt-repository -y ppa:ethereum/ethereum \
&& apt-get update \
&& apt-get install -y solc \
&& apt-get install -y libssl-dev \
&& apt-get install -y python3-pip=9.0.1-2 python3-dev \
&& apt-get install -y \
solc \
libssl-dev \
python3-dev \
pandoc \
git \
&& ln -s /usr/bin/python3 /usr/local/bin/python \
# && pip3 install --upgrade pip \
&& apt-get install -y pandoc \
&& apt-get install -y git \
&& cd /opt/mythril \
&& pip3 install -r requirements.txt \
&& python setup.py install
CMD []
ENTRYPOINT ["/usr/local/bin/myth"]

@ -1,2 +1,2 @@
include mythril/disassembler/signatures.json
include mythril/analysis/templates/*.html
include mythril/analysis/templates/*

@ -4,28 +4,16 @@ verify_ssl = true
name = "pypi"
[packages]
requests = "*"
plyvel = "*"
py-solc = "*"
coverage = "*"
BTrees = "*"
ethereum = ">=2.3.0"
zodb = ">=5.3.0"
eth-abi = "*"
"z3-solver" = ">=4.5"
eth-account = "*"
eth-tester = "*"
laser-ethereum = ">=0.5.20"
"jinja2" = "*"
attrs = ">=17.0.0"
rlp = "<1.0.0"
"e1839a8" = {path = ".", editable = true}
[dev-packages]
pylint = "*"
yapf = "*"
pytest = "*"
pytest-mock = "*"
pytest-cov = "*"
[requires]
python_version = "3.6"
[pipenv]
allow_prereleases = true

716
Pipfile.lock generated

@ -1,716 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "b8b7e52dd560311e7e06c0c51ab86c67503a1b7d7499e372ad00698acc16f43c"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"asn1crypto": {
"hashes": [
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
"sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"
],
"version": "==0.24.0"
},
"attrdict": {
"hashes": [
"sha256:86aeb6d3809e0344409f8148d7cac9eabce5f0b577c160b5e90d10df3f8d2ad3"
],
"version": "==2.0.0"
},
"attrs": {
"hashes": [
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9",
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"
],
"index": "pypi",
"version": "==17.4.0"
},
"btrees": {
"hashes": [
"sha256:46b02cb69b26a5238db771ea1955b503df73ecf254bb8063af4c61999fc75b5c",
"sha256:4986f7ea25013e0370d88a4699490f83da92745705001b3d619de7d9600edc66",
"sha256:4996f282254bc30ab3855df4b757a675d043edf069368ac8e9ac1fadcaebb89b",
"sha256:4c77eed4ae3e182de559296893ae00b8da3201d51c51751787b53b34ac3b1a79",
"sha256:888c016774630b7be2339888df1d0e7c91e1e0139e1b9ec80309feb1fc6fd9ec",
"sha256:895e5d173dd77989d8b9b9649e01a2509c6553ca3820c15f058e129fcbdab88c",
"sha256:a80c5f14eac095502b5ba6adfdbea7a891dc5d761efeef75d11c2dbed7a9e5f0",
"sha256:acfdd66a3db6753cec1a06345fbef27b4cc592e269dfc162fa1f881230d1addc",
"sha256:df8a059fc7c43ae34c47806be00021432988efdc8b24e8422fa6a785c9c78150"
],
"index": "pypi",
"version": "==4.5.0"
},
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"cffi": {
"hashes": [
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
],
"version": "==1.11.5"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"coincurve": {
"hashes": [
"sha256:14f775b2a2034661ba125655529c883ba09936d16edd2edd28714d9be6ed7ca8",
"sha256:23bb379ab641423aea822effc3c63f06893f126cfd877e310382549048b6c4a6",
"sha256:29252b639e4c86d258cd01f747a8a00bc3e0533606e04cd1716af4b27cdcfe35",
"sha256:59bf263ce47e25865ea3491fa4d2d075ca3feb77d5ba961e95124d20b97916f8",
"sha256:605e73623f3b4d7a041af8032d55902fbb6b36151db427bad1655493a9bafcb3",
"sha256:683efd4f0ee89fa15ce7d6c4bb0cb48c86178f66a5d8538698ffdad8a079df3a",
"sha256:76b8c2738c9535223248c8da2b71de791b50ef18b6b8f1cd11b16242af9096b2",
"sha256:7afa48c11124b1d14baf63ef543e3438af0d8ba82b580f7a3b0c82b1fae2c697",
"sha256:7d66d081f46ce0e2c63d55cc791e7c1e6b0115eaee3c965edc0fb4f93d541537",
"sha256:7eaaa1d73084ed3436d64096dd8a22fd76a58f3cdbf5e3e3b949e73e694e17b6",
"sha256:9f565ca651e4304387460d8230cd8cc23ccea97c4a03f260b6b6238728516122",
"sha256:ad41b88ceffb953f4abc8c2b09123aeb4ba2f6949301ba1a8908832415f38255",
"sha256:ca8008b6c32726f15a50c3e9bac81c22d370b466377b21a8104e263610e90d94",
"sha256:ed671ecef3eb69aa46f1805d136b793a627fce94fc90d20f86ac5a357e00c08f"
],
"version": "==7.1.0"
},
"coverage": {
"hashes": [
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
"sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed",
"sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a",
"sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd",
"sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640",
"sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2",
"sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162",
"sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508",
"sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249",
"sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694",
"sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a",
"sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287",
"sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1",
"sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000",
"sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1",
"sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e",
"sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5",
"sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062",
"sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba",
"sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc",
"sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc",
"sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99",
"sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653",
"sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c",
"sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558",
"sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f",
"sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4",
"sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91",
"sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d",
"sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9",
"sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd",
"sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d",
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80",
"sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e"
],
"index": "pypi",
"version": "==4.5.1"
},
"cytoolz": {
"hashes": [
"sha256:84cc06fa40aa310f2df79dd440fc5f84c3e20f01f9f7783fc9c38d0a11ba00e5"
],
"version": "==0.9.0.1"
},
"dictionaries": {
"hashes": [
"sha256:1ec6d4b2e2c5762a7423f66a3b423bc976439137e1537df5a164ea040abca2cb",
"sha256:26e0c57694d5e01b648c058939d69fbdc6d0caf04cd5b70cb7b4a69e577c1c31"
],
"version": "==0.0.1"
},
"eth-abi": {
"hashes": [
"sha256:3b965a707640cac5260208ceb58e02fd41b58b8e356dc95784dfdef8e3b1d4d0",
"sha256:58aed210e49da6bd318c026d306da2bf4c63022745460a791546ac10c4982162"
],
"index": "pypi",
"version": "==1.0.0"
},
"eth-account": {
"hashes": [
"sha256:8c33e63e1e04527a37e00616569313e009db1efc5619731f3d4ec8890eea5ca4",
"sha256:c386f0e3e2e3b56c6f564fa4001a05d5dca5844e69794750e8a7621083308941"
],
"index": "pypi",
"version": "==0.2.0"
},
"eth-hash": {
"hashes": [
"sha256:43adcab75a957fcf8c453d5542be55e4e0bd4e166270f45b09ac69b4d6486a06",
"sha256:8695f5f3794497d1357b2ef6e84c67a7daf4bfec1dde9f76ff6b2022c2cc03a6"
],
"version": "==0.1.2"
},
"eth-keyfile": {
"hashes": [
"sha256:70d734af17efdf929a90bb95375f43522be4ed80c3b9e0a8bca575fb11cd1159",
"sha256:939540efb503380bc30d926833e6a12b22c6750de80feef3720d79e5a79de47d"
],
"version": "==0.5.1"
},
"eth-keys": {
"hashes": [
"sha256:5ab2612f457452dc0a318655051cdd05c20f4db2f445003a46c98d324101b0e4",
"sha256:b48fc92a527bd905525855ebe45e79ba17be6654c4bedb947119648c145c74c0"
],
"version": "==0.2.0b3"
},
"eth-rlp": {
"hashes": [
"sha256:1330ebf341cd13fefbd9edaa038054cb19bc38368f866eb777f1f880577ed499",
"sha256:773bd96b4b83939822ef5d7dffa90448d5ccc2d38e5aeb03850c808ae43c183d"
],
"version": "==0.1.0"
},
"eth-tester": {
"hashes": [
"sha256:2e85782fc0627c5f29ed143865b8c3f27411bc28c78d6273ea797a24527e265c",
"sha256:836695b7c3159c9d9461de3397c5e1b044d798e785181c3de2012ad04be0a2f6"
],
"index": "pypi",
"version": "==0.1.0b23"
},
"eth-utils": {
"hashes": [
"sha256:0eb71bdafda7e7e4c80ba98c06b3f89472e8ba0183a149be678f13cbb3b2e9b4",
"sha256:add4cc71b64e40b15c1e7b037905daf59da58e046004bde7a2915f86a7fc8e57"
],
"version": "==1.0.3"
},
"ethereum": {
"hashes": [
"sha256:69a22c2f793970d184777bb92589e67d0f622d56eda7c3c1bfc1f0edad522c1c"
],
"index": "pypi",
"version": "==2.3.1"
},
"future": {
"hashes": [
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
],
"version": "==0.16.0"
},
"hexbytes": {
"hashes": [
"sha256:27cc227ae95fc20d44325ac0329a0293d656a05230da079650705030c7d7a819",
"sha256:67e5608cb4a14d0a4ced058e595bb1f70c207ef2b5219fdc82af10e54bcf38de"
],
"version": "==0.1.0"
},
"idna": {
"hashes": [
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
],
"version": "==2.6"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"index": "pypi",
"version": "==2.10"
},
"laser-ethereum": {
"hashes": [
"sha256:720b35d554c7dbd160bfc8f8de630e8b856fec34950a89844eb340bdcd052338"
],
"index": "pypi",
"version": "==0.16.0"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"pbkdf2": {
"hashes": [
"sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979"
],
"version": "==1.3"
},
"persistent": {
"hashes": [
"sha256:1d01c21746a5583c025800a312815c61ca1010a4b39f2b5e072f5b8edbee27df",
"sha256:26060716176a6fe0e1459f06c7d165950a0caca9793b2a511ad6b054d7d154ff",
"sha256:2890566acc8dd8e08407e119ea926fa41ca71f3fe83918303bc86f895e588f65",
"sha256:2d5e67ee369610f3198b566b3bae22436248bc42d51d3e283662b60defe568f2",
"sha256:3190e88b9717e8368e4f6b82a706cdb475ebbdc499023c9a0f1967de4e08f902",
"sha256:46d62295a2ee2ed3eefccef5d47d21fc616a6c1113ee1f6063c9b8061abb84d0",
"sha256:4766d57e225b5b6c2a120c80de2e383dec05daaf0406ceb8cde0cc94524e6eae",
"sha256:4a6b9c1ee2bb220197be8847f331d714a5a0ad63ce5b86cb29bc7fa77d7e7a41",
"sha256:4eb5be9f1318883ab71110a3c1844a08d5bbdf52428f2c7dec382ae83938d90c",
"sha256:52c751883ab367b4b150a3ec7b85847c18f9d0b64891b7426e851d3b46f1bbe0",
"sha256:56a1f80dd89cfd0e9cf90cf8034653a218ae996f09f9c23ad0050aafb45dde7c",
"sha256:59a9f2b3baab9bfc4780325b01f4136064411f008b07bfdc9a5100c7cd6c1404",
"sha256:7fe9f29b3cdeb528013692870f94d89bf2a6492a78ba07a0cda204f1fd133b7b",
"sha256:864113a235652a01f5c453ace560683688539a50706c6cfac920d610658794dc",
"sha256:8aed3d08a9f4935fbf46d50cc6865cec0075040b53df2d2a76f5f9512c8bb05f",
"sha256:90afcfa3b2d1f91635fcb161091f509fb345237dae6cdc98f8215e829d1c932f",
"sha256:994be774f65669ebea6429017aeea0e98627a2b830745378e160d3320873c226",
"sha256:9dff9299be1e486ab4cb89a6eddb07d0fb6176be230a6b62094acf1e40f0cd19",
"sha256:a55bfeb2977364efee0687f3b7b9d3ec83c2fe65018e26938ed0386717d47bc1",
"sha256:a5f70dffa8d252ac2f0cc7c5b86f4db32bedeee8c413b9e2289921d103217370",
"sha256:b4b8d1e6e9eb68360b244cdaffa916aa60fde2b7881f9268adc7118291f77443",
"sha256:bd05ab36bbffe099819135bbe8dd8b7da9f8eddbd2be50ee0250c504b8522604",
"sha256:cc61af5e11ad4516773f6791ba8cee5c1085c2fd58b1d5d7ef54250fc46dc396",
"sha256:cf264cd55866c7ffbcbe1328f8d8b28fd042a5dd0c03a03f68c0887df3aa1964",
"sha256:d77a0c6139b3fcd32c684e1a23666c5076ea9fcf4c2eecc564b98d5254d930e0",
"sha256:e91af0b256b9f593c28f95ad2422757c170120734aafbfda2402242ee120c18c",
"sha256:ef28d3874e076cad9e1392ca33e1320da21dcfa33d6dfae804324fbb5c656724",
"sha256:f1d3a571128391baacb844725dd7a7d355fdbf556434fc1a1b00b8edfc12bf50"
],
"version": "==4.2.4.2"
},
"plyvel": {
"hashes": [
"sha256:059d5689ffe078061edfb12fe9251abcac9996aa20cfec9049fdd7391c8ed742",
"sha256:134e78519403a6f71f1e66df945763413c48d0f6dec02e1a61f55adf0f83106d",
"sha256:368eb22344cfe0e5c4ab64b7ec970c02b3c99150cb595bd7e15a66287cd0dd11",
"sha256:a2f2ac289893fb7b43108528e557ce4c079e938883a1db12279e02b3e47eaa4f",
"sha256:adc2573a82d100db3d583da5348e74833cd47d4221cff299285d2c8e09570edf",
"sha256:b7736bf08e83c1a95cce0cb91809f94eb612666158feaba8c4b7ef2d3f955a6e"
],
"index": "pypi",
"version": "==1.0.4"
},
"py-ecc": {
"hashes": [
"sha256:c7808a70c08bfc5c07b328f4df4406cfd3e365dd81f63bdd997c3c1eae34334a",
"sha256:f747ea69d40160c0a158c116bc3656eece9457cec446c8bfaffffd62f835de56"
],
"version": "==1.4.2"
},
"py-flags": {
"hashes": [
"sha256:2b2b18caa7f11bdb276029fac823a9102057a0953c58f618b8b7000ef3773836",
"sha256:87b2a3f9a86fc1f739753b11c359145024a65ad7392c3eb364794149acc78120"
],
"version": "==1.1.2"
},
"py-solc": {
"hashes": [
"sha256:0e657cc639b91649084901c00f0b14b921d40ab1b2faed0fb1216e80999bda72",
"sha256:90b7308abe35825979a1a03294bc383b5282bebdf9db1dda58223142dc7e9955"
],
"index": "pypi",
"version": "==2.1.0"
},
"pycparser": {
"hashes": [
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
],
"version": "==2.18"
},
"pycryptodome": {
"hashes": [
"sha256:043c82cd3dd3120286a1b325ace93000cf52abb13a067c3ecb6220f874fe4c30",
"sha256:0cdd73492859d853f60b8185715312dbca465879661e28d354d1cf5ea11860e7",
"sha256:15013007e393d0cc0e69f4329a47c4c8597b7f3d02c12c03f805405542f70c71",
"sha256:19d81b92bff837cdade735b9023808556bb4868e1ce194dad4d5ec4e2b2851f3",
"sha256:1ceb3e87605c4f0080115a8a00abf45f5df27b0166a37fd669fbff4523273cfc",
"sha256:2354a77051ed4a2959ce2aac508071eb3e42fc348ea39228b2eac335990bf508",
"sha256:27bd2878200690b050dca34f505b5c623532324b3de40267c1484784063134df",
"sha256:322f239e51fda80233762400a8975ab728639b571fa58545b95b9c44042af010",
"sha256:49a71eb990af30ff6276cfe201eb83ed3640ae989c1b5973f7b55a46c94232d1",
"sha256:4b5a2680008da3ac0cef2d3661597e0cbf8a3eb19eed35b859fd67e2de63eb85",
"sha256:6d34fe5134eb5d62368e21e6f203ac1770bc7273e9536c4a280121312c2de53a",
"sha256:733d5eb7e5ceed8b9d0b3c24c81f52c04cb5de6786461388204fceefe4456aa5",
"sha256:7c73d3798fe2946953768b788ce554c0d4b390780f5e73d63bd833241af27bfe",
"sha256:97af76f5200f15e97cac58d77f319dec40b4bada98de697c91a9517e63b41d1a",
"sha256:97cc46ff02b99dafdc2e0385b325cec0f8a15bf8b285d6ed1d7e4a3bc2067ce1",
"sha256:a561b59e0c3548eb649af381b7c38c6fd8392bbd4d0a8214794b2b761f405af4",
"sha256:ab2c633bfc23cf41be9281228517cb6f87879f4f1aeb154ed72bd53ab7cc83e9",
"sha256:adb54316998337f315520bbd8ef4d8bbd940b4ddfaef8ba1db3c137c5e499399",
"sha256:b4a3b710287eb1fc3e2cc1af018063f003530dff00c9ea4c55ae19bc1f3923cc",
"sha256:bcfdb66d6604882c3f96eea922552c2487cc0aec4b883cd217b9d341d2f8fad0",
"sha256:c08c053eb8716bbbd5e13e38f453b9e46a063e68df8659f3c421dcb7519fd381",
"sha256:e51da4ef9d9e2695a04044152f380c2db17adc9fc6fad8e24d863ead9cd548ed",
"sha256:e850e07f54dc3de9a1efdd59d227fcd1cb30cdd307dafdc647c79e8f30cf5032",
"sha256:ebc579c41fe26748dc1bad4f9105f08740ee28826293a28103b3875968695a5e",
"sha256:ed94cb1b4bf24be734f2bf2db3e8ea75f3914d2f8e684291bee54bbe4a5a9151",
"sha256:f5e19802295e63bdf83bb92849285c01f7167840efb1c1e08507a50b10ba7efa",
"sha256:fc569682f012b1f62f8d28d8f9bc71f1de67648cd1bc124ef8ccf8db4edfc28a"
],
"version": "==3.6.1"
},
"pyethash": {
"hashes": [
"sha256:ff66319ce26b9d77df1f610942634dac9742e216f2c27b051c0a2c2dec9c2818"
],
"version": "==0.1.27"
},
"pysha3": {
"hashes": [
"sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0",
"sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48",
"sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4",
"sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d",
"sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9",
"sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603",
"sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f",
"sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f",
"sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77",
"sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5",
"sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9",
"sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d",
"sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24",
"sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608",
"sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b",
"sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030",
"sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8",
"sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef",
"sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf",
"sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07",
"sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"
],
"version": "==1.0.2"
},
"pyyaml": {
"hashes": [
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736",
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f",
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7",
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269"
],
"version": "==3.12"
},
"repoze.lru": {
"hashes": [
"sha256:0429a75e19380e4ed50c0694e26ac8819b4ea7851ee1fc7583c8572db80aff77",
"sha256:f77bf0e1096ea445beadd35f3479c5cff2aa1efe604a133e67150bc8630a62ea"
],
"version": "==0.7"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"index": "pypi",
"version": "==2.18.4"
},
"rlp": {
"hashes": [
"sha256:87879a0ba1479b760cee98af165de2eee95258b261faa293199f60742be96f34"
],
"version": "==0.6.0"
},
"scrypt": {
"hashes": [
"sha256:18ccbc63d87c6f89b753194194bb37aeaf1abc517e4b989461d115c1d93ce128",
"sha256:232acdbc3434d2de55def8d5dbf1bc4b9bfc50da7c5741df2a6eebc4e18d3720",
"sha256:475ac80239b3d788ae71a09c3019ca915e149aaa339adcdd1c9eef121293dc88",
"sha256:4ad7188f2e42dbee2ff1cd72e3da40b170ba41847effbf0d726444f62ae60f3a",
"sha256:85919f023148cd9fb01d75ad4e3e061928c298fa6249a0cd6cd469c4b947595e",
"sha256:971db040d3963ebe4b919a203fe10d7d6659951d3644066314330983dc175ed4",
"sha256:a124719c686f2b5957e392465147fb3fd6077e7c643e9538cab1ee631eb01dde",
"sha256:a343c302b3e99dcb7fcbe57aa7919ed761f1568f854291ccebe1b5e6e2c9e509",
"sha256:bc131f74a688fa09993c518ca666a2ebd4268b207e039cbab03a034228140d3e",
"sha256:c23daecee405cb036845917295c76f8d747fc890158df40cb304b4b3c3640079",
"sha256:dc40f0e1a357a49ca62f30f2fc09e92e02c062a656f27949b436b2ba8002d9e1",
"sha256:f8239b2d47fa1d40bc27efd231dc7083695d10c1c2ac51a99380360741e0362d"
],
"version": "==0.8.6"
},
"semantic-version": {
"hashes": [
"sha256:2a4328680073e9b243667b201119772aefc5fc63ae32398d6afafff07c4f54c0",
"sha256:2d06ab7372034bcb8b54f2205370f4aa0643c133b7e6dbd129c5200b83ab394b"
],
"version": "==2.6.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"toolz": {
"hashes": [
"sha256:929f0a7ea7f61c178bd951bdae93920515d3fbdbafc8e6caf82d752b9b3b31c9"
],
"version": "==0.9.0"
},
"transaction": {
"hashes": [
"sha256:269601a3493cd3eddeb869419ceadfc5e6d2bc931e9970d11fc4649dab189c3c",
"sha256:9de0f93f833713270fbceaf6092194313c1de0afb660e66dea8e089855eb281c",
"sha256:f2242070e437e5d555ea3df809cb517860513254c828f33847df1c5e4b776c7a"
],
"version": "==2.2.1"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"z3-solver": {
"hashes": [
"sha256:6b10b317f056890a341304071fb3ab220f0adb2c87439a04eba9e69028a7e3ff",
"sha256:c185d05d236c6c9756e914756c73f797cb618d81b42e694166639cce5bcfdb1f",
"sha256:c802dbe5368743dd30dd2a684c15b83b17c3c95df54b66f97611a5988ae0f696",
"sha256:e41001b7f43ecb9eb9bedf6762bd0e002561590487cc78c0b48f608a85ce02ac"
],
"index": "pypi",
"version": "==4.5.1.0.post2"
},
"zc.lockfile": {
"hashes": [
"sha256:96cb13769e042988ea25d23d44cf09342ea0f887083d0f9736968f3617665853"
],
"version": "==1.3.0"
},
"zconfig": {
"hashes": [
"sha256:6c77f5658101ccd76f01592baa5dac563da36034a55d02d8ef616e690729c05d",
"sha256:de0a802e5dfea3c0b3497ccdbe33a5023c4265f950f33e35dd4cf078d2a81b19"
],
"version": "==3.2.0"
},
"zodb": {
"hashes": [
"sha256:0b306042f4f0d558a477d65c34b0dd6e7604c6e583f55dfda52befa2fa13e076"
],
"index": "pypi",
"version": "==5.4.0"
},
"zodbpickle": {
"hashes": [
"sha256:04e6eca53b6e7f562ff7c53415fbdf277166f89f254b5d341db1bcc1f7f0b770",
"sha256:0a9788a37979715cfa98052e37d6ee1880463aa0fba635caf2ec64b6fdbd2e4a",
"sha256:1397a43cf7ad7f5c9b75cf30df9232b0f03a4d74154ee344afc5e09331a3b3a1",
"sha256:1f93b692fcc4dfa20a06e40f4b24e587fb0dd9c00834fac295ee73e1c2623090",
"sha256:2261f0f4958c48ba81e30e144f5a0ac937452200c2bf375489c38f0343f45902",
"sha256:23228cf8c33c6955ab215324c84688e82848c2669a06e1b1656b4facfff81fe0",
"sha256:33e6066759f4c462baf3a65e41095c0d93751f2817d19874405d3b2094ff9108",
"sha256:3af9169fb1d5901cf6693ab356b0dfda20ad2cacc5673fad59b4449ed50d5399",
"sha256:4ce6982ec92a85dd0af89671bf0252a7f7259f762d9fd5ec4bec0049309129a2",
"sha256:60bf75ac7efa1ab6d72b5460e86cb69979599f828f60175c1a8f05dda0e6184a",
"sha256:87c23cba15329957ff867471b8eef9c0b2174c40f61a6978d20a71f4c524d875",
"sha256:87f0467e944101a7dcd674b43a33a10d4f58b61fffcb9ac0efd2453726fd0309",
"sha256:8f22db458f3b682b1ed4a89e4f825cadbc278ce89b0915ed25d05b841630c86d",
"sha256:95fbaac0639f1d29008d09fd5eb421a8dbc87e5e4e282729772250866a028c52",
"sha256:96dce0fb50d4f9ae64fe289826904ea851fd7f5d30597296ca5fb0a69396c0be",
"sha256:9fb4630ac7893fc97f69c8069577d90a84974f96d2dcdb2c067c0698f232c02d",
"sha256:a31b82d1df4f34587f4c4be22165be00f0ec04e8818d8806169f28c0fd1adf11",
"sha256:abc02cb2adbdad9c64f03b9e3195cb118a3a2239139757dbb88d5693cd113d54",
"sha256:bcf7ecef9a5966facc3a3823ce2ca022d6289b3646860fc47260e55038e9d321",
"sha256:c259e38812691512a0b11d96ffc81e9ad3c78cbb9e37d2faf19ad5ce18870e4b",
"sha256:e781b3b33aef6e667725fcf4365d4422248e8eae9ea394006ace9d65e2c99ff8",
"sha256:efdd2589aab15cbed8bbe8958552dc9a2ceeb178d138217bfa6db6012847b4ed",
"sha256:f14109e4c3c5353cc1926e4a0b7a9fda74731e2ea98320701ab69e0b9787a424"
],
"version": "==1.0"
},
"zope.interface": {
"hashes": [
"sha256:21506674d30c009271fe68a242d330c83b1b9d76d62d03d87e1e9528c61beea6",
"sha256:3d184aff0756c44fff7de69eb4cd5b5311b6f452d4de28cb08343b3f21993763",
"sha256:467d364b24cb398f76ad5e90398d71b9325eb4232be9e8a50d6a3b3c7a1c8789",
"sha256:57c38470d9f57e37afb460c399eb254e7193ac7fb8042bd09bdc001981a9c74c",
"sha256:9ada83f4384bbb12dedc152bcdd46a3ac9f5f7720d43ac3ce3e8e8b91d733c10",
"sha256:a1daf9c5120f3cc6f2b5fef8e1d2a3fb7bbbb20ed4bfdc25bc8364bc62dcf54b",
"sha256:e6b77ae84f2b8502d99a7855fa33334a1eb6159de45626905cb3e454c023f339",
"sha256:e881ef610ff48aece2f4ee2af03d2db1a146dc7c705561bd6089b2356f61641f",
"sha256:f41037260deaacb875db250021fe883bf536bf6414a4fd25b25059b02e31b120"
],
"version": "==4.5.0"
}
},
"develop": {
"astroid": {
"hashes": [
"sha256:35cfae47aac19c7b407b7095410e895e836f2285ccf1220336afba744cc4c5f2",
"sha256:38186e481b65877fd8b1f9acc33e922109e983eb7b6e487bd4c71002134ad331"
],
"version": "==1.6.3"
},
"attrs": {
"hashes": [
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9",
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"
],
"index": "pypi",
"version": "==17.4.0"
},
"isort": {
"hashes": [
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
],
"version": "==4.3.4"
},
"lazy-object-proxy": {
"hashes": [
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a",
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"
],
"version": "==1.3.1"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"more-itertools": {
"hashes": [
"sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea",
"sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e",
"sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"
],
"version": "==4.1.0"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff",
"sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c",
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5"
],
"version": "==0.6.0"
},
"py": {
"hashes": [
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881",
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
],
"version": "==1.5.3"
},
"pylint": {
"hashes": [
"sha256:0b7e6b5d9f1d4e0b554b5d948f14ed7969e8cdf9a0120853e6e5af60813b18ab",
"sha256:34738a82ab33cbd3bb6cd4cef823dbcabdd2b6b48a4e3a3054a2bbbf0c712be9"
],
"index": "pypi",
"version": "==1.8.4"
},
"pytest": {
"hashes": [
"sha256:6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c",
"sha256:fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1"
],
"index": "pypi",
"version": "==3.5.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"wrapt": {
"hashes": [
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
],
"version": "==1.10.11"
},
"yapf": {
"hashes": [
"sha256:7d8ae3567f3fb2d288f127d35e4decb3348c96cd091001e02e818465da618f90",
"sha256:dd23b52edbb4c0461d0383050f7886175b0df9ab8fd0b67edd41f94e25770993"
],
"index": "pypi",
"version": "==0.21.0"
}
}
}

@ -1,18 +1,19 @@
# Mythril
[![PyPI](https://badge.fury.io/py/mythril.svg)](https://pypi.python.org/pypi/mythril)
[![Join the chat at https://gitter.im/ConsenSys/mythril](https://badges.gitter.im/ConsenSys/mythril.svg)](https://gitter.im/ConsenSys/mythril?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Master Build Status](https://img.shields.io/circleci/project/github/ConsenSys/mythril/master.svg)
[![Join the chat at https://gitter.im/ConsenSys/mythril](https://badges.gitter.im/ConsenSys/mythril.svg)](https://gitter.im/ConsenSys/mythril?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![PyPI](https://badge.fury.io/py/mythril.svg)](https://pypi.python.org/pypi/mythril)
[![Waffle.io - Columns and their card count](https://badge.waffle.io/ConsenSys/mythril.svg?columns=all)](https://waffle.io/ConsenSys/mythril)
<img height="120px" align="right" src="/static/mythril.png"/>
Mythril is a security analysis tool for Ethereum smart contracts. It uses concolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. The analysis is based on [laser-ethereum](https://github.com/b-mueller/laser-ethereum), a symbolic execution library for EVM bytecode.
Mythril is a security analysis tool for Ethereum smart contracts. It uses concolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities.
## Installation and setup
Build the [Docker](https://www.docker.com) image:
Get it with [Docker](https://www.docker.com):
```bash
$ git clone https://github.com/ConsenSys/mythril/
$ docker build mythril
$ docker pull mythril/myth
```
Install from Pypi:
@ -29,15 +30,16 @@ Documentation has moved to the [Wiki page](https://github.com/ConsenSys/mythril/
## Publications and Videos
- [HITBSecConf 2018 - Smashing Ethereum smart contracts for fun and real profit](https://www.youtube.com/watch?v=iqf6epACgds)
- [HITBSecConf 2018 conference paper](https://github.com/b-mueller/smashing-smart-contracts/blob/master/smashing-smart-contracts-1of1.pdf)
- [HITBSecConf 2018 - Smashing Ethereum smart contracts for fun and real profit](https://www.youtube.com/watch?v=iqf6epACgds)
- [EDCon Toronto 2018 - Mythril: Find bugs and verify security properties in your contracts](https://www.youtube.com/watch?v=NJ9StJThxZY&feature=youtu.be&t=3h3m18s)
## Mythril is Hiring
## Acknowledgements
- JSON RPC library is adapted from [ethjsonrpc](https://github.com/ConsenSys/ethjsonrpc) (it doesn't seem to be maintained anymore, and I needed to make some changes to it).
- The signature data in `signatures.json` was initially obtained from the [Ethereum Function Signature Database](https://www.4byte.directory).
[ConsenSys Diligence](https://consensys.net/diligence/) is building a dedicated Mythril team. If you're a coder and/or Ethereum security enthusiast who wants to do interesting and challenging work for a decentralized organization, check out the open positions below. Please visit the links below to apply.
- Many features, bugfixes and analysis modules have been added by [contributors](https://github.com/b-mueller/mythril/graphs/contributors).
- [Developer - Security Analysis Tools](https://new.consensys.net/careers/?gh_jid=1129067)
- [Developer - Security Analysis Tools (Part Time)](https://new.consensys.net/careers/?gh_jid=1129048)
- [Lead Developer - Security Tools for Auditors](https://new.consensys.net/careers/?gh_jid=1127282)
- [Lead Developer - Secure SDLC Tools](https://new.consensys.net/careers/?gh_jid=1127284)
- [Product Manager - Security Tools](https://new.consensys.net/careers/?gh_jid=1127271)

@ -1,12 +1,37 @@
#!/bin/sh
python3 --version
echo "Please make sure you are using python 3.6.x"
echo -n "Checking Python version... "
python -c 'import sys
print(sys.version)
assert sys.version_info[0:2] >= (3,6), \
"""Please make sure you are using Python 3.6.x.
You ran with {}""".format(sys.version)' || exit $?
solc --version
echo "Please make sure you are using solc 0.4.21"
echo "Checking solc version..."
out=$(solc --version) || {
echo 2>&1 "Please make sure you have solc installed, version 0.4.21 or greater"
}
case $out in
*Version:\ 0.4.2[1-9]* )
echo $out
break ;;
* )
echo $out
echo "Please make sure your solc version is at least 0.4.21"
exit 1
;;
esac
echo "Checking that truffle is installed..."
if ! which truffle ; then
echo "Please make sure you have etherum truffle installed (npm install -g truffle)"
exit 2
fi
rm -rf ./tests/testdata/outputs_current/
mkdir -p ./tests/testdata/outputs_current/
rm -rf ./tests/testdata/outputs_current_laser_result/
mkdir -p ./tests/testdata/outputs_current_laser_result/
mkdir -p /tmp/test-reports
pytest --junitxml=/tmp/test-reports/junit.xml

@ -5,8 +5,11 @@ echo "Please make sure you are using python 3.6.x"
rm -rf ./tests/testdata/outputs_current/
mkdir -p ./tests/testdata/outputs_current/
rm -rf ./tests/testdata/outputs_current_laser_result/
mkdir -p ./tests/testdata/outputs_current_laser_result/
rm -rf coverage_html_report
coverage run -m unittest discover -p "*_test.py"
coverage html
open coverage_html_report/index.html
py.test \
--cov=mythril \
--cov-config=tox.ini \
--cov-report=html:coverage_html_report \

@ -0,0 +1,15 @@
#!/bin/sh
set -eo pipefail
NAME=mythril/myth
VERSION_TAG=${NAME}:${CIRCLE_TAG#?}
LATEST_TAG=${NAME}:latest
docker build -t ${VERSION_TAG} .
docker tag ${VERSION_TAG} ${LATEST_TAG}
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
docker push ${VERSION_TAG}
docker push ${LATEST_TAG}

@ -1,6 +1,7 @@
import re
from jinja2 import Environment, PackageLoader, select_autoescape
from mythril.laser.ethereum.svm import NodeFlags
import z3
default_opts = {
@ -95,15 +96,17 @@ def extract_nodes(statespace, color_map):
code_split = []
for instruction in instructions:
if instruction['opcode'].startswith("PUSH"):
code_split.append("%d %s %s" % (instruction['address'], instruction['opcode'], instruction['argument']))
# code_split.append("{instruction['address']} {instruction['opcode']} {instruction['argument']}")
elif instruction['opcode'].startswith("JUMPDEST"):
code_split.append("%d %s %s" % (instruction['address'], instruction['opcode'], node.function_name))
code_line = "%d %s %s" % (instruction['address'], instruction['opcode'], instruction['argument'])
elif instruction['opcode'].startswith("JUMPDEST") and NodeFlags.FUNC_ENTRY in node.flags and instruction['address'] == node.start_addr:
code_line = node.function_name
else:
code_split.append("%d %s" % (instruction['address'], instruction['opcode']))
code_line = "%d %s" % (instruction['address'], instruction['opcode'])
truncated_code = '\n'.join(code_split) if (len(code_split) < 7) else '\n'.join(
code_split[:6]) + "\n(click to expand +)"
code_line = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code_line)
code_split.append(code_line)
truncated_code = '\n'.join(code_split) if (len(code_split) < 7) \
else '\n'.join(code_split[:6]) + "\n(click to expand +)"
nodes.append({
'id': str(node_key),
@ -142,7 +145,7 @@ def extract_edges(statespace):
def generate_graph(statespace, title="Mythril / Ethereum LASER Symbolic VM", physics=False, phrackify=False):
env = Environment(loader=PackageLoader('mythril.analysis'), autoescape=select_autoescape(['html', 'xml']))
template = env.get_template('graph.html')
template = env.get_template('callgraph.html')
graph_opts = default_opts
accounts = statespace.accounts

@ -12,62 +12,71 @@ Check for invocations of delegatecall(msg.data) in the fallback function.
def execute(statespace):
"""
Executes analysis module for delegate call analysis module
:param statespace: Statespace to analyse
:return: Found issues
"""
issues = []
for call in statespace.calls:
if (call.type == "DELEGATECALL"):
if call.type is not "DELEGATECALL":
continue
if call.node.function_name is not "fallback":
continue
state = call.state
address = state.get_current_instruction()['address']
meminstart = get_variable(state.mstate.stack[-3])
if (call.node.function_name == "fallback"):
if meminstart.type == VarType.CONCRETE:
issues += _concrete_call(call, state, address, meminstart)
stack = state.mstate.stack
meminstart = get_variable(stack[-3])
if call.to.type == VarType.SYMBOLIC:
issues += _symbolic_call(call, state, address, statespace)
return issues
if meminstart.type == VarType.CONCRETE:
if (re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val]))):
def _concrete_call(call, state, address, meminstart):
if not re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val])):
return []
issue = Issue(call.node.contract_name, call.node.function_name, address, "Call data forwarded with delegatecall()", "Informational")
issue = Issue(call.node.contract_name, call.node.function_name, address,
"Call data forwarded with delegatecall()", "Informational")
issue.description = \
"This contract forwards its call data via DELEGATECALL in its fallback function. " \
"This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n"
"This means that any function in the called contract can be executed. Note that the callee contract will have " \
"access to the storage of the calling contract.\n "
if (call.to.type == VarType.CONCRETE):
issue.description += ("DELEGATECALL target: " + hex(call.to.val))
else:
issue.description += "DELEGATECALL target: " + str(call.to)
target = hex(call.to.val) if call.to.type == VarType.CONCRETE else str(call.to)
issue.description += "DELEGATECALL target: {}".format(target)
issues.append(issue)
return [issue]
if (call.to.type == VarType.SYMBOLIC):
def _symbolic_call(call, state, address, statespace):
issue = Issue(call.node.contract_name, call.node.function_name, address, call.type + " to a user-supplied address")
if ("calldata" in str(call.to)):
if "calldata" in str(call.to):
issue.description = \
"This contract delegates execution to a contract address obtained from calldata. "
else:
m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to))
if (m):
if m:
idx = m.group(1)
func = statespace.find_storage_write(state.environment.active_account.address, idx)
if (func):
issue.description = "This contract delegates execution to a contract address in storage slot " + str(idx) + ". This storage slot can be written to by calling the function `" + func + "`. "
if func:
issue.description = "This contract delegates execution to a contract address in storage slot " + str(
idx) + ". This storage slot can be written to by calling the function `" + func + "`. "
else:
logging.debug("[DELEGATECALL] No storage writes to index " + str(idx))
issue.description += "Be aware that the called contract gets unrestricted access to this contract's state."
issues.append(issue)
return issues
return [issue]

@ -11,7 +11,7 @@ Check for constraints on tx.origin (i.e., access to some functionality is restri
def execute(statespace):
logging.debug("Executing module: DEPRECIATED OPCODES")
logging.debug("Executing module: DEPRECATED OPCODES")
issues = []
@ -25,7 +25,7 @@ def execute(statespace):
if(instruction['opcode'] == "ORIGIN"):
issue = Issue(node.contract_name, node.function_name, instruction['address'], "Use of tx.origin", "Warning",
"Function " + node.function_name + " retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use tx.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin"
"Function " + node.function_name + " retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin"
)
issues.append(issue)

@ -3,7 +3,7 @@ from mythril.analysis import solver
from mythril.analysis.ops import *
from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError
from laser.ethereum.taint_analysis import TaintRunner
from mythril.laser.ethereum.taint_analysis import TaintRunner
import re
import copy
import logging

@ -0,0 +1,59 @@
from mythril.analysis.report import Issue
"""
MODULE DESCRIPTION:
Check for multiple sends in a single transaction
"""
def execute(statespace):
issues = []
for call in statespace.calls:
findings = []
# explore state
findings += _explore_states(call, statespace)
# explore nodes
findings += _explore_nodes(call, statespace)
if len(findings) > 0:
node = call.node
instruction = call.state.get_current_instruction()
issue = Issue(node.contract_name, node.function_name, instruction['address'],
"Multiple Calls",
"Information")
issue.description = \
"Multiple sends exist in one transaction, try to isolate each external call into its own transaction." \
" As external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
for finding in findings:
issue.description += \
"Call at address: {}\n".format(finding.state.get_current_instruction()['address'])
issues.append(issue)
return issues
def _explore_nodes(call, statespace):
children = _child_nodes(statespace, call.node)
sending_children = list(filter(lambda call: call.node in children, statespace.calls))
return sending_children
def _explore_states(call, statespace):
other_calls = list(
filter(lambda other: other.node == call.node and other.state_index > call.state_index, statespace.calls)
)
return other_calls
def _child_nodes(statespace, node):
result = []
children = [statespace.nodes[edge.node_to] for edge in statespace.edges if edge.node_from == node.uid]
for child in children:
result.append(child)
result += _child_nodes(statespace, child)
return result

@ -54,7 +54,7 @@ def _get_states_with_opcode(statespace, opcode):
def _dependent_on_storage(expression):
""" Checks if expression is dependent on a storage symbol and returns the influencing storages"""
pattern = re.compile(r"storage_[a-z0-9_&^]+")
pattern = re.compile(r"storage_[a-z0-9_&^]*[0-9]+")
return pattern.findall(str(simplify(expression)))

@ -1,5 +1,5 @@
from mythril.analysis.report import Issue
from laser.ethereum.svm import NodeFlags
from mythril.laser.ethereum.svm import NodeFlags
import logging
import re

@ -1,6 +1,6 @@
from z3 import *
from enum import Enum
from laser.ethereum import helper
from mythril.laser.ethereum import helper
class VarType(Enum):

@ -1,14 +1,16 @@
import hashlib
import json
import operator
from jinja2 import PackageLoader, Environment
class Issue:
def __init__(self, contract, function, pc, title, _type="Informational", description="", debug=""):
def __init__(self, contract, function, address, title, _type="Informational", description="", debug=""):
self.title = title
self.contract = contract
self.function = function
self.pc = pc
self.address = address
self.description = description
self.type = _type
self.debug = debug
@ -18,7 +20,7 @@ class Issue:
def as_dict(self):
issue = {'title': self.title, 'description':self.description, 'function': self.function, 'type': self.type, 'address': self.pc, 'debug': self.debug}
issue = {'title': self.title, 'description':self.description, 'function': self.function, 'type': self.type, 'address': self.address, 'debug': self.debug}
if self.filename and self.lineno:
issue['filename'] = self.filename
@ -30,91 +32,43 @@ class Issue:
return issue
def add_code_info(self, contract):
if self.pc:
codeinfo = contract.get_source_info(self.pc)
if self.address:
codeinfo = contract.get_source_info(self.address)
self.filename = codeinfo.filename
self.code = codeinfo.code
self.lineno = codeinfo.lineno
class Report:
environment = Environment(loader=PackageLoader('mythril.analysis'), trim_blocks=True)
def __init__(self, verbose=False):
self.issues = {}
self.verbose = verbose
pass
def sorted_issues(self):
issue_list = [issue.as_dict() for key, issue in self.issues.items()]
return sorted(issue_list, key=operator.itemgetter('address', 'title'))
def append_issue(self, issue):
m = hashlib.md5()
m.update((issue.contract + str(issue.pc) + issue.title).encode('utf-8'))
m.update((issue.contract + str(issue.address) + issue.title).encode('utf-8'))
self.issues[m.digest()] = issue
def as_text(self):
text = ""
for key, issue in self.issues.items():
text += "==== " + issue.title + " ====\n"
text += "Type: " + issue.type + "\n"
if len(issue.contract):
text += "Contract: " + issue.contract + "\n"
else:
text += "Contract: Unknown\n"
text += "Function name: " + issue.function + "\n"
text += "PC address: " + str(issue.pc) + "\n"
text += issue.description + "\n--------------------\n"
if issue.filename and issue.lineno:
text += "In file: " + issue.filename + ":" + str(issue.lineno)
if issue.code:
text += "\n\n" + issue.code + "\n\n--------------------\n"
if self.verbose and issue.debug:
text += "\nDEBUGGING INFORMATION:\n\n" + issue.debug + "\n--------------------\n"
text += "\n"
return text
name = self._file_name()
template = Report.environment.get_template('report_as_text.jinja2')
return template.render(filename=name, issues=self.sorted_issues(), verbose=self.verbose)
def as_json(self):
issues = []
for key, issue in self.issues.items():
issues.append(issue.as_dict())
result = {'success': True, 'error': None, 'issues': issues}
return json.dumps(result)
result = {'success': True, 'error': None, 'issues': self.sorted_issues()}
return json.dumps(result, sort_keys=True)
def as_markdown(self):
text = ""
for key, issue in self.issues.items():
if text == "":
if (issue.filename):
text += "# Analysis results for " + issue.filename
text += "\n\n## " + issue.title + "\n\n"
text += "- Type: " + issue.type + "\n"
if len(issue.contract):
text += "- Contract: " + issue.contract + "\n"
else:
text += "- Contract: Unknown\n"
text += "- Function name: `" + issue.function + "`\n"
text += "- PC address: " + str(issue.pc) + "\n\n"
text += "### Description\n\n" + issue.description
if issue.filename and issue.lineno:
text += "\nIn *%s:%d*\n" % (issue.filename, issue.lineno)
if issue.code:
text += "\n```\n" + issue.code + "\n```"
if self.verbose and issue.debug:
text += "\n\n### Debugging Information\n" + issue.debug
filename = self._file_name()
template = Report.environment.get_template('report_as_markdown.jinja2')
return template.render(filename=filename, issues=self.sorted_issues(), verbose=self.verbose)
return text
def _file_name(self):
if len(self.issues.values()) > 0:
return list(self.issues.values())[0].filename

@ -1,5 +1,5 @@
from mythril import ether
from laser.ethereum import svm
from mythril.laser.ethereum import svm
import copy
import logging
from .ops import get_variable, SStore, Call, VarType

@ -0,0 +1,37 @@
# Analysis results for {{ filename }}
{% if issues %}
{% for issue in issues %}
## {{ issue.title }}
- Type: {{ issue.type }}
- Contract: {{ issue.contract | default("Unknown") }}
- Function name: `{{ issue.function }}`
- PC address: {{ issue.address }}
### Description
{{ issue.description.rstrip() }}
{% if issue.filename and issue.lineno %}
In file: {{ issue.filename }}:{{ issue.lineno }}
{% endif %}
{% if issue.code %}
### Code
```
{{ issue.code }}
```
{% endif %}
{% if verbose and issue.debug %}
--------------------
### Debugging Information:
{{ issue.debug }}
{% endif %}
{% endfor %}
{% else %}
The analysis was completed successfully. No issues were detected.
{% endif %}

@ -0,0 +1,29 @@
{% if issues %}
{% for issue in issues %}
==== {{ issue.title }} ====
Type: {{ issue.type }}
Contract: {{ issue.contract | default("Unknown") }}
Function name: {{ issue.function }}
PC address: {{ issue.address }}
{{ issue.description }}
--------------------
{% if issue.filename and issue.lineno %}
In file: {{ issue.filename }}:{{ issue.lineno }}
{% endif %}
{% if issue.code %}
{{ issue.code }}
--------------------
{% endif %}
{% if verbose and issue.debug %}
--------------------
DEBUGGING INFORMATION:
{{ issue.debug }}
{% endif %}
{% endfor %}
{% else %}
The analysis was completed successfully. No issues were detected.
{% endif %}

@ -1,5 +1,5 @@
from z3 import Z3Exception, simplify
from laser.ethereum.svm import NodeFlags
from mythril.laser.ethereum.svm import NodeFlags
import re
colors = [

@ -11,6 +11,7 @@ class Disassembly:
self.xrefs = []
self.func_to_addr = {}
self.addr_to_func = {}
self.bytecode = code
try:
mythril_dir = os.environ['MYTHRIL_DIR']

@ -1,157 +0,0 @@
import os
import hashlib
import persistent.list
import transaction
from BTrees.OOBTree import BTree
import ZODB
from ZODB import FileStorage
from multiprocessing import Pool
import logging
from mythril.ether.ethcontract import ETHContract, InstanceList
from mythril import ether
import time
BLOCKS_PER_THREAD = 256
NUM_THREADS = 8
def get_persistent_storage(db_dir=None):
if not db_dir:
db_dir = os.path.join(os.path.expanduser('~'), ".mythril")
if not os.path.exists(db_dir):
os.makedirs(db_dir)
db_path = os.path.join(db_dir, "contractstorage.fs")
storage = FileStorage.FileStorage(db_path)
db = ZODB.DB(storage)
connection = db.open()
storage_root = connection.root()
try:
contract_storage = storage_root['contractStorage']
except KeyError:
contract_storage = ContractStorage()
storage_root['contractStorage'] = contract_storage
return contract_storage, db
class SyncBlocks(object):
'''
Processes the block chunk
'''
def __init__(self, eth):
self.eth = eth
def __call__(self, startblock):
'''
Processesing method
'''
logging.info("SYNC_BLOCKS %d to %d" % (startblock, startblock + BLOCKS_PER_THREAD))
contracts = {}
for blockNum in range(startblock, startblock + BLOCKS_PER_THREAD):
block = self.eth.eth_getBlockByNumber(blockNum)
for tx in block['transactions']:
if not tx['to']:
receipt = self.eth.eth_getTransactionReceipt(tx['hash'])
if receipt is not None:
contract_address = receipt['contractAddress']
contract_code = self.eth.eth_getCode(contract_address)
contract_balance = self.eth.eth_getBalance(contract_address)
if not contract_balance:
continue
ethcontract = ETHContract(contract_code, tx['input'])
m = hashlib.md5()
m.update(contract_code.encode('UTF-8'))
contract_hash = m.digest()
contracts[contract_hash] = {'ethcontract': ethcontract, 'address': contract_address, 'balance': contract_balance}
blockNum -= 1
return contracts
class ContractStorage(persistent.Persistent):
def __init__(self):
self.contracts = BTree()
self.instance_lists = BTree()
self.last_block = 0
self.eth = None
def get_contract_by_hash(self, contract_hash):
return self.contracts[contract_hash]
def initialize(self, eth):
self.eth = eth
if self.last_block:
blockNum = self.last_block
print("Resuming synchronization from block " + str(blockNum))
else:
blockNum = eth.eth_blockNumber()
print("Starting synchronization from latest block: " + str(blockNum))
processed = 0
while (blockNum > 0):
numbers = []
for i in range(1, NUM_THREADS + 1):
numbers.append(max(0, blockNum - (i * BLOCKS_PER_THREAD)))
pool = Pool(NUM_THREADS, initargs=(self.eth))
results = pool.map(SyncBlocks(self.eth), numbers)
pool.close()
pool.join()
for result in results:
for (contract_hash, data) in result.items():
try:
self.contracts[contract_hash]
except KeyError:
self.contracts[contract_hash] = data['ethcontract']
m = InstanceList()
self.instance_lists[contract_hash] = m
self.instance_lists[contract_hash].add(data['address'], data['balance'])
blockNum -= NUM_THREADS * BLOCKS_PER_THREAD
processed += NUM_THREADS * BLOCKS_PER_THREAD
self.last_block = blockNum
transaction.commit()
cost_time = time.time() - ether.start_time
print("%d blocks processed (in %d seconds), %d unique contracts in database, next block: %d" % (processed, cost_time, len(self.contracts), max(0, blockNum)))
# If we've finished initializing the database, start over from the end of the chain if we want to initialize again
self.last_block = 0
print("Finished synchronization")
def search(self, expression, callback_func):
all_keys = list(self.contracts)
for k in all_keys:
if self.contracts[k].matches_expression(expression):
m = self.instance_lists[k]
callback_func(k.hex(), self.contracts[k], m.addresses, m.balances)

@ -1,4 +1,4 @@
import laser.ethereum.helper as helper
import mythril.laser.ethereum.helper as helper
from mythril.ether.ethcontract import ETHContract
from mythril.ether.util import *
from mythril.exceptions import NoContractFoundError
@ -36,7 +36,7 @@ class SolidityContract(ETHContract):
self.solidity_files = []
for filename in data['sourceList']:
with open(filename, 'r') as file:
with open(filename, 'r', encoding='utf-8') as file:
code = file.read()
self.solidity_files.append(SolidityFile(filename, code))

@ -49,8 +49,9 @@ def main():
outputs.add_argument('--verbose-report', action='store_true', help='Include debugging information in report')
database = parser.add_argument_group('local contracts database')
database.add_argument('--init-db', action='store_true', help='initialize the contract database')
database.add_argument('-s', '--search', help='search the contract database', metavar='EXPRESSION')
database.add_argument('--leveldb-dir', help='specify leveldb directory for search or direct access operations', metavar='LEVELDB_PATH')
database.add_argument('--search-all', action='store_true', help='search all contracts instead of active (non-zero balance) only')
utilities = parser.add_argument_group('utilities')
utilities.add_argument('--hash', help='calculate function signature hash', metavar='SIGNATURE')
@ -62,18 +63,18 @@ def main():
options = parser.add_argument_group('options')
options.add_argument('-m', '--modules', help='Comma-separated list of security analysis modules', metavar='MODULES')
options.add_argument('--max-depth', type=int, default=12, help='Maximum recursion depth for symbolic execution')
options.add_argument('--max-depth', type=int, default=22, help='Maximum recursion depth for symbolic execution')
options.add_argument('--solc-args', help='Extra arguments for solc')
options.add_argument('--phrack', action='store_true', help='Phrack-style call graph')
options.add_argument('--enable-physics', action='store_true', help='enable graph physics simulation')
options.add_argument('-v', type=int, help='log level (0-2)', metavar='LOG_LEVEL')
options.add_argument('--leveldb', help='enable direct leveldb access operations', metavar='LEVELDB_PATH')
rpc = parser.add_argument_group('RPC options')
rpc.add_argument('-i', action='store_true', help='Preset: Infura Node service (Mainnet)')
rpc.add_argument('--rpc', help='custom RPC settings', metavar='HOST:PORT / ganache / infura-[network_name]')
rpc.add_argument('--rpctls', type=bool, default=False, help='RPC connection over TLS')
rpc.add_argument('--ipc', action='store_true', help='Connect via local IPC')
rpc.add_argument('--leveldb', action='store_true', help='Enable direct leveldb access operations')
# Get config values
@ -87,7 +88,7 @@ def main():
# Parse cmdline args
if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.fire_lasers
if not (args.search or args.hash or args.disassemble or args.graph or args.fire_lasers
or args.storage or args.truffle or args.statespace_json):
parser.print_help()
sys.exit()
@ -106,27 +107,31 @@ def main():
try:
# the mythril object should be our main interface
#init_db = None, infura = None, rpc = None, rpctls = None, ipc = None,
#infura = None, rpc = None, rpctls = None, ipc = None,
#solc_args = None, dynld = None, max_recursion_depth = 12):
mythril = Mythril(solv=args.solv, dynld=args.dynld,
solc_args=args.solc_args)
if args.leveldb:
# Open LevelDB if specified
mythril.set_db_leveldb(args.leveldb)
elif (args.address or args.init_db) and not args.leveldb:
if args.address and not args.leveldb:
# Establish RPC/IPC connection if necessary
if args.i:
mythril.set_db_rpc_infura()
mythril.set_api_rpc_infura()
elif args.rpc:
mythril.set_db_rpc(rpc=args.rpc, rpctls=args.rpctls)
mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls)
elif args.ipc:
mythril.set_db_ipc()
mythril.set_api_ipc()
else:
mythril.set_db_rpc_localhost()
mythril.set_api_rpc_localhost()
elif args.leveldb or args.search:
# Open LevelDB if necessary
mythril.set_api_leveldb(mythril.leveldb_dir if not args.leveldb_dir else args.leveldb_dir)
if args.search:
# Database search ops
mythril.search_db(args.search, args.search_all)
sys.exit()
if args.truffle:
try:
@ -137,15 +142,6 @@ def main():
"Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully.")
sys.exit()
elif args.search:
# Database search ops
mythril.search_db(args.search)
sys.exit()
elif args.init_db:
mythril.init_db()
sys.exit()
# Load / compile input contracts
address = None
@ -202,8 +198,8 @@ def main():
max_depth=args.max_depth)
outputs = {
'json': report.as_json(),
'text': report.as_text() or "The analysis was completed successfully. No issues were detected.",
'markdown': report.as_markdown() or "The analysis was completed successfully. No issues were detected."
'text': report.as_text(),
'markdown': report.as_markdown()
}
print(outputs[args.outform])

@ -0,0 +1,74 @@
gascost = {
'PUSH': 3,
'DUP': 3,
'SWAP': 3,
'STOP': 0,
'ADD': 3,
'MUL': 5,
'SUB': 3,
'DIV': 5,
'SDIV': 5,
'MOD': 5,
'SMOD': 5,
'ADDMOD': 8,
'MULMOD': 8,
'EXP': 10,
'SIGNEXTEND': 5,
'LT': 3,
'GT': 3,
'SLT': 3,
'SGT': 3,
'EQ': 3,
'ISZERO': 3,
'AND': 3,
'OR': 3,
'XOR': 3,
'NOT': 3,
'BYTE': 3,
'SHA3': 30,
'ADDRESS': 2,
'BALANCE': 400,
'ORIGIN': 2,
'CALLER': 2,
'CALLVALUE': 2,
'CALLDATALOAD': 3,
'CALLDATASIZE': 2,
'CALLDATACOPY': 3,
'CODESIZE': 2,
'CODECOPY': 3,
'GASPRICE': 2,
'EXTCODESIZE': 700,
'EXTCODECOPY': 700,
'BLOCKHASH': 20,
'COINBASE': 2,
'TIMESTAMP': 2,
'NUMBER': 2,
'DIFFICULTY': 2,
'GASLIMIT': 2,
'POP': 2,
'MLOAD': 3,
'MSTORE': 3,
'MSTORE8': 3,
'SLOAD': 50,
'SSTORE': 0,
'JUMP': 8,
'JUMPI': 10,
'PC': 2,
'MSIZE': 2,
'GAS': 2,
'JUMPDEST': 1,
'LOG0': 375,
'LOG1': 750,
'LOG2': 1125,
'LOG3': 1500,
'LOG4': 1875,
'CREATE': 32000,
'CALL': 40,
'CALLCODE': 40,
'RETURN': 0,
'DELEGATECALL': 40,
'CALLBLACKBOX': 40,
'STATICCALL': 40,
'REVERT': 0,
'SUICIDE': 5000,
}

@ -0,0 +1,122 @@
import re
from z3 import *
import logging
import sha3 as _sha3
import struct
TT256 = 2 ** 256
TT256M1 = 2 ** 256 - 1
TT255 = 2 ** 255
ALL_BYTES = tuple(
struct.pack('B', i)
for i in range(256)
)
def zpad(x, l):
""" Left zero pad value `x` at least to length `l`.
>>> zpad('\xca\xfe', 4)
'\x00\x00\xca\xfe'
"""
return b'\x00' * max(0, l - len(x)) + x
def sha3(seed):
return _sha3.keccak_256(bytes(seed)).digest()
def safe_decode(hex_encoded_string):
if (hex_encoded_string.startswith("0x")):
return bytes.fromhex(hex_encoded_string[2:])
else:
return bytes.fromhex(hex_encoded_string)
def to_signed(i):
return i if i < TT255 else i - TT256
def get_instruction_index(instruction_list, address):
index = 0
for instr in instruction_list:
if instr['address'] == address:
return index
index += 1
return None
def get_trace_line(instr, state):
stack = str(state.stack[::-1])
# stack = re.sub("(\d+)", lambda m: hex(int(m.group(1))), stack)
stack = re.sub("\n", "", stack)
return str(instr['address']) + " " + instr['opcode'] + "\tSTACK: " + stack
def pop_bitvec(state):
# pop one element from stack, converting boolean expressions and
# concrete Python variables to BitVecVal
item = state.stack.pop()
if type(item) == BoolRef:
return If(item, BitVecVal(1, 256), BitVecVal(0, 256))
elif type(item) == bool:
if item:
return BitVecVal(1, 256)
else:
return BitVecVal(0, 256)
elif type(item) == int:
return BitVecVal(item, 256)
else:
return simplify(item)
def get_concrete_int(item):
if (type(item) == int):
return item
if (type(item) == BitVecNumRef):
return item.as_long()
return simplify(item).as_long()
def concrete_int_from_bytes(_bytes, start_index):
# logging.debug("-- concrete_int_from_bytes: " + str(_bytes[start_index:start_index+32]))
b = _bytes[start_index:start_index+32]
val = int.from_bytes(b, byteorder='big')
return val
def concrete_int_to_bytes(val):
# logging.debug("concrete_int_to_bytes " + str(val))
if (type(val) == int):
return val.to_bytes(32, byteorder='big')
return (simplify(val).as_long()).to_bytes(32, byteorder='big')
def bytearray_to_int(arr):
o = 0
for a in arr:
o = (o << 8) + a
return o

@ -0,0 +1,88 @@
# -*- coding: utf8 -*-
import copy
import hashlib
import coincurve
from py_ecc.secp256k1 import N as secp256k1n
from mythril.laser.ethereum.helper import ALL_BYTES, bytearray_to_int, concrete_int_to_bytes, sha3, zpad
def int_to_32bytes(i): #used because int can't fit as bytes function's input
o = [0] * 32
for x in range(32):
o[31 - x] = i & 0xff
i >>= 8
return bytes(o)
def ecrecover_to_pub(rawhash, v, r, s):
try:
pk = coincurve.PublicKey.from_signature_and_message(
zpad(concrete_int_to_bytes(r), 32) + zpad(concrete_int_to_bytes(s), 32) +
ALL_BYTES[v - 27],
rawhash,
hasher=None,
)
pub = pk.format(compressed=False)[1:]
except BaseException:
pub = b"\x00" * 64
return pub
def extract32(data, i):
if i >= len(data):
return 0
o = data[i: min(i + 32, len(data))]
o.extend(bytearray(32 - len(o)))
return bytearray_to_int(o)
def ecrecover(data):
try:
data = bytearray(data)
except TypeError:
return "ecrecover_"+str(data)
message = b''.join(map(lambda x: ALL_BYTES[x], data[0:32]))
v = extract32(data, 32)
r = extract32(data, 64)
s = extract32(data, 96)
if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28:
return []
try:
pub = ecrecover_to_pub(message, v, r, s)
except Exception as e:
return []
o = [0] * 12 + [x for x in sha3(pub)[-20:]]
return o
def sha256(data):
try:
data = bytes(data)
except TypeError:
return "sha256_"+str(data)
return hashlib.sha256(data).digest()
def ripemd160(data):
try:
data = bytes(data)
except TypeError:
return "ripemd160_"+str(data)
return 12*[0]+[i for i in hashlib.new('ripemd160', data).digest()]
def identity(data):
return copy.copy(data)
def native_contracts(address, data):
'''
takes integer address 1, 2, 3, 4
'''
functions = (ecrecover, sha256, ripemd160, identity)
return functions[address-1](data)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,309 @@
import logging, copy
import mythril.laser.ethereum.helper as helper
class TaintRecord:
"""
TaintRecord contains tainting information for a specific (state, node)
the information specifies the taint status before executing the operation belonging to the state
"""
def __init__(self):
""" Builds a taint record """
self.stack = []
self.memory = {}
self.storage = {}
self.states = []
def stack_tainted(self, index):
""" Returns taint value of stack element at index"""
if index < len(self.stack):
return self.stack[index]
return None
def memory_tainted(self, index):
""" Returns taint value of memory element at index"""
if index in self.memory.keys():
return self.memory[index]
return False
def storage_tainted(self, index):
""" Returns taint value of storage element at index"""
if index in self.storage.keys():
return self.storage[index]
return False
def add_state(self, state):
""" Adds state with this taint record """
self.states.append(state)
def clone(self):
""" Clones this record"""
clone = TaintRecord()
clone.stack = copy.deepcopy(self.stack)
clone.memory = copy.deepcopy(self.memory)
clone.storage = copy.deepcopy(self.storage)
return clone
class TaintResult:
""" Taint analysis result obtained after having ran the taint runner"""
def __init__(self):
self.records = []
def check(self, state, stack_index):
"""
Checks if stack variable is tainted, before executing the instruction
:param state: state to check variable in
:param stack_index: index of stack variable
:return: tainted
"""
record = self._try_get_record(state)
if record is None:
return None
return record.stack_tainted(stack_index)
def add_records(self, records):
""" Adds records to this taint result """
self.records += records
def _try_get_record(self, state):
""" Finds record belonging to the state """
for record in self.records:
if state in record.states:
return record
return None
class TaintRunner:
"""
Taint runner, is able to run taint analysis on symbolic execution result
"""
@staticmethod
def execute(statespace, node, state, initial_stack=[]):
"""
Runs taint analysis on the statespace
:param statespace: symbolic statespace to run taint analysis on
:param node: taint introduction node
:param state: taint introduction state
:param stack_indexes: stack indexes to introduce taint
:return: TaintResult object containing analysis results
"""
result = TaintResult()
# Build initial current_node
init_record = TaintRecord()
init_record.stack = initial_stack
state_index = node.states.index(state)
# List of (Node, TaintRecord, index)
current_nodes = [(node, init_record, state_index)]
for node, record, index in current_nodes:
records = TaintRunner.execute_node(node, record, index)
result.add_records(records)
children = [statespace.nodes[edge.node_to] for edge in statespace.edges if edge.node_from == node.uid]
for child in children:
current_nodes.append((child, records[-1], 0))
return result
@staticmethod
def execute_node(node, last_record, state_index=0):
"""
Runs taint analysis on a given node
:param node: node to analyse
:param last_record: last taint record to work from
:param state_index: state index to start from
:return: List of taint records linked to the states in this node
"""
records = [last_record]
for index in range(state_index, len(node.states)):
current_state = node.states[index]
records.append(TaintRunner.execute_state(records[-1], current_state))
return records[1:]
@staticmethod
def execute_state(record, state):
assert len(state.mstate.stack) == len(record.stack)
""" Runs taint analysis on a state """
record.add_state(state)
new_record = record.clone()
# Apply Change
op = state.get_current_instruction()['opcode']
if op in TaintRunner.stack_taint_table.keys():
mutator = TaintRunner.stack_taint_table[op]
TaintRunner.mutate_stack(new_record, mutator)
elif op.startswith("PUSH"):
TaintRunner.mutate_push(op, new_record)
elif op.startswith("DUP"):
TaintRunner.mutate_dup(op, new_record)
elif op.startswith("SWAP"):
TaintRunner.mutate_swap(op, new_record)
elif op is "MLOAD":
TaintRunner.mutate_mload(new_record, state.mstate.stack[-1])
elif op.startswith("MSTORE"):
TaintRunner.mutate_mstore(new_record, state.mstate.stack[-1])
elif op is "SLOAD":
TaintRunner.mutate_sload(new_record, state.mstate.stack[-1])
elif op is "SSTORE":
TaintRunner.mutate_sstore(new_record, state.mstate.stack[-1])
elif op.startswith("LOG"):
TaintRunner.mutate_log(new_record, op)
elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'):
TaintRunner.mutate_call(new_record, op)
else:
logging.debug("Unknown operation encountered: {}".format(op))
return new_record
@staticmethod
def mutate_stack(record, mutator):
pop, push = mutator
values = []
for i in range(pop):
values.append(record.stack.pop())
taint = any(values)
for i in range(push):
record.stack.append(taint)
@staticmethod
def mutate_push(op, record):
TaintRunner.mutate_stack(record, (0, 1))
@staticmethod
def mutate_dup(op, record):
depth = int(op[3:])
index = len(record.stack) - depth
record.stack.append(record.stack[index])
@staticmethod
def mutate_swap(op, record):
depth = int(op[4:])
l = len(record.stack) - 1
i = l - depth
record.stack[l], record.stack[i] = record.stack[i], record.stack[l]
@staticmethod
def mutate_mload(record, op0):
_ = record.stack.pop()
try:
index = helper.get_concrete_int(op0)
except AttributeError:
logging.debug("Can't MLOAD taint track symbolically")
record.stack.append(False)
return
record.stack.append(record.memory_tainted(index))
@staticmethod
def mutate_mstore(record, op0):
_, value_taint = record.stack.pop(), record.stack.pop()
try:
index = helper.get_concrete_int(op0)
except AttributeError:
logging.debug("Can't mstore taint track symbolically")
return
record.memory[index] = value_taint
@staticmethod
def mutate_sload(record, op0):
_ = record.stack.pop()
try:
index = helper.get_concrete_int(op0)
except AttributeError:
logging.debug("Can't MLOAD taint track symbolically")
record.stack.append(False)
return
record.stack.append(record.storage_tainted(index))
@staticmethod
def mutate_sstore(record, op0):
_, value_taint = record.stack.pop(), record.stack.pop()
try:
index = helper.get_concrete_int(op0)
except AttributeError:
logging.debug("Can't mstore taint track symbolically")
return
record.storage[index] = value_taint
@staticmethod
def mutate_log(record, op):
depth = int(op[3:])
for _ in range(depth + 2):
record.stack.pop()
@staticmethod
def mutate_call(record, op):
pops = 6
if op in ('CALL', 'CALLCODE'):
pops += 1
for _ in range(pops):
record.stack.pop()
record.stack.append(False)
stack_taint_table = {
# instruction: (taint source, taint target)
'POP': (1, 0),
'ADD': (2, 1),
'MUL': (2, 1),
'SUB': (2, 1),
'AND': (2, 1),
'OR': (2, 1),
'XOR': (2, 1),
'NOT': (1, 1),
'BYTE': (2, 1),
'DIV': (2, 1),
'MOD': (2, 1),
'SDIV': (2, 1),
'SMOD': (2, 1),
'ADDMOD': (3, 1),
'MULMOD': (3, 1),
'EXP': (2, 1),
'SIGNEXTEND': (2, 1),
'LT': (2, 1),
'GT': (2, 1),
'SLT': (2, 1),
'SGT': (2, 1),
'EQ': (2, 1),
'ISZERO': (1, 1),
'CALLVALUE': (0, 1),
'CALLDATALOAD': (1, 1),
'CALLDATACOPY': (3, 0), #todo
'CALLDATASIZE': (0, 1),
'ADDRESS': (0, 1),
'BALANCE': (1, 1),
'ORIGIN': (0, 1),
'CALLER': (0, 1),
'CODESIZE': (0, 1),
'SHA3': (2, 1),
'GASPRICE': (0, 1),
'CODECOPY': (3, 0),
'EXTCODESIZE': (1, 1),
'EXTCODECOPY': (4, 0),
'RETURNDATASIZE': (0, 1),
'BLOCKHASH': (1, 1),
'COINBASE': (0, 1),
'TIMESTAMP': (0, 1),
'NUMBER': (0, 1),
'DIFFICULTY': (0, 1),
'GASLIMIT': (0, 1),
'JUMP': (1, 0),
'JUMPI': (2, 0),
'PC': (0, 1),
'MSIZE': (0, 1),
'GAS': (0, 1),
'CREATE': (3, 1),
'RETURN': (2, 0)
}

@ -39,55 +39,27 @@ class EthLevelDB(object):
self.db = ETH_DB(path)
self.headBlockHeader = None
self.headState = None
self.all_contracts = None
self.active_contracts = None
self.instance_lists = None
def get_all_contracts(self):
def get_contracts(self, search_all):
'''
get all contracts
iterate through contracts with non-zero balance by default or all if search_all is set
'''
if not self.all_contracts:
self.all_contracts = []
self.active_contracts = []
self.instance_lists = []
state = self._get_head_state()
accounts = state.get_all_accounts()
for a in accounts:
if a.code is not None:
code = _encode_hex(a.code)
for account in self._get_head_state().get_all_accounts():
if account.code is not None and (search_all or account.balance != 0):
code = _encode_hex(account.code)
md5 = hashlib.md5()
md5.update(code.encode('UTF-8'))
contract_hash = md5.digest()
contract = ETHContract(code, name=contract_hash.hex())
self.all_contracts.append(contract)
if a.balance != 0:
md5 = InstanceList()
md5.add(_encode_hex(a.address), a.balance)
self.instance_lists.append(md5)
self.active_contracts.append(contract)
return self.all_contracts
def get_active_contracts(self):
'''
get all contracts with non-zero balance
'''
if not self.active_contracts:
self.get_all_contracts() # optimized
return self.active_contracts
yield contract, _encode_hex(account.address), account.balance
def search(self, expression, callback_func):
def search(self, expression, search_all, callback_func):
'''
searches through non-zero balance contracts
'''
contracts = self.get_active_contracts()
for i in range(0, len(contracts)):
if contracts[i].matches_expression(expression):
m = self.instance_lists[i]
callback_func(contracts[i].name, contracts[i], m.addresses, m.balances)
for contract, address, balance in self.get_contracts(search_all):
if contract.matches_expression(expression):
callback_func(contract.name, contract, [address], [balance])
def eth_getBlockHeaderByNumber(self, number):
'''

@ -121,10 +121,8 @@ class State():
def get_all_accounts(self):
'''
iterates through trie to get all items
iterates through trie to and yields non-blank leafs as accounts
'''
accounts = []
for addressHash, rlpdata in self.secureTrie.trie.to_dict().items():
for addressHash, rlpdata in self.secureTrie.trie.iter_branch():
if rlpdata != trie.BLANK_NODE:
accounts.append(rlp.decode(rlpdata, Account, db=self.db, address=addressHash))
return accounts
yield rlp.decode(rlpdata, Account, db=self.db, address=addressHash)

@ -11,13 +11,15 @@ import os
import re
from ethereum import utils
import codecs
from solc.exceptions import SolcError
import solc
from configparser import ConfigParser
import platform
from copy import deepcopy
from mythril.disassembler.disassembly import Disassembly
from mythril.ether import util
from mythril.ether.contractstorage import get_persistent_storage
from mythril.ether.ethcontract import ETHContract
from mythril.ether.soliditycontract import SolidityContract
from mythril.rpc.client import EthJsonRpc
@ -48,17 +50,17 @@ class Mythril(object):
Example:
mythril = Mythril()
mythril.set_db_rpc_infura()
mythril.set_api_rpc_infura()
# (optional) other db adapters
mythril.set_db_rpc(args)
mythril.set_db_ipc()
mythril.set_db_rpc_localhost()
# (optional) other API adapters
mythril.set_api_rpc(args)
mythril.set_api_ipc()
mythril.set_api_rpc_localhost()
mythril.set_api_leveldb(path)
# (optional) other func
mythril.analyze_truffle_project(args)
mythril.search_db(args)
mythril.init_db()
# load contract
mythril.load_from_bytecode(bytecode)
@ -90,10 +92,10 @@ class Mythril(object):
self.mythril_dir = self._init_mythril_dir()
self.signatures_file, self.sigs = self._init_signatures()
self.solc_binary = self._init_solc_binary(solv)
self.leveldb_dir = self._init_config()
self.eth = None
self.ethDb = None
self.dbtype = None # track type of db (rpc,ipc,leveldb) used
self.eth = None # ethereum API client
self.ethDb = None # ethereum LevelDB client
self.contracts = [] # loaded contracts
@ -137,6 +139,41 @@ class Mythril(object):
self.sigs = jsonsigs
def _init_config(self):
# If no config file exists, create it. Default LevelDB path is specified based on OS
config_path = os.path.join(self.mythril_dir, 'config.ini')
system = platform.system().lower()
fallback_dir = os.path.expanduser('~')
if system.startswith("darwin"):
fallback_dir = os.path.join(fallback_dir, "Library", "Ethereum")
elif system.startswith("windows"):
fallback_dir = os.path.join(fallback_dir, "AppData", "Roaming", "Ethereum")
else:
fallback_dir = os.path.join(fallback_dir, ".ethereum")
fallback_dir = os.path.join(fallback_dir, "geth", "chaindata")
if not os.path.exists(config_path):
logging.info("No config file found. Creating default: " + config_path)
config = ConfigParser(allow_no_value=True)
config.optionxform = str
config.add_section('defaults')
config.set('defaults', "#Default chaindata locations:")
config.set('defaults', "#– Mac: ~/Library/Ethereum/geth/chaindata")
config.set('defaults', "#– Linux: ~/.ethereum/geth/chaindata")
config.set('defaults', "#– Windows: %USERPROFILE%\\AppData\\Roaming\\Ethereum\\geth\\chaindata")
config.set('defaults', 'leveldb_dir', fallback_dir)
with codecs.open(config_path, 'w', 'utf-8') as fp:
config.write(fp)
config = ConfigParser(allow_no_value=True)
config.optionxform = str
config.read(config_path, 'utf-8')
leveldb_dir = config.get('defaults', 'leveldb_dir', fallback=fallback_dir)
return os.path.expanduser(leveldb_dir)
def analyze_truffle_project(self, *args, **kwargs):
return analyze_truffle_project(*args, **kwargs) # just passthru for now
@ -170,18 +207,16 @@ class Mythril(object):
solc_binary = 'solc'
return solc_binary
def set_db_leveldb(self, leveldb):
def set_api_leveldb(self, leveldb):
self.ethDb = EthLevelDB(leveldb)
self.eth = self.ethDb
self.dbtype = "leveldb"
return self.eth
def set_db_rpc_infura(self):
def set_api_rpc_infura(self):
self.eth = EthJsonRpc('mainnet.infura.io', 443, True)
logging.info("Using INFURA for RPC queries")
self.dbtype = "rpc"
def set_db_rpc(self, rpc=None, rpctls=False):
def set_api_rpc(self, rpc=None, rpctls=False):
if rpc == 'ganache':
rpcconfig = ('localhost', 7545, False)
else:
@ -197,50 +232,35 @@ class Mythril(object):
if rpcconfig:
self.eth = EthJsonRpc(rpcconfig[0], int(rpcconfig[1]), rpcconfig[2])
self.dbtype = "rpc"
logging.info("Using RPC settings: %s" % str(rpcconfig))
else:
raise CriticalError("Invalid RPC settings, check help for details.")
def set_db_ipc(self):
def set_api_ipc(self):
try:
self.eth = EthIpc()
self.dbtype = "ipc"
except Exception as e:
raise CriticalError(
"IPC initialization failed. Please verify that your local Ethereum node is running, or use the -i flag to connect to INFURA. \n" + str(
e))
def set_db_rpc_localhost(self):
def set_api_rpc_localhost(self):
self.eth = EthJsonRpc('localhost', 8545)
self.dbtype = "rpc"
logging.info("Using default RPC settings: http://localhost:8545")
def search_db(self, search):
def search_db(self, search, search_all):
def search_callback(code_hash, code, addresses, balances):
print("Matched contract with code hash " + code_hash)
for i in range(0, len(addresses)):
print("Address: " + addresses[i] + ", balance: " + str(balances[i]))
contract_storage, _ = get_persistent_storage(self.mythril_dir)
try:
if self.dbtype=="leveldb":
contract_storage.search(search, search_callback)
else:
self.ethDB.search(search, search_callback)
self.ethDb.search(search, search_all, search_callback)
except SyntaxError:
raise CriticalError("Syntax error in search expression.")
def init_db(self):
contract_storage, _ = get_persistent_storage(self.mythril_dir)
try:
contract_storage.initialize(self.eth)
except FileNotFoundError as e:
raise CriticalError("Error syncing database over IPC: " + str(e))
except ConnectionError as e:
raise CriticalError("Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly.")
def load_from_bytecode(self, code):
address = util.get_indexed_address(0)
self.contracts.append(ETHContract(code, name="MAIN"))
@ -283,6 +303,7 @@ class Mythril(object):
try:
signatures.add_signatures_from_file(file, self.sigs)
self._update_signatures(self.sigs)
contract = SolidityContract(file, contract_name, solc_args=self.solc_args)
logging.info("Analyzing contract %s:%s" % (file, contract.name))
except FileNotFoundError:
@ -295,7 +316,6 @@ class Mythril(object):
self.contracts.append(contract)
contracts.append(contract)
self._update_signatures(self.sigs)
return address, contracts
def dump_statespace(self, contract, address=None, max_depth=12):

@ -10,7 +10,7 @@ def add_signatures_from_file(file, sigs={}):
code = f.read()
funcs = re.findall(r'function[\s]+(.*?\))', code, re.DOTALL)
funcs = re.findall(r'function[\s]+(\w+\([^\)]*\))', code, re.DOTALL)
for f in funcs:

@ -10,7 +10,7 @@ from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.report import Report
from mythril.ether import util
from laser.ethereum import helper
from mythril.laser.ethereum import helper
def analyze_truffle_project(args):
@ -41,7 +41,7 @@ def analyze_truffle_project(args):
ethcontract = ETHContract(bytecode, name=name)
address = util.get_indexed_address(0)
sym = SymExecWrapper(ethcontract, address, max_depth=10)
sym = SymExecWrapper(ethcontract, address, max_depth=args.max_depth)
issues = fire_lasers(sym)
if not len(issues):
@ -80,7 +80,7 @@ def analyze_truffle_project(args):
for issue in issues:
index = helper.get_instruction_index(disassembly.instruction_list, issue.pc)
index = helper.get_instruction_index(disassembly.instruction_list, issue.address)
if index:
try:

@ -1,22 +1,23 @@
rlp<1.0.0
ethereum>=2.3.0
ZODB>=5.3.0
z3-solver>=4.5
laser-ethereum>=0.17.8
requests
BTrees
plyvel
py-solc
pytest
configparser>=3.5.0
coverage
eth_abi>=1.0.0
eth-utils>=1.0.1
eth-account>=0.1.0a2
ethereum>=2.3.0
eth-hash>=0.1.0
eth-keyfile>=0.5.1
eth-keys>=0.2.0b3
eth-rlp>=0.1.0
eth-tester>=0.1.0b21
coverage
jinja2
attrs
pytest
eth-utils>=1.0.1
jinja2>=2.9
mock
persistent>=4.2.0
plyvel
py-flags
py-solc
pytest>=3.6.0
pytest-cov
pytest_mock
requests
rlp<1.0.0
z3-solver>=4.5

@ -1,11 +1,13 @@
from setuptools import setup, find_packages
from setuptools.command.install import install
import sys
import os
# Package version (vX.Y.Z). It must match git tag being used for CircleCI
# deployment; otherwise the build will failed.
VERSION = "v0.17.9"
VERSION = "v0.18.7"
class VerifyVersionCommand(install):
"""Custom command to verify that the git tag matches our version"""
@ -157,26 +159,24 @@ unfortunately completely destroys usability.
Blockchain exploration
----------------------
Mythril builds its own contract database to enable fast search
operations. This enables operations like those described in the
`legendary "Mitch Brenner" blog
post <https://medium.com/@rtaylor30/how-i-snatched-your-153-037-eth-after-a-bad-tinder-date-d1d84422a50b>`__
in [STRIKEOUT:seconds] minutes instead of days. Unfortunately, the
initial sync process is slow. You don't need to sync the whole
blockchain right away though: If you abort the syncing process with
``ctrl+c``, it will be auto-resumed the next time you run the
``--init-db`` command.
Mythril allows to search geth contract database directly as well as
perform other operations targetting local geth database instead of
exposed RPC/IPC API. This enables operations like those described
in the `legendary "Mitch Brenner" blog post
<https://medium.com/@rtaylor30/how-i-snatched-your-153-037-eth-after-a-bad-tinder-date-d1d84422a50b>`__
in [STRIKEOUT:seconds] minutes instead of days.
.. code:: bash
The default behavior is to search contracts with a non-zero balance.
You can disable this behavior with the ``--search-all`` flag.
$ myth --init-db
Starting synchronization from latest block: 4323706
Processing block 4323000, 3 individual contracts in database
(...)
You may also use geth database directly for fetching contracts instead of
using IPC/RPC APIs by specifying ``--leveldb`` flag. This is useful
because search will return hashed addresses which will not be accepted by
IPC/RPC APIs.
The default behavior is to only sync contracts with a non-zero balance.
You can disable this behavior with the ``--sync-all`` flag, but be aware
that this will result in a huge (as in: dozens of GB) database.
By default database operations will target default geth data directory on
your system. You may edit the generated configuration at ``~/.mythril/config.ini``
or you may supply ``--leveldb-dir <PATH>`` parameter in command line.
Searching from the command line
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -188,8 +188,9 @@ expressions, such as:
.. code:: bash
$ myth --search "func#changeMultisig(address)#"
$ myth --search "code#PUSH1 0x50,POP#"
$ myth --search "code#PUSH1 0x50,POP#" --search-all
$ myth --search "func#changeMultisig(address)# and code#PUSH1 0x50#"
$ myth -s "code#PUSH#" --leveldb-dir /Volumes/MyPassport/Ether/Rinkeby/geth/chaindata
Reading contract storage
~~~~~~~~~~~~~~~~~~~~~~~~
@ -305,14 +306,10 @@ setup(
install_requires=[
'ethereum>=2.3.0',
'ZODB>=5.3.0',
'z3-solver>=4.5',
'laser-ethereum>=0.17.8',
'requests',
'BTrees',
'py-solc',
'plyvel',
'pytest',
'eth_abi>=1.0.0',
'eth-utils>=1.0.1',
'eth-account>=0.1.0a2',
@ -322,9 +319,18 @@ setup(
'eth-rlp>=0.1.0',
'eth-tester>=0.1.0b21',
'coverage',
'jinja2',
'attrs',
'rlp<1.0.0'
'jinja2>=2.9',
'rlp<1.0.0',
'py-flags',
'mock',
'configparser>=3.5.0',
'persistent>=4.2.0'
],
tests_require=[
'pytest>=3.6.0',
'pytest_mock',
'pytest-cov'
],
python_requires='>=3.5',
@ -332,6 +338,10 @@ setup(
extras_require={
},
package_data={
'mythril.analysis.templates': ['*']
},
include_package_data=True,
scripts=['myth'],

@ -28,7 +28,4 @@ contract Crowdfunding {
return balances[msg.sender];
}
function() public payable {
invest();
}
}

@ -7,8 +7,11 @@ TESTS_DIR = Path(__file__).parent
PROJECT_DIR = TESTS_DIR.parent
TESTDATA = TESTS_DIR / "testdata"
TESTDATA_INPUTS = TESTDATA / "inputs"
TESTDATA_INPUTS_CONTRACTS = TESTDATA / "input_contracts"
TESTDATA_OUTPUTS_EXPECTED = TESTDATA / "outputs_expected"
TESTDATA_OUTPUTS_CURRENT = TESTDATA / "outputs_current"
TESTDATA_OUTPUTS_CURRENT_LASER_RESULT = TESTDATA / "outputs_current_laser_result"
TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT = TESTDATA / "outputs_expected_laser_result"
MYTHRIL_DIR = TESTS_DIR / "mythril_dir"

@ -0,0 +1,249 @@
from mythril.analysis.modules.delegatecall import execute, _concrete_call, _symbolic_call
from mythril.analysis.ops import Call, Variable, VarType
from mythril.analysis.symbolic import SymExecWrapper
from mythril.laser.ethereum.svm import GlobalState, Node, Environment, Account
import pytest
from unittest.mock import MagicMock, patch
import pytest_mock
def test_concrete_call():
# arrange
address = "0x10"
state = GlobalState(None, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable(1, VarType.CONCRETE)
meminstart = Variable(1, VarType.CONCRETE)
call = Call(node, state, None, None, to, None)
# act
issues = _concrete_call(call, state, address, meminstart)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Call data forwarded with delegatecall()"
assert issue.type == 'Informational'
assert issue.description == "This contract forwards its call data via DELEGATECALL in its fallback function." \
" This means that any function in the called contract can be executed." \
" Note that the callee contract will have access to the storage of the " \
"calling contract.\n DELEGATECALL target: 0x1"
def test_concrete_call_symbolic_to():
# arrange
address = "0x10"
state = GlobalState(None, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("calldata_3", VarType.SYMBOLIC)
meminstart = Variable(1, VarType.CONCRETE)
call = Call(node, state, None, None, to, None)
# act
issues = _concrete_call(call, state, address, meminstart)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Call data forwarded with delegatecall()"
assert issue.type == 'Informational'
assert issue.description == "This contract forwards its call data via DELEGATECALL in its fallback function." \
" This means that any function in the called contract can be executed." \
" Note that the callee contract will have access to the storage of the " \
"calling contract.\n DELEGATECALL target: calldata_3"
def test_concrete_call_not_calldata():
# arrange
state = GlobalState(None, None)
state.mstate.memory = ["placeholder", "not_calldata"]
meminstart = Variable(1, VarType.CONCRETE)
# act
issues = _concrete_call(None, state, None, meminstart)
# assert
assert issues == []
def test_symbolic_call_storage_to(mocker):
# arrange
address = "0x10"
active_account = Account(address)
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, state, None, "Type: ", to, None)
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None)
statespace = SymExecWrapper(1)
mocker.patch.object(statespace, 'find_storage_write')
statespace.find_storage_write.return_value = "Function name"
# act
issues = _symbolic_call(call, state, address, statespace)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == 'Type: to a user-supplied address'
assert issue.type == 'Informational'
assert issue.description == 'This contract delegates execution to a contract address in storage slot 1.' \
' This storage slot can be written to by calling the function `Function name`. ' \
'Be aware that the called contract gets unrestricted access to this contract\'s state.'
def test_symbolic_call_calldata_to(mocker):
# arrange
address = "0x10"
state = GlobalState(None, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("calldata", VarType.SYMBOLIC)
call = Call(node, state, None, "Type: ", to, None)
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None)
statespace = SymExecWrapper(1)
mocker.patch.object(statespace, 'find_storage_write')
statespace.find_storage_write.return_value = "Function name"
# act
issues = _symbolic_call(call, state, address, statespace)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == 'Type: to a user-supplied address'
assert issue.type == 'Informational'
assert issue.description == 'This contract delegates execution to a contract address obtained from calldata. ' \
'Be aware that the called contract gets unrestricted access to this contract\'s state.'
@patch('mythril.laser.ethereum.svm.GlobalState.get_current_instruction')
@patch('mythril.analysis.modules.delegatecall._concrete_call')
@patch('mythril.analysis.modules.delegatecall._symbolic_call')
def test_delegate_call(sym_mock, concrete_mock, curr_instruction):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
curr_instruction.return_value = {'address': '0x10'}
active_account = Account('0x10')
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
state.mstate.stack = [1, 2, 3]
assert state.get_current_instruction() == {'address': '0x10'}
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, state, None, "DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
issues = execute(statespace)
# assert
assert concrete_mock.call_count == 1
assert sym_mock.call_count == 1
@patch('mythril.analysis.modules.delegatecall._concrete_call')
@patch('mythril.analysis.modules.delegatecall._symbolic_call')
def test_delegate_call_not_delegate(sym_mock, concrete_mock):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
node = Node("example")
node.function_name = "fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, None, None, "NOT_DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
issues = execute(statespace)
# assert
assert issues == []
assert concrete_mock.call_count == 0
assert sym_mock.call_count == 0
@patch('mythril.analysis.modules.delegatecall._concrete_call')
@patch('mythril.analysis.modules.delegatecall._symbolic_call')
def test_delegate_call_not_fallback(sym_mock, concrete_mock):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
node = Node("example")
node.function_name = "not_fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, None, None, "DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
issues = execute(statespace)
# assert
assert issues == []
assert concrete_mock.call_count == 0
assert sym_mock.call_count == 0

@ -1,32 +0,0 @@
from mythril.ether.contractstorage import get_persistent_storage
import os
from tests import BaseTestCase
class GetAndSearchContractTestCase(BaseTestCase):
def setUp(self):
super(GetAndSearchContractTestCase, self).setUp()
script_path = os.path.dirname(os.path.realpath(__file__))
storage_dir = os.path.join(script_path, 'teststorage')
self.storage, self.db = get_persistent_storage(storage_dir)
def tearDown(self):
self.db.close()
super(GetAndSearchContractTestCase, self).tearDown()
def mockCallback(self, code_hash, code, addresses, balances):
self.code_hash = code_hash
self.isFound = True
pass
def runTest(self):
contract = self.storage.get_contract_by_hash(bytes.fromhex("ea061445eacbe86b7ffed2bb9e52075e"))
self.assertTrue("0x60606040" in contract.code, 'error reading contract code from database')
self.isFound = False
self.storage.search("code#PUSH1#", self.mockCallback)
self.assertTrue(self.isFound, 'storage search error')
self.assertEqual(self.code_hash, 'ea061445eacbe86b7ffed2bb9e52075e', 'storage search error')

@ -0,0 +1,117 @@
import json
from mythril.ether.soliditycontract import SolidityContract
from mythril.laser.ethereum.svm import GlobalState, MachineState
from mythril.laser.ethereum import svm
from tests import *
SHA256_TEST = [ (0,False) for i in range(6)]
RIPEMD160_TEST = [ (0,False) for i in range(6)]
ECRECOVER_TEST = [ (0,False) for i in range(9)]
IDENTITY_TEST = [ (0, False) for i in range(4)]
SHA256_TEST[0] = (5555555555555555, True) #These are Random numbers to check whether the 'if condition' is entered or not(True means entered)
SHA256_TEST[1] = (323232325445454546, True)
SHA256_TEST[2] = (34756834765834658, False)
SHA256_TEST[3] = (8756476956956795876987, True)
SHA256_TEST[4] = (5763467587689578369, True)
SHA256_TEST[5] = (948365957658767467857, False)
RIPEMD160_TEST[0] = (1242435356364, True)
RIPEMD160_TEST[1] = (6732648654386435, True)
RIPEMD160_TEST[2] = (97457657536546465, False)
RIPEMD160_TEST[3] = (56436346436456546, True)
RIPEMD160_TEST[4] = (999999999999999999993, True)
RIPEMD160_TEST[5] = (1111111111112, False)
ECRECOVER_TEST[0] = (786428768768632537676, True)
ECRECOVER_TEST[1] = (4897983476979346779638, False)
ECRECOVER_TEST[2] = (674837568743979857398564869, True)
ECRECOVER_TEST[3] = (3487683476979311, False)
ECRECOVER_TEST[4] = (853729594875984769847369, True)
ECRECOVER_TEST[5] = (83579382475972439587, False)
ECRECOVER_TEST[6] = (8437589437695876985769, True)
ECRECOVER_TEST[7] = (9486794873598347697596, False)
ECRECOVER_TEST[8] = (346934876983476, True)
IDENTITY_TEST[0] = (87426857369875698, True)
IDENTITY_TEST[1] = (476934798798347, False)
IDENTITY_TEST[2] = (7346948379483769, True)
IDENTITY_TEST[3] = (83269476937987, False)
def _all_info(laser):
accounts = {}
for address, _account in laser.accounts.items():
account = _account.as_dict()
account["code"] = account["code"].instruction_list
account['balance'] = str(account['balance'])
accounts[address] = account
nodes = {}
for uid, node in laser.nodes.items():
states = []
for state in node.states:
if isinstance(state, MachineState):
states.append(state.as_dict())
elif isinstance(state, GlobalState):
environment = state.environment.as_dict()
environment["active_account"] = environment["active_account"].address
states.append({
'accounts': state.accounts.keys(),
'environment': environment,
'mstate': state.mstate.as_dict()
})
nodes[uid] = {
'uid': node.uid,
'contract_name': node.contract_name,
'start_addr': node.start_addr,
'states': states,
'constraints': node.constraints,
'function_name': node.function_name,
'flags': str(node.flags)
}
edges = [edge.as_dict() for edge in laser.edges]
return {
'accounts': accounts,
'nodes': nodes,
'edges': edges,
'total_states': laser.total_states,
'max_depth': laser.max_depth
}
def _test_natives(laser_info, test_list, test_name):
success = 0
for i,j in test_list:
if (str(i) in laser_info) == j:
success+=1
else:
print ("Failed: "+str(i)+" "+str(j))
assert(success == len(test_list))
class NativeTests(BaseTestCase):
def runTest(self):
disassembly = SolidityContract('./tests/native_tests.sol').disassembly
account = svm.Account("0x0000000000000000000000000000000000000000", disassembly)
accounts = {account.address: account}
laser = svm.LaserEVM(accounts, max_depth = 100)
laser.sym_exec(account.address)
laser_info = str(_all_info(laser))
print('\n')
_test_natives(laser_info, SHA256_TEST, 'SHA256')
_test_natives(laser_info, RIPEMD160_TEST, 'RIPEMD160')
_test_natives(laser_info, ECRECOVER_TEST, 'ECRECOVER')
_test_natives(laser_info, IDENTITY_TEST, 'IDENTITY')

@ -0,0 +1,166 @@
pragma solidity ^0.4.17;
contract Caller {
address public fixed_address; //Just some useless variables
address public stored_address;
uint256 statevar; //useless( but good for testing as they contribute as decoys)
bytes32 far;
function Caller(address addr) {
fixed_address = addr;
}
function thisisfine() public { //some typical function as a decoy
fixed_address.call();
}
function sha256_test1() public {
uint256 i;
if(sha256('ab','c') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True
i = 5555555555555555;
}
if(sha256('abc') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True
i = 323232325445454546;
}
}
function sha256_test2() public {
uint256 i;
if(sha256('abd') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad) { //False
i = 34756834765834658;
}
if(sha256('ab','d') == 0xa52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9) { //True
i = 8756476956956795876987;
}
}
function sha256_test3() public {
uint256 i;
if(sha256('') == 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855) { //True
i = 5763467587689578369;
}
if(sha256('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdhhfdhhhhhh') == 0xe4ebd771f821e3277b77dcc39e94fe7172a5c9c8c12f8885c2d5513385a0a8b8) { //False
i = 948365957658767467857;
}
}
function ripemd_test1() public {
uint256 i;
if(ripemd160('ab','c') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True
i = 1242435356364;
}
if(ripemd160('abc') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True
i = 6732648654386435;
}
}
function ripemd_test2() public {
uint256 i;
if(ripemd160('abd') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc) { //False
i = 97457657536546465;
}
if(ripemd160('ab','d') == 0xb0a79cc77e333ea11974e105cd051d33836928b0) { //True
i = 56436346436456546;
}
}
function ripemd_test3() public {
uint256 i;
if(ripemd160('') == 0x9c1185a5c5e9fc54612808977ee8f548b2258d31) { //True
i = 999999999999999999993;
}
if(ripemd160('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh') == 0x2d1b88a5daa5d138eb7bb14ee320010937f0ebe7) { //False
i = 1111111111112;
}
}
function ecrecover_test1() public {
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8;
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(prefix, foobar);
uint8 v = 28;
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608;
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada;
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8a) { //True
uint256 bignum = 786428768768632537676;
}
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False
uint256 small = 4897983476979346779638;
}
foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e;
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //True
uint256 dk = 674837568743979857398564869;
}
foobar = 0x38d18acb67d25c7bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; //not same as above, minor change(7bb instead of 8bb)
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //False
uint256 pk = 3487683476979311;
}
}
function ecrecover_test2() public {
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8;
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(prefix, foobar);
uint8 v = 26;
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608;
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada;
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True
uint256 bignum = 853729594875984769847369;
}
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False
uint256 small = 83579382475972439587;
}
}
function ecrecover_test3() public {
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8;
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(prefix, foobar);
uint8 v = 29;
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608;
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada;
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True
uint256 bignum = 8437589437695876985769;
}
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False
uint256 small = 9486794873598347697596;
}
}
function ecrecover_test4() public {
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8;
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(prefix, foobar);
uint8 v = 27;
bytes32 r = 0xfffffffffffffffffffffffffffffffffaaedce6af48a03bbfd25e8cd0364141; //greater than the max limit
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada;
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True
uint256 bignum = 346934876983476;
}
}
function need_identity_invoke(uint sea) returns (uint) {
return sea; //identity is invoked here in compiler and not below
}
function identity_function(int input) public returns(int out) {
assembly{
let x := mload(0x40)
mstore(x, input)
let success := call(500000000, 0x4, 100000, x, 0x20, x, 0x20)
out := mload(x)
mstore(0x40, x)
}
}
function identity_test1() public{
if(identity_function(100)==100) //True
uint256 smallnum = 87426857369875698;
if(identity_function(200)==100) //False
uint256 bignum = 476934798798347;
}
function identity_test2() public{
if(identity_function(12345678)==12345678) //True
uint256 smallnum = 7346948379483769;
if(identity_function(74648796976)==4685987) //False
uint256 bignum = 83269476937987;
}
}

@ -19,7 +19,7 @@ def _fix_debug_data(json_str):
read_json = json.loads(json_str)
for issue in read_json["issues"]:
issue["debug"] = "<DEBUG-DATA>"
return json.dumps(read_json, indent=4)
return json.dumps(read_json, sort_keys=True)
def _generate_report(input_file):
@ -44,18 +44,41 @@ def reports():
return results
def _assert_empty(changed_files):
def _assert_empty(changed_files, postfix):
""" Asserts there are no changed files and otherwise builds error message"""
message = ""
for input_file in changed_files:
output_expected = (TESTDATA_OUTPUTS_EXPECTED / (input_file.name + ".json")).read_text().splitlines(1)
output_current = (TESTDATA_OUTPUTS_CURRENT / (input_file.name + ".json")).read_text().splitlines(1)
output_expected = (TESTDATA_OUTPUTS_EXPECTED / (input_file.name + postfix)).read_text().splitlines(1)
output_current = (TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix)).read_text().splitlines(1)
difference = ''.join(difflib.unified_diff(output_expected, output_current))
message += "Found differing file for input: {} \n Difference: \n {} \n".format(str(input_file), str(difference))
assert message == "", message
def _assert_empty_json(changed_files):
""" Asserts there are no changed files and otherwise builds error message"""
postfix = ".json"
expected = []
actual = []
def ordered(obj):
if isinstance(obj, dict):
return sorted((k, ordered(v)) for k, v in obj.items())
elif isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
for input_file in changed_files:
output_expected = json.loads((TESTDATA_OUTPUTS_EXPECTED / (input_file.name + postfix)).read_text())
output_current = json.loads((TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix)).read_text())
if not ordered(output_expected.items()) == ordered(output_current.items()):
expected.append(output_expected)
actual.append(output_current)
assert expected == actual
def _get_changed_files(postfix, report_builder, reports):
"""
@ -74,13 +97,32 @@ def _get_changed_files(postfix, report_builder, reports):
yield input_file
def _get_changed_files_json(report_builder, reports):
postfix = ".json"
def ordered(obj):
if isinstance(obj, dict):
return sorted((k, ordered(v)) for k, v in obj.items())
elif isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
for report, input_file in reports:
output_expected = TESTDATA_OUTPUTS_EXPECTED / (input_file.name + postfix)
output_current = TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix)
output_current.write_text(report_builder(report))
if not ordered(json.loads(output_expected.read_text())) == ordered(json.loads(output_current.read_text())):
yield input_file
def test_json_report(reports):
_assert_empty(_get_changed_files('.json', lambda report: _fix_path(_fix_debug_data(report.as_json())).strip(), reports))
_assert_empty_json(_get_changed_files_json(lambda report: _fix_path(_fix_debug_data(report.as_json())).strip(), reports))
def test_markdown_report(reports):
_assert_empty(_get_changed_files('.markdown', lambda report: _fix_path(report.as_markdown()), reports))
_assert_empty(_get_changed_files('.markdown', lambda report: _fix_path(report.as_markdown()), reports), '.markdown')
def test_text_report(reports):
_assert_empty(_get_changed_files('.text', lambda report: _fix_path(report.as_text()), reports))
_assert_empty(_get_changed_files('.text', lambda report: _fix_path(report.as_text()), reports), '.text')

@ -1,10 +1,92 @@
import unittest
import json
from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph
from mythril.ether.ethcontract import ETHContract
from mythril.ether.soliditycontract import SolidityContract
from mythril.laser.ethereum.svm import GlobalState, MachineState
from mythril.laser.ethereum import svm
from tests import *
class SVMTestCase(unittest.TestCase):
class LaserEncoder(json.JSONEncoder):
def default(self, o):
if getattr(o, "__module__", None) == "z3.z3":
return str(o)
return str(o)
def _all_info(laser):
accounts = {}
for address, _account in laser.accounts.items():
account = _account.as_dict()
account["code"] = account["code"].instruction_list
account['balance'] = str(account['balance'])
accounts[address] = account
nodes = {}
for uid, node in laser.nodes.items():
states = []
for state in node.states:
if isinstance(state, MachineState):
states.append(state.as_dict())
elif isinstance(state, GlobalState):
environment = state.environment.as_dict()
environment["active_account"] = environment["active_account"].address
states.append({
'accounts': state.accounts.keys(),
'environment': environment,
'mstate': state.mstate.as_dict()
})
nodes[uid] = {
'uid': node.uid,
'contract_name': node.contract_name,
'start_addr': node.start_addr,
'states': states,
'constraints': node.constraints,
'function_name': node.function_name,
'flags': str(node.flags)
}
edges = [edge.as_dict() for edge in laser.edges]
return {
'accounts': accounts,
'nodes': nodes,
'edges': edges,
'total_states': laser.total_states,
'max_depth': laser.max_depth
}
class SVMTestCase(BaseTestCase):
def setUp(self):
super(SVMTestCase, self).setUp()
svm.gbl_next_uid = 0
def test_laser_result(self):
for input_file in TESTDATA_INPUTS_CONTRACTS.iterdir():
if input_file.name == "weak_random.sol":
continue
output_expected = TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT / (input_file.name + ".json")
output_current = TESTDATA_OUTPUTS_CURRENT_LASER_RESULT / (input_file.name + ".json")
disassembly = SolidityContract(str(input_file)).disassembly
account = svm.Account("0x0000000000000000000000000000000000000000", disassembly)
accounts = {account.address: account}
laser = svm.LaserEVM(accounts)
laser.sym_exec(account.address)
laser_info = _all_info(laser)
output_current.write_text(json.dumps(laser_info, cls=LaserEncoder, indent=4))
if not (output_expected.read_text() == output_expected.read_text()):
self.found_changed_files(input_file, output_expected, output_current)
self.assert_and_show_changed_files()
def runTest(self):

@ -0,0 +1,29 @@
from mythril.laser.ethereum.taint_analysis import *
def test_mutate_not_tainted():
# Arrange
record = TaintRecord()
record.stack = [True, False, False]
# Act
TaintRunner.mutate_stack(record, (2,1))
# Assert
assert record.stack_tainted(0)
assert record.stack_tainted(1) is False
assert record.stack == [True, False]
def test_mutate_tainted():
# Arrange
record = TaintRecord()
record.stack = [True, False, True]
# Act
TaintRunner.mutate_stack(record, (2, 1))
# Assert
assert record.stack_tainted(0)
assert record.stack_tainted(1)
assert record.stack == [True, True]

@ -0,0 +1,36 @@
from mythril.laser.ethereum.taint_analysis import *
def test_record_tainted_check():
# arrange
record = TaintRecord()
record.stack = [True, False, True]
# act
tainted = record.stack_tainted(2)
# assert
assert tainted is True
def test_record_untainted_check():
# arrange
record = TaintRecord()
record.stack = [True, False, False]
# act
tainted = record.stack_tainted(2)
# assert
assert tainted is False
def test_record_untouched_check():
# arrange
record = TaintRecord()
# act
tainted = record.stack_tainted(3)
# assert
assert tainted is None

@ -0,0 +1,36 @@
from mythril.laser.ethereum.taint_analysis import *
from mythril.laser.ethereum.svm import GlobalState
def test_result_state():
# arrange
taint_result = TaintResult()
record = TaintRecord()
state = GlobalState(2, None)
state.mstate.stack = [1,2,3]
record.add_state(state)
record.stack = [False, False, False]
# act
taint_result.add_records([record])
tainted = taint_result.check(state, 2)
# assert
assert tainted is False
assert record in taint_result.records
def test_result_no_state():
# arrange
taint_result = TaintResult()
record = TaintRecord()
state = GlobalState(2, None)
state.mstate.stack = [1,2,3]
# act
taint_result.add_records([record])
tainted = taint_result.check(state, 2)
# assert
assert tainted is None
assert record in taint_result.records

@ -0,0 +1,94 @@
import mock
import pytest
from pytest_mock import mocker
from mythril.laser.ethereum.taint_analysis import *
from mythril.laser.ethereum.svm import GlobalState, Node, Edge, LaserEVM, MachineState
def test_execute_state(mocker):
record = TaintRecord()
record.stack = [True, False, True]
state = GlobalState(None, None)
state.mstate.stack = [1, 2, 3]
mocker.patch.object(state, 'get_current_instruction')
state.get_current_instruction.return_value = {"opcode": "ADD"}
# Act
new_record = TaintRunner.execute_state(record, state)
# Assert
assert new_record.stack == [True, True]
assert record.stack == [True, False, True]
def test_execute_node(mocker):
record = TaintRecord()
record.stack = [True, True, False, False]
state_1 = GlobalState(None, None)
state_1.mstate.stack = [1, 2, 3]
state_1.mstate.pc = 1
mocker.patch.object(state_1, 'get_current_instruction')
state_1.get_current_instruction.return_value = {"opcode": "SWAP1"}
state_2 = GlobalState(None, 1)
state_2.mstate.stack = [1, 2, 4, 1]
mocker.patch.object(state_2, 'get_current_instruction')
state_2.get_current_instruction.return_value = {"opcode": "ADD"}
node = Node("Test contract")
node.states = [state_1, state_2]
# Act
records = TaintRunner.execute_node(node, record)
# Assert
assert len(records) == 2
assert records[0].stack == [True, True, False, False]
assert records[1].stack == [True, True, False]
assert state_2 in records[0].states
assert state_1 in record.states
def test_execute(mocker):
state_1 = GlobalState(None, None, MachineState(gas=10000000))
state_1.mstate.stack = [1, 2]
mocker.patch.object(state_1, 'get_current_instruction')
state_1.get_current_instruction.return_value = {"opcode": "PUSH"}
state_2 = GlobalState(None, None, MachineState(gas=10000000))
state_2.mstate.stack = [1, 2, 3]
mocker.patch.object(state_2, 'get_current_instruction')
state_2.get_current_instruction.return_value = {"opcode": "ADD"}
node_1 = Node("Test contract")
node_1.states = [state_1, state_2]
state_3 = GlobalState(None, None, MachineState(gas=10000000))
state_3.mstate.stack = [1, 2]
mocker.patch.object(state_3, 'get_current_instruction')
state_3.get_current_instruction.return_value = {"opcode": "ADD"}
node_2 = Node("Test contract")
node_2.states = [state_3]
edge = Edge(node_1.uid, node_2.uid)
statespace = LaserEVM(None)
statespace.edges = [edge]
statespace.nodes[node_1.uid] = node_1
statespace.nodes[node_2.uid] = node_2
# Act
result = TaintRunner.execute(statespace, node_1, state_1, [True, True])
# Assert
print(result)
assert len(result.records) == 3
assert result.records[2].states == []
assert state_3 in result.records[1].states

@ -28,7 +28,4 @@ contract Crowdfunding {
return balances[msg.sender];
}
function() public payable {
invest();
}
}

@ -0,0 +1,6 @@
pragma solidity ^0.4.22;
contract nonAscii {
function renderNonAscii () public pure returns (string) {
return "Хэллоу Ворлд";
}
}

@ -0,0 +1,152 @@
contract Rubixi {
//Declare variables for storage critical to contract
uint private balance = 0;
uint private collectedFees = 0;
uint private feePercent = 10;
uint private pyramidMultiplier = 300;
uint private payoutOrder = 0;
address private creator;
//Sets creator
function DynamicPyramid() {
creator = msg.sender;
}
modifier onlyowner {
if (msg.sender == creator) _;
}
struct Participant {
address etherAddress;
uint payout;
}
Participant[] private participants;
//Fallback function
function() {
init();
}
//init function run on fallback
function init() private {
//Ensures only tx with value of 1 ether or greater are processed and added to pyramid
if (msg.value < 1 ether) {
collectedFees += msg.value;
return;
}
uint _fee = feePercent;
//50% fee rebate on any ether value of 50 or greater
if (msg.value >= 50 ether) _fee /= 2;
addPayout(_fee);
}
//Function called for valid tx to the contract
function addPayout(uint _fee) private {
//Adds new address to participant array
participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100));
//These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan
if (participants.length == 10) pyramidMultiplier = 200;
else if (participants.length == 25) pyramidMultiplier = 150;
// collect fees and update contract balance
balance += (msg.value * (100 - _fee)) / 100;
collectedFees += (msg.value * _fee) / 100;
//Pays earlier participiants if balance sufficient
while (balance > participants[payoutOrder].payout) {
uint payoutToSend = participants[payoutOrder].payout;
participants[payoutOrder].etherAddress.send(payoutToSend);
balance -= participants[payoutOrder].payout;
payoutOrder += 1;
}
}
//Fee functions for creator
function collectAllFees() onlyowner {
if (collectedFees == 0) throw;
creator.send(collectedFees);
collectedFees = 0;
}
function collectFeesInEther(uint _amt) onlyowner {
_amt *= 1 ether;
if (_amt > collectedFees) collectAllFees();
if (collectedFees == 0) throw;
creator.send(_amt);
collectedFees -= _amt;
}
function collectPercentOfFees(uint _pcent) onlyowner {
if (collectedFees == 0 || _pcent > 100) throw;
uint feesToCollect = collectedFees / 100 * _pcent;
creator.send(feesToCollect);
collectedFees -= feesToCollect;
}
//Functions for changing variables related to the contract
function changeOwner(address _owner) onlyowner {
creator = _owner;
}
function changeMultiplier(uint _mult) onlyowner {
if (_mult > 300 || _mult < 120) throw;
pyramidMultiplier = _mult;
}
function changeFeePercentage(uint _fee) onlyowner {
if (_fee > 10) throw;
feePercent = _fee;
}
//Functions to provide information to end-user using JSON interface or other interfaces
function currentMultiplier() constant returns(uint multiplier, string info) {
multiplier = pyramidMultiplier;
info = 'This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min.';
}
function currentFeePercentage() constant returns(uint fee, string info) {
fee = feePercent;
info = 'Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)';
}
function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) {
pyramidBalance = balance / 1 ether;
info = 'All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to';
}
function nextPayoutWhenPyramidBalanceTotalsApproximately() constant returns(uint balancePayout) {
balancePayout = participants[payoutOrder].payout / 1 ether;
}
function feesSeperateFromBalanceApproximately() constant returns(uint fees) {
fees = collectedFees / 1 ether;
}
function totalParticipants() constant returns(uint count) {
count = participants.length;
}
function numberOfParticipantsWaitingForPayout() constant returns(uint count) {
count = participants.length - payoutOrder;
}
function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) {
if (orderInPyramid <= participants.length) {
Address = participants[orderInPyramid].etherAddress;
Payout = participants[orderInPyramid].payout / 1 ether;
}
}
}

@ -1 +1 @@
606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806312065fe01461008257806327e235e3146100ab57806356885cd8146100f85780636c343ffe1461010d5780638da5cb5b14610122578063e8b5e51f14610177575b610080610181565b005b341561008d57600080fd5b6100956101ec565b6040518082815260200191505060405180910390f35b34156100b657600080fd5b6100e2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610232565b6040518082815260200191505060405180910390f35b341561010357600080fd5b61010b61024a565b005b341561011857600080fd5b61012061028d565b005b341561012d57600080fd5b610135610342565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61017f610181565b005b60025434118015610193575060035434105b151561019e57600080fd5b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b60006020528060005260406000206000915090505481565b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102e957600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561034057600080fd5b565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820bbf8d45345e3ef7004b6445155bc5f20c8a6dc61dec2637ed9f5eb80f5b2ab0a0029
608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806312065fe01461007d57806327e235e3146100a857806356885cd8146100ff5780636c343ffe146101165780638da5cb5b1461012d578063e8b5e51f14610184575b600080fd5b34801561008957600080fd5b5061009261018e565b6040518082815260200191505060405180910390f35b3480156100b457600080fd5b506100e9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506101d4565b6040518082815260200191505060405180910390f35b34801561010b57600080fd5b506101146101ec565b005b34801561012257600080fd5b5061012b61022f565b005b34801561013957600080fd5b506101426102eb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61018c610311565b005b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b60006020528060005260406000206000915090505481565b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561028b57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156102e8573d6000803e3d6000fd5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025434118015610323575060035434105b151561032e57600080fd5b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820402df619c16e4325eb7830ed063880a283ac25dff982b6a5be67138df0c209550029

@ -0,0 +1 @@
608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806324ff38a214610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60606040805190810160405280601781526020017fd0a5d18dd0bbd0bbd0bed18320d092d0bed180d0bbd0b40000000000000000008152509050905600a165627a7a72305820a11284868fc6a38ff1d72ce9ec40db9c6c7c49902b5cabec3680e88e5ab92dcb0029

@ -11,49 +11,27 @@
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
## Message call to external contract
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xd24b08cc`
- PC address: 779
### Description
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
## Message call to external contract
## Unchecked CALL return value
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xe11f493e`
- PC address: 858
### Description
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
## State change after external call
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe11f493e`
- PC address: 869
- Function name: `_function_0x5a6814ec`
- PC address: 661
### Description
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe1d10f79`
- PC address: 912
- Function name: `_function_0xd24b08cc`
- PC address: 779
### Description
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
## Transaction order dependence
@ -70,23 +48,23 @@ A possible transaction order independence vulnerability exists in function _func
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x5a6814ec`
- PC address: 661
- Function name: `_function_0xd24b08cc`
- PC address: 779
### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Unchecked CALL return value
## Message call to external contract
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xd24b08cc`
- PC address: 779
- Function name: `_function_0xe11f493e`
- PC address: 858
### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
## Unchecked CALL return value
@ -99,6 +77,28 @@ The return value of an external call is not checked. Note that execution continu
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## State change after external call
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe11f493e`
- PC address: 869
### Description
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
## Message call to external contract
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe1d10f79`
- PC address: 912
### Description
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
## Unchecked CALL return value
- Type: Informational

@ -6,36 +6,20 @@ PC address: 661
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
--------------------
==== Message call to external contract ====
Type: Warning
Contract: Unknown
Function name: _function_0xd24b08cc
PC address: 779
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
--------------------
==== Message call to external contract ====
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown
Function name: _function_0xe11f493e
PC address: 858
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
--------------------
==== State change after external call ====
Type: Warning
Contract: Unknown
Function name: _function_0xe11f493e
PC address: 869
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
Function name: _function_0x5a6814ec
PC address: 661
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Message call to external contract ====
Type: Warning
Contract: Unknown
Function name: _function_0xe1d10f79
PC address: 912
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
Function name: _function_0xd24b08cc
PC address: 779
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
--------------------
==== Transaction order dependence ====
@ -49,17 +33,17 @@ A possible transaction order independence vulnerability exists in function _func
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown
Function name: _function_0x5a6814ec
PC address: 661
Function name: _function_0xd24b08cc
PC address: 779
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Unchecked CALL return value ====
==== Message call to external contract ====
Type: Informational
Contract: Unknown
Function name: _function_0xd24b08cc
PC address: 779
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
Function name: _function_0xe11f493e
PC address: 858
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
--------------------
==== Unchecked CALL return value ====
@ -70,6 +54,22 @@ PC address: 858
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== State change after external call ====
Type: Warning
Contract: Unknown
Function name: _function_0xe11f493e
PC address: 869
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
--------------------
==== Message call to external contract ====
Type: Warning
Contract: Unknown
Function name: _function_0xe1d10f79
PC address: 912
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
--------------------
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown

@ -1,4 +1,4 @@
0 PUSH1 0x60
0 PUSH1 0x80
2 PUSH1 0x40
4 MSTORE
5 PUSH1 0x04
@ -16,383 +16,405 @@
54 DUP1
55 PUSH4 0x12065fe0
60 EQ
61 PUSH2 0x0082
61 PUSH2 0x007d
64 JUMPI
65 DUP1
66 PUSH4 0x27e235e3
71 EQ
72 PUSH2 0x00ab
72 PUSH2 0x00a8
75 JUMPI
76 DUP1
77 PUSH4 0x56885cd8
82 EQ
83 PUSH2 0x00f8
83 PUSH2 0x00ff
86 JUMPI
87 DUP1
88 PUSH4 0x6c343ffe
93 EQ
94 PUSH2 0x010d
94 PUSH2 0x0116
97 JUMPI
98 DUP1
99 PUSH4 0x8da5cb5b
104 EQ
105 PUSH2 0x0122
105 PUSH2 0x012d
108 JUMPI
109 DUP1
110 PUSH4 0xe8b5e51f
115 EQ
116 PUSH2 0x0177
116 PUSH2 0x0184
119 JUMPI
120 JUMPDEST
121 PUSH2 0x0080
124 PUSH2 0x0181
127 JUMP
128 JUMPDEST
129 STOP
130 JUMPDEST
131 CALLVALUE
132 ISZERO
133 PUSH2 0x008d
136 JUMPI
137 PUSH1 0x00
139 DUP1
140 REVERT
141 JUMPDEST
142 PUSH2 0x0095
145 PUSH2 0x01ec
148 JUMP
149 JUMPDEST
150 PUSH1 0x40
152 MLOAD
153 DUP1
154 DUP3
155 DUP2
156 MSTORE
157 PUSH1 0x20
159 ADD
160 SWAP2
161 POP
162 POP
163 PUSH1 0x40
165 MLOAD
166 DUP1
167 SWAP2
168 SUB
169 SWAP1
170 RETURN
171 JUMPDEST
172 CALLVALUE
173 ISZERO
174 PUSH2 0x00b6
177 JUMPI
178 PUSH1 0x00
180 DUP1
181 REVERT
182 JUMPDEST
183 PUSH2 0x00e2
186 PUSH1 0x04
188 DUP1
189 DUP1
190 CALLDATALOAD
191 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
212 AND
213 SWAP1
214 PUSH1 0x20
216 ADD
217 SWAP1
218 SWAP2
219 SWAP1
220 POP
221 POP
222 PUSH2 0x0232
225 JUMP
226 JUMPDEST
227 PUSH1 0x40
229 MLOAD
230 DUP1
231 DUP3
232 DUP2
233 MSTORE
234 PUSH1 0x20
236 ADD
237 SWAP2
238 POP
239 POP
240 PUSH1 0x40
242 MLOAD
243 DUP1
121 PUSH1 0x00
123 DUP1
124 REVERT
125 JUMPDEST
126 CALLVALUE
127 DUP1
128 ISZERO
129 PUSH2 0x0089
132 JUMPI
133 PUSH1 0x00
135 DUP1
136 REVERT
137 JUMPDEST
138 POP
139 PUSH2 0x0092
142 PUSH2 0x018e
145 JUMP
146 JUMPDEST
147 PUSH1 0x40
149 MLOAD
150 DUP1
151 DUP3
152 DUP2
153 MSTORE
154 PUSH1 0x20
156 ADD
157 SWAP2
158 POP
159 POP
160 PUSH1 0x40
162 MLOAD
163 DUP1
164 SWAP2
165 SUB
166 SWAP1
167 RETURN
168 JUMPDEST
169 CALLVALUE
170 DUP1
171 ISZERO
172 PUSH2 0x00b4
175 JUMPI
176 PUSH1 0x00
178 DUP1
179 REVERT
180 JUMPDEST
181 POP
182 PUSH2 0x00e9
185 PUSH1 0x04
187 DUP1
188 CALLDATASIZE
189 SUB
190 DUP2
191 ADD
192 SWAP1
193 DUP1
194 DUP1
195 CALLDATALOAD
196 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
217 AND
218 SWAP1
219 PUSH1 0x20
221 ADD
222 SWAP1
223 SWAP3
224 SWAP2
225 SWAP1
226 POP
227 POP
228 POP
229 PUSH2 0x01d4
232 JUMP
233 JUMPDEST
234 PUSH1 0x40
236 MLOAD
237 DUP1
238 DUP3
239 DUP2
240 MSTORE
241 PUSH1 0x20
243 ADD
244 SWAP2
245 SUB
246 SWAP1
247 RETURN
248 JUMPDEST
249 CALLVALUE
250 ISZERO
251 PUSH2 0x0103
254 JUMPI
255 PUSH1 0x00
245 POP
246 POP
247 PUSH1 0x40
249 MLOAD
250 DUP1
251 SWAP2
252 SUB
253 SWAP1
254 RETURN
255 JUMPDEST
256 CALLVALUE
257 DUP1
258 REVERT
259 JUMPDEST
260 PUSH2 0x010b
263 PUSH2 0x024a
266 JUMP
258 ISZERO
259 PUSH2 0x010b
262 JUMPI
263 PUSH1 0x00
265 DUP1
266 REVERT
267 JUMPDEST
268 STOP
269 JUMPDEST
270 CALLVALUE
271 ISZERO
272 PUSH2 0x0118
275 JUMPI
276 PUSH1 0x00
278 DUP1
279 REVERT
280 JUMPDEST
281 PUSH2 0x0120
284 PUSH2 0x028d
287 JUMP
288 JUMPDEST
289 STOP
268 POP
269 PUSH2 0x0114
272 PUSH2 0x01ec
275 JUMP
276 JUMPDEST
277 STOP
278 JUMPDEST
279 CALLVALUE
280 DUP1
281 ISZERO
282 PUSH2 0x0122
285 JUMPI
286 PUSH1 0x00
288 DUP1
289 REVERT
290 JUMPDEST
291 CALLVALUE
292 ISZERO
293 PUSH2 0x012d
296 JUMPI
297 PUSH1 0x00
299 DUP1
300 REVERT
291 POP
292 PUSH2 0x012b
295 PUSH2 0x022f
298 JUMP
299 JUMPDEST
300 STOP
301 JUMPDEST
302 PUSH2 0x0135
305 PUSH2 0x0342
308 JUMP
309 JUMPDEST
310 PUSH1 0x40
312 MLOAD
313 DUP1
314 DUP3
315 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
336 AND
337 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
358 AND
359 DUP2
360 MSTORE
361 PUSH1 0x20
363 ADD
364 SWAP2
365 POP
366 POP
367 PUSH1 0x40
369 MLOAD
370 DUP1
371 SWAP2
372 SUB
373 SWAP1
374 RETURN
375 JUMPDEST
376 PUSH2 0x017f
379 PUSH2 0x0181
382 JUMP
383 JUMPDEST
384 STOP
385 JUMPDEST
386 PUSH1 0x02
388 SLOAD
389 CALLVALUE
390 GT
391 DUP1
392 ISZERO
393 PUSH2 0x0193
396 JUMPI
397 POP
398 PUSH1 0x03
400 SLOAD
401 CALLVALUE
402 LT
403 JUMPDEST
404 ISZERO
405 ISZERO
406 PUSH2 0x019e
409 JUMPI
410 PUSH1 0x00
412 DUP1
413 REVERT
414 JUMPDEST
415 CALLVALUE
416 PUSH1 0x00
418 DUP1
419 CALLER
420 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
441 AND
442 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
463 AND
464 DUP2
465 MSTORE
466 PUSH1 0x20
468 ADD
469 SWAP1
470 DUP2
471 MSTORE
472 PUSH1 0x20
474 ADD
302 CALLVALUE
303 DUP1
304 ISZERO
305 PUSH2 0x0139
308 JUMPI
309 PUSH1 0x00
311 DUP1
312 REVERT
313 JUMPDEST
314 POP
315 PUSH2 0x0142
318 PUSH2 0x02eb
321 JUMP
322 JUMPDEST
323 PUSH1 0x40
325 MLOAD
326 DUP1
327 DUP3
328 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
349 AND
350 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
371 AND
372 DUP2
373 MSTORE
374 PUSH1 0x20
376 ADD
377 SWAP2
378 POP
379 POP
380 PUSH1 0x40
382 MLOAD
383 DUP1
384 SWAP2
385 SUB
386 SWAP1
387 RETURN
388 JUMPDEST
389 PUSH2 0x018c
392 PUSH2 0x0311
395 JUMP
396 JUMPDEST
397 STOP
398 JUMPDEST
399 PUSH1 0x00
401 DUP1
402 PUSH1 0x00
404 CALLER
405 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
426 AND
427 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
448 AND
449 DUP2
450 MSTORE
451 PUSH1 0x20
453 ADD
454 SWAP1
455 DUP2
456 MSTORE
457 PUSH1 0x20
459 ADD
460 PUSH1 0x00
462 SHA3
463 SLOAD
464 SWAP1
465 POP
466 SWAP1
467 JUMP
468 JUMPDEST
469 PUSH1 0x00
471 PUSH1 0x20
473 MSTORE
474 DUP1
475 PUSH1 0x00
477 SHA3
478 PUSH1 0x00
480 DUP3
481 DUP3
482 SLOAD
483 ADD
484 SWAP3
485 POP
477 MSTORE
478 PUSH1 0x40
480 PUSH1 0x00
482 SHA3
483 PUSH1 0x00
485 SWAP2
486 POP
487 DUP2
488 SWAP1
489 SSTORE
490 POP
487 SWAP1
488 POP
489 SLOAD
490 DUP2
491 JUMP
492 JUMPDEST
493 PUSH1 0x00
495 DUP1
493 CALLER
494 PUSH1 0x01
496 PUSH1 0x00
498 CALLER
499 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
520 AND
521 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
542 AND
543 DUP2
544 MSTORE
545 PUSH1 0x20
547 ADD
548 SWAP1
549 DUP2
550 MSTORE
551 PUSH1 0x20
553 ADD
554 PUSH1 0x00
556 SHA3
557 SLOAD
558 SWAP1
559 POP
560 SWAP1
561 JUMP
562 JUMPDEST
563 PUSH1 0x00
565 PUSH1 0x20
567 MSTORE
568 DUP1
569 PUSH1 0x00
571 MSTORE
572 PUSH1 0x40
574 PUSH1 0x00
576 SHA3
577 PUSH1 0x00
579 SWAP2
580 POP
581 SWAP1
582 POP
583 SLOAD
584 DUP2
585 JUMP
586 JUMPDEST
587 CALLER
588 PUSH1 0x01
590 PUSH1 0x00
592 PUSH2 0x0100
595 EXP
596 DUP2
597 SLOAD
598 DUP2
599 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
620 MUL
621 NOT
622 AND
623 SWAP1
624 DUP4
625 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
646 AND
647 MUL
648 OR
649 SWAP1
650 SSTORE
651 POP
652 JUMP
653 JUMPDEST
654 PUSH1 0x01
656 PUSH1 0x00
658 SWAP1
659 SLOAD
660 SWAP1
661 PUSH2 0x0100
664 EXP
665 SWAP1
666 DIV
667 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
688 AND
689 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
710 AND
711 CALLER
712 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
733 AND
734 EQ
735 ISZERO
736 ISZERO
737 PUSH2 0x02e9
740 JUMPI
498 PUSH2 0x0100
501 EXP
502 DUP2
503 SLOAD
504 DUP2
505 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
526 MUL
527 NOT
528 AND
529 SWAP1
530 DUP4
531 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
552 AND
553 MUL
554 OR
555 SWAP1
556 SSTORE
557 POP
558 JUMP
559 JUMPDEST
560 PUSH1 0x01
562 PUSH1 0x00
564 SWAP1
565 SLOAD
566 SWAP1
567 PUSH2 0x0100
570 EXP
571 SWAP1
572 DIV
573 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
594 AND
595 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
616 AND
617 CALLER
618 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
639 AND
640 EQ
641 ISZERO
642 ISZERO
643 PUSH2 0x028b
646 JUMPI
647 PUSH1 0x00
649 DUP1
650 REVERT
651 JUMPDEST
652 CALLER
653 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
674 AND
675 PUSH2 0x08fc
678 ADDRESS
679 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
700 AND
701 BALANCE
702 SWAP1
703 DUP2
704 ISZERO
705 MUL
706 SWAP1
707 PUSH1 0x40
709 MLOAD
710 PUSH1 0x00
712 PUSH1 0x40
714 MLOAD
715 DUP1
716 DUP4
717 SUB
718 DUP2
719 DUP6
720 DUP9
721 DUP9
722 CALL
723 SWAP4
724 POP
725 POP
726 POP
727 POP
728 ISZERO
729 DUP1
730 ISZERO
731 PUSH2 0x02e8
734 JUMPI
735 RETURNDATASIZE
736 PUSH1 0x00
738 DUP1
739 RETURNDATACOPY
740 RETURNDATASIZE
741 PUSH1 0x00
743 DUP1
744 REVERT
745 JUMPDEST
746 CALLER
747 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
768 AND
769 PUSH2 0x08fc
772 ADDRESS
773 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
794 AND
795 BALANCE
796 SWAP1
797 DUP2
798 ISZERO
799 MUL
800 SWAP1
801 PUSH1 0x40
803 MLOAD
804 PUSH1 0x00
806 PUSH1 0x40
808 MLOAD
809 DUP1
810 DUP4
811 SUB
812 DUP2
813 DUP6
814 DUP9
815 DUP9
816 CALL
817 SWAP4
818 POP
819 POP
820 POP
821 POP
822 ISZERO
823 ISZERO
824 PUSH2 0x0340
827 JUMPI
828 PUSH1 0x00
830 DUP1
831 REVERT
832 JUMPDEST
833 JUMP
834 JUMPDEST
835 PUSH1 0x01
837 PUSH1 0x00
839 SWAP1
840 SLOAD
841 SWAP1
842 PUSH2 0x0100
845 EXP
846 SWAP1
847 DIV
848 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
869 AND
743 REVERT
744 JUMPDEST
745 POP
746 JUMP
747 JUMPDEST
748 PUSH1 0x01
750 PUSH1 0x00
752 SWAP1
753 SLOAD
754 SWAP1
755 PUSH2 0x0100
758 EXP
759 SWAP1
760 DIV
761 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
782 AND
783 DUP2
784 JUMP
785 JUMPDEST
786 PUSH1 0x02
788 SLOAD
789 CALLVALUE
790 GT
791 DUP1
792 ISZERO
793 PUSH2 0x0323
796 JUMPI
797 POP
798 PUSH1 0x03
800 SLOAD
801 CALLVALUE
802 LT
803 JUMPDEST
804 ISZERO
805 ISZERO
806 PUSH2 0x032e
809 JUMPI
810 PUSH1 0x00
812 DUP1
813 REVERT
814 JUMPDEST
815 CALLVALUE
816 PUSH1 0x00
818 DUP1
819 CALLER
820 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
841 AND
842 PUSH20 0xffffffffffffffffffffffffffffffffffffffff
863 AND
864 DUP2
865 MSTORE
866 PUSH1 0x20
868 ADD
869 SWAP1
870 DUP2
871 JUMP
872 STOP
871 MSTORE
872 PUSH1 0x20
874 ADD
875 PUSH1 0x00
877 SHA3
878 PUSH1 0x00
880 DUP3
881 DUP3
882 SLOAD
883 ADD
884 SWAP3
885 POP
886 POP
887 DUP2
888 SWAP1
889 SSTORE
890 POP
891 JUMP
892 STOP

File diff suppressed because one or more lines are too long

@ -7,7 +7,7 @@
"description": "In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `crowdfunding()`.",
"function": "withdrawfunds()",
"type": "Warning",
"address": 816,
"address": 722,
"debug": "<DEBUG-DATA>"
},
{
@ -15,7 +15,7 @@
"description": "A possible integer overflow exists in the function `invest()`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
"function": "invest()",
"type": "Warning",
"address": 483,
"address": 883,
"debug": "<DEBUG-DATA>"
}
]

@ -5,7 +5,7 @@
- Type: Warning
- Contract: Unknown
- Function name: `withdrawfunds()`
- PC address: 816
- PC address: 722
### Description
@ -18,7 +18,7 @@ There is a check on storage index 1. This storage slot can be written to by call
- Type: Warning
- Contract: Unknown
- Function name: `invest()`
- PC address: 483
- PC address: 883
### Description

@ -2,7 +2,7 @@
Type: Warning
Contract: Unknown
Function name: withdrawfunds()
PC address: 816
PC address: 722
In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.
There is a check on storage index 1. This storage slot can be written to by calling the function `crowdfunding()`.
@ -12,7 +12,7 @@ There is a check on storage index 1. This storage slot can be written to by call
Type: Warning
Contract: Unknown
Function name: invest()
PC address: 483
PC address: 883
A possible integer overflow exists in the function `invest()`.
The addition or multiplication may result in a value higher than the maximum representable integer.
--------------------

@ -0,0 +1,167 @@
0 PUSH1 0x80
2 PUSH1 0x40
4 MSTORE
5 PUSH1 0x04
7 CALLDATASIZE
8 LT
9 PUSH2 0x0041
12 JUMPI
13 PUSH1 0x00
15 CALLDATALOAD
16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000
46 SWAP1
47 DIV
48 PUSH4 0xffffffff
53 AND
54 DUP1
55 PUSH4 0x24ff38a2
60 EQ
61 PUSH2 0x0046
64 JUMPI
65 JUMPDEST
66 PUSH1 0x00
68 DUP1
69 REVERT
70 JUMPDEST
71 CALLVALUE
72 DUP1
73 ISZERO
74 PUSH2 0x0052
77 JUMPI
78 PUSH1 0x00
80 DUP1
81 REVERT
82 JUMPDEST
83 POP
84 PUSH2 0x005b
87 PUSH2 0x00d6
90 JUMP
91 JUMPDEST
92 PUSH1 0x40
94 MLOAD
95 DUP1
96 DUP1
97 PUSH1 0x20
99 ADD
100 DUP3
101 DUP2
102 SUB
103 DUP3
104 MSTORE
105 DUP4
106 DUP2
107 DUP2
108 MLOAD
109 DUP2
110 MSTORE
111 PUSH1 0x20
113 ADD
114 SWAP2
115 POP
116 DUP1
117 MLOAD
118 SWAP1
119 PUSH1 0x20
121 ADD
122 SWAP1
123 DUP1
124 DUP4
125 DUP4
126 PUSH1 0x00
128 JUMPDEST
129 DUP4
130 DUP2
131 LT
132 ISZERO
133 PUSH2 0x009b
136 JUMPI
137 DUP1
138 DUP3
139 ADD
140 MLOAD
141 DUP2
142 DUP5
143 ADD
144 MSTORE
145 PUSH1 0x20
147 DUP2
148 ADD
149 SWAP1
150 POP
151 PUSH2 0x0080
154 JUMP
155 JUMPDEST
156 POP
157 POP
158 POP
159 POP
160 SWAP1
161 POP
162 SWAP1
163 DUP2
164 ADD
165 SWAP1
166 PUSH1 0x1f
168 AND
169 DUP1
170 ISZERO
171 PUSH2 0x00c8
174 JUMPI
175 DUP1
176 DUP3
177 SUB
178 DUP1
179 MLOAD
180 PUSH1 0x01
182 DUP4
183 PUSH1 0x20
185 SUB
186 PUSH2 0x0100
189 EXP
190 SUB
191 NOT
192 AND
193 DUP2
194 MSTORE
195 PUSH1 0x20
197 ADD
198 SWAP2
199 POP
200 JUMPDEST
201 POP
202 SWAP3
203 POP
204 POP
205 POP
206 PUSH1 0x40
208 MLOAD
209 DUP1
210 SWAP2
211 SUB
212 SWAP1
213 RETURN
214 JUMPDEST
215 PUSH1 0x60
217 PUSH1 0x40
219 DUP1
220 MLOAD
221 SWAP1
222 DUP2
223 ADD
224 PUSH1 0x40
226 MSTORE
227 DUP1
228 PUSH1 0x17
230 DUP2
231 MSTORE
232 PUSH1 0x20
234 ADD
235 PUSH32 0xd0a5d18dd0bbd0bbd0bed18320d092d0bed180d0bbd0b4000000000000000000
268 DUP2
269 MSTORE
270 POP
271 SWAP1
272 POP
273 SWAP1
274 JUMP
275 STOP

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
{"error": null, "issues": [], "success": true}

@ -0,0 +1,3 @@
# Analysis results for None
The analysis was completed successfully. No issues were detected.

@ -0,0 +1 @@
The analysis was completed successfully. No issues were detected.

@ -4,7 +4,7 @@
"issues": [
{
"title": "Use of tx.origin",
"description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use tx.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin",
"description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin",
"function": "transferOwnership(address)",
"type": "Warning",
"address": 317,

@ -9,5 +9,5 @@
### Description
Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use tx.sender instead.
Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

@ -3,7 +3,7 @@ Type: Warning
Contract: Unknown
Function name: transferOwnership(address)
PC address: 317
Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use tx.sender instead.
Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin
--------------------

@ -5,33 +5,33 @@
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 649
- PC address: 567
### Description
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
## Integer Overflow
## Integer Underflow
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 725
- PC address: 649
### Description
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
## Integer Underflow
## Integer Overflow
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 567
- PC address: 725
### Description
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.

@ -2,26 +2,26 @@
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 649
PC address: 567
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
--------------------
==== Integer Overflow ====
==== Integer Underflow ====
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 725
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
PC address: 649
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
--------------------
==== Integer Underflow ====
==== Integer Overflow ====
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 567
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
PC address: 725
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
--------------------

@ -5,33 +5,33 @@
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 649
- PC address: 567
### Description
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
## Integer Overflow
## Integer Underflow
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 725
- PC address: 649
### Description
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
## Integer Underflow
## Integer Overflow
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 567
- PC address: 725
### Description
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.

@ -2,26 +2,26 @@
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 649
PC address: 567
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
--------------------
==== Integer Overflow ====
==== Integer Underflow ====
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 725
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
PC address: 649
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
--------------------
==== Integer Underflow ====
==== Integer Overflow ====
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 567
A possible integer underflow exists in the function `sendeth(address,uint256)`.
The subtraction may result in a value < 0.
PC address: 725
A possible integer overflow exists in the function `sendeth(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
--------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,41 @@
[tox]
envlist = py36
[testenv]
deps =
pytest
pytest-mock
whitelist_externals = mkdir
commands =
mkdir -p {toxinidir}/tests/testdata/outputs_current/
mkdir -p {toxinidir}/tests/testdata/outputs_current_laser_result/
py.test -v \
--junitxml={toxworkdir}/output/{envname}/junit.xml \
{posargs}
[testenv:py36]
basepython = python3.6
setenv =
COVERAGE_FILE = .coverage.{envname}
deps =
pytest
pytest-mock
pytest-cov
whitelist_externals = mkdir
commands =
mkdir -p {toxinidir}/tests/testdata/outputs_current/
mkdir -p {toxinidir}/tests/testdata/outputs_current_laser_result/
py.test -v \
--cov=mythril \
--cov-config=tox.ini \
--cov-report=xml:{toxworkdir}/output/{envname}/coverage.xml \
--cov-report=html:{toxworkdir}/output/{envname}/covhtml \
--junitxml={toxworkdir}/output/{envname}/junit.xml \
{posargs}
[coverage:report]
omit =
*__init__.py
/usr/*
*_test.py
setup.py
Loading…
Cancel
Save