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: jobs:
# Basic testing of a new commit to any branch. # Basic testing of a new commit to any branch.
test: test:
docker: <<: *defaults
- image: birdofpreyru/mythril:0.0.1
steps: steps:
- checkout: - checkout:
path: /home/mythril path: /home/mythril
@ -14,13 +15,23 @@ jobs:
# path param in checkout command, and this symlink compenstates for that. # path param in checkout command, and this symlink compenstates for that.
# - run: ln -s /root/project /home/mythril # - run: ln -s /root/project /home/mythril
- run: - restore-cache:
name: Installing mythril tools keys:
command: cd /home && ./install-mythril-tools.sh laser-ethereum - tox-env-{{ checksum "/home/mythril/setup.py" }}
- run: - run:
name: Install dependencies, in case any are missing in Docker image name: Install tox envs
command: pip3 install -r /home/mythril/requirements.txt 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: - run:
background: true background: true
@ -29,33 +40,55 @@ jobs:
- run: - run:
name: Unit-testing 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: - store_test_results:
path: /tmp/test-reports path: /home/mythril/.tox/output
- store_artifacts: - store_artifacts:
path: /tmp/test-reports path: /home/mythril/.tox/output
- run: - run:
name: Ensuring that setup script is functional 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: - run:
docker: name: Integration tests
- image: birdofpreyru/mythril:0.0.1 command: if [ -z "$CIRCLE_PR_NUMBER" ]; then ./run-integration-tests.sh; fi
working_directory: /home
pypi_release:
<<: *defaults
steps: steps:
- checkout: - checkout:
path: /home/mythril path: /home/mythril
- run: - run:
name: Verify Git tag vs. version name: Verify Git tag vs. version
command: cd /home/mythril && python3 setup.py verify command: python3 setup.py verify
working_directory: /home/mythril
- run: - run:
name: Build name: Build
command: cd /home/mythril && python3 setup.py sdist command: python3 setup.py sdist
working_directory: /home/mythril
- run: - run:
name: Deploy 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: workflows:
version: 2 version: 2
@ -65,7 +98,15 @@ workflows:
filters: filters:
tags: tags:
only: /.*/ only: /.*/
- deploy: - pypi_release:
filters:
branches:
ignore: /.*/
tags:
only: /v[0-9]+(\.[0-9]+)*/
requires:
- test
- dockerhub_release:
filters: filters:
branches: branches:
ignore: /.*/ 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_style = space
indent_size = 4 indent_size = 4
charset = utf-8 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 .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 *.asm
mythril.egg-info
build
dist
*.rst *.rst
*.lock *.lock
!Pipfile.lock
*.svg *.svg
laser*
lol* lol*
.idea* .idea*
coverage_html_report/ coverage_html_report/
.coverage
.pytest_cache
tests/testdata/outputs_current/ tests/testdata/outputs_current/
tests/testdata/outputs_current_laser_result/
tests/mythril_dir/signatures.json 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 \ 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 \ && add-apt-repository -y ppa:ethereum/ethereum \
&& apt-get update \ && apt-get update \
&& apt-get install -y solc \ && apt-get install -y \
&& apt-get install -y libssl-dev \ solc \
&& apt-get install -y python3-pip=9.0.1-2 python3-dev \ libssl-dev \
python3-dev \
pandoc \
git \
&& ln -s /usr/bin/python3 /usr/local/bin/python \ && ln -s /usr/bin/python3 /usr/local/bin/python \
# && pip3 install --upgrade pip \ && cd /opt/mythril \
&& apt-get install -y pandoc \
&& apt-get install -y git \
&& pip3 install -r requirements.txt \ && pip3 install -r requirements.txt \
&& python setup.py install && python setup.py install
CMD [] ENTRYPOINT ["/usr/local/bin/myth"]

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

@ -4,28 +4,16 @@ verify_ssl = true
name = "pypi" name = "pypi"
[packages] [packages]
requests = "*" "e1839a8" = {path = ".", editable = true}
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"
[dev-packages] [dev-packages]
pylint = "*" pylint = "*"
yapf = "*" yapf = "*"
pytest = "*" pytest = "*"
pytest-mock = "*"
pytest-cov = "*"
[requires] [requires]
python_version = "3.6"
[pipenv] [pipenv]
allow_prereleases = true 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 # 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) ![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"/> <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 ## Installation and setup
Build the [Docker](https://www.docker.com) image: Get it with [Docker](https://www.docker.com):
```bash ```bash
$ git clone https://github.com/ConsenSys/mythril/ $ docker pull mythril/myth
$ docker build mythril
``` ```
Install from Pypi: Install from Pypi:
@ -29,15 +30,16 @@ Documentation has moved to the [Wiki page](https://github.com/ConsenSys/mythril/
## Publications and Videos ## 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 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) - [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 [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.
- 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).
- 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 #!/bin/sh
python3 --version echo -n "Checking Python version... "
echo "Please make sure you are using python 3.6.x" 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 "Checking solc version..."
echo "Please make sure you are using solc 0.4.21" 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/ rm -rf ./tests/testdata/outputs_current/
mkdir -p ./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 mkdir -p /tmp/test-reports
pytest --junitxml=/tmp/test-reports/junit.xml 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/ rm -rf ./tests/testdata/outputs_current/
mkdir -p ./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 rm -rf coverage_html_report
coverage run -m unittest discover -p "*_test.py" py.test \
coverage html --cov=mythril \
open coverage_html_report/index.html --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 import re
from jinja2 import Environment, PackageLoader, select_autoescape from jinja2 import Environment, PackageLoader, select_autoescape
from mythril.laser.ethereum.svm import NodeFlags
import z3 import z3
default_opts = { default_opts = {
@ -95,15 +96,17 @@ def extract_nodes(statespace, color_map):
code_split = [] code_split = []
for instruction in instructions: for instruction in instructions:
if instruction['opcode'].startswith("PUSH"): if instruction['opcode'].startswith("PUSH"):
code_split.append("%d %s %s" % (instruction['address'], instruction['opcode'], instruction['argument'])) code_line = "%d %s %s" % (instruction['address'], instruction['opcode'], instruction['argument'])
# code_split.append("{instruction['address']} {instruction['opcode']} {instruction['argument']}") elif instruction['opcode'].startswith("JUMPDEST") and NodeFlags.FUNC_ENTRY in node.flags and instruction['address'] == node.start_addr:
elif instruction['opcode'].startswith("JUMPDEST"): code_line = node.function_name
code_split.append("%d %s %s" % (instruction['address'], instruction['opcode'], node.function_name))
else: 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_line = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code_line)
code_split[:6]) + "\n(click to expand +)" 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({ nodes.append({
'id': str(node_key), '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): 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'])) 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 graph_opts = default_opts
accounts = statespace.accounts accounts = statespace.accounts

@ -12,62 +12,71 @@ Check for invocations of delegatecall(msg.data) in the fallback function.
def execute(statespace): def execute(statespace):
"""
Executes analysis module for delegate call analysis module
:param statespace: Statespace to analyse
:return: Found issues
"""
issues = [] issues = []
for call in statespace.calls: 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 state = call.state
address = state.get_current_instruction()['address'] 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 if call.to.type == VarType.SYMBOLIC:
meminstart = get_variable(stack[-3]) 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 = \ issue.description = \
"This contract forwards its call data via DELEGATECALL in its fallback function. " \ "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): target = hex(call.to.val) if call.to.type == VarType.CONCRETE else str(call.to)
issue.description += ("DELEGATECALL target: " + hex(call.to.val)) issue.description += "DELEGATECALL target: {}".format(target)
else:
issue.description += "DELEGATECALL target: " + str(call.to)
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") 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 = \ issue.description = \
"This contract delegates execution to a contract address obtained from calldata. " "This contract delegates execution to a contract address obtained from calldata. "
else: else:
m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to)) m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to))
if (m): if m:
idx = m.group(1) idx = m.group(1)
func = statespace.find_storage_write(state.environment.active_account.address, idx) func = statespace.find_storage_write(state.environment.active_account.address, idx)
if (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 + "`. " 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: else:
logging.debug("[DELEGATECALL] No storage writes to index " + str(idx)) 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." issue.description += "Be aware that the called contract gets unrestricted access to this contract's state."
issues.append(issue) return [issue]
return issues

@ -11,7 +11,7 @@ Check for constraints on tx.origin (i.e., access to some functionality is restri
def execute(statespace): def execute(statespace):
logging.debug("Executing module: DEPRECIATED OPCODES") logging.debug("Executing module: DEPRECATED OPCODES")
issues = [] issues = []
@ -25,7 +25,7 @@ def execute(statespace):
if(instruction['opcode'] == "ORIGIN"): if(instruction['opcode'] == "ORIGIN"):
issue = Issue(node.contract_name, node.function_name, instruction['address'], "Use of tx.origin", "Warning", 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) issues.append(issue)

@ -3,7 +3,7 @@ from mythril.analysis import solver
from mythril.analysis.ops import * from mythril.analysis.ops import *
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from laser.ethereum.taint_analysis import TaintRunner from mythril.laser.ethereum.taint_analysis import TaintRunner
import re import re
import copy import copy
import logging 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): def _dependent_on_storage(expression):
""" Checks if expression is dependent on a storage symbol and returns the influencing storages""" """ 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))) return pattern.findall(str(simplify(expression)))

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

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

@ -1,14 +1,16 @@
import hashlib import hashlib
import json import json
import operator
from jinja2 import PackageLoader, Environment
class Issue: 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.title = title
self.contract = contract self.contract = contract
self.function = function self.function = function
self.pc = pc self.address = address
self.description = description self.description = description
self.type = _type self.type = _type
self.debug = debug self.debug = debug
@ -18,7 +20,7 @@ class Issue:
def as_dict(self): 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: if self.filename and self.lineno:
issue['filename'] = self.filename issue['filename'] = self.filename
@ -30,91 +32,43 @@ class Issue:
return issue return issue
def add_code_info(self, contract): def add_code_info(self, contract):
if self.pc: if self.address:
codeinfo = contract.get_source_info(self.pc) codeinfo = contract.get_source_info(self.address)
self.filename = codeinfo.filename self.filename = codeinfo.filename
self.code = codeinfo.code self.code = codeinfo.code
self.lineno = codeinfo.lineno self.lineno = codeinfo.lineno
class Report: class Report:
environment = Environment(loader=PackageLoader('mythril.analysis'), trim_blocks=True)
def __init__(self, verbose=False): def __init__(self, verbose=False):
self.issues = {} self.issues = {}
self.verbose = verbose self.verbose = verbose
pass 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): def append_issue(self, issue):
m = hashlib.md5() 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 self.issues[m.digest()] = issue
def as_text(self): def as_text(self):
text = "" name = self._file_name()
template = Report.environment.get_template('report_as_text.jinja2')
for key, issue in self.issues.items(): return template.render(filename=name, issues=self.sorted_issues(), verbose=self.verbose)
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
def as_json(self): def as_json(self):
issues = [] result = {'success': True, 'error': None, 'issues': self.sorted_issues()}
for key, issue in self.issues.items(): return json.dumps(result, sort_keys=True)
issues.append(issue.as_dict())
result = {'success': True, 'error': None, 'issues': issues}
return json.dumps(result)
def as_markdown(self): def as_markdown(self):
text = "" filename = self._file_name()
template = Report.environment.get_template('report_as_markdown.jinja2')
for key, issue in self.issues.items(): return template.render(filename=filename, issues=self.sorted_issues(), verbose=self.verbose)
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
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 mythril import ether
from laser.ethereum import svm from mythril.laser.ethereum import svm
import copy import copy
import logging import logging
from .ops import get_variable, SStore, Call, VarType 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 z3 import Z3Exception, simplify
from laser.ethereum.svm import NodeFlags from mythril.laser.ethereum.svm import NodeFlags
import re import re
colors = [ colors = [

@ -11,6 +11,7 @@ class Disassembly:
self.xrefs = [] self.xrefs = []
self.func_to_addr = {} self.func_to_addr = {}
self.addr_to_func = {} self.addr_to_func = {}
self.bytecode = code
try: try:
mythril_dir = os.environ['MYTHRIL_DIR'] 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.ethcontract import ETHContract
from mythril.ether.util import * from mythril.ether.util import *
from mythril.exceptions import NoContractFoundError from mythril.exceptions import NoContractFoundError
@ -36,7 +36,7 @@ class SolidityContract(ETHContract):
self.solidity_files = [] self.solidity_files = []
for filename in data['sourceList']: for filename in data['sourceList']:
with open(filename, 'r') as file: with open(filename, 'r', encoding='utf-8') as file:
code = file.read() code = file.read()
self.solidity_files.append(SolidityFile(filename, code)) 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') outputs.add_argument('--verbose-report', action='store_true', help='Include debugging information in report')
database = parser.add_argument_group('local contracts database') 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('-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 = parser.add_argument_group('utilities')
utilities.add_argument('--hash', help='calculate function signature hash', metavar='SIGNATURE') utilities.add_argument('--hash', help='calculate function signature hash', metavar='SIGNATURE')
@ -62,18 +63,18 @@ def main():
options = parser.add_argument_group('options') options = parser.add_argument_group('options')
options.add_argument('-m', '--modules', help='Comma-separated list of security analysis modules', metavar='MODULES') 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('--solc-args', help='Extra arguments for solc')
options.add_argument('--phrack', action='store_true', help='Phrack-style call graph') 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('--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('-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 = parser.add_argument_group('RPC options')
rpc.add_argument('-i', action='store_true', help='Preset: Infura Node service (Mainnet)') 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('--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('--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('--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 # Get config values
@ -87,7 +88,7 @@ def main():
# Parse cmdline args # 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): or args.storage or args.truffle or args.statespace_json):
parser.print_help() parser.print_help()
sys.exit() sys.exit()
@ -106,27 +107,31 @@ def main():
try: try:
# the mythril object should be our main interface # 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): #solc_args = None, dynld = None, max_recursion_depth = 12):
mythril = Mythril(solv=args.solv, dynld=args.dynld, mythril = Mythril(solv=args.solv, dynld=args.dynld,
solc_args=args.solc_args) solc_args=args.solc_args)
if args.leveldb: if args.address and not args.leveldb:
# Open LevelDB if specified
mythril.set_db_leveldb(args.leveldb)
elif (args.address or args.init_db) and not args.leveldb:
# Establish RPC/IPC connection if necessary # Establish RPC/IPC connection if necessary
if args.i: if args.i:
mythril.set_db_rpc_infura() mythril.set_api_rpc_infura()
elif args.rpc: 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: elif args.ipc:
mythril.set_db_ipc() mythril.set_api_ipc()
else: 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: if args.truffle:
try: 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.") "Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully.")
sys.exit() 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 # Load / compile input contracts
address = None address = None
@ -202,8 +198,8 @@ def main():
max_depth=args.max_depth) max_depth=args.max_depth)
outputs = { outputs = {
'json': report.as_json(), 'json': report.as_json(),
'text': report.as_text() or "The analysis was completed successfully. No issues were detected.", 'text': report.as_text(),
'markdown': report.as_markdown() or "The analysis was completed successfully. No issues were detected." 'markdown': report.as_markdown()
} }
print(outputs[args.outform]) 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.db = ETH_DB(path)
self.headBlockHeader = None self.headBlockHeader = None
self.headState = 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: for account in self._get_head_state().get_all_accounts():
self.all_contracts = [] if account.code is not None and (search_all or account.balance != 0):
self.active_contracts = [] code = _encode_hex(account.code)
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)
md5 = hashlib.md5() md5 = hashlib.md5()
md5.update(code.encode('UTF-8')) md5.update(code.encode('UTF-8'))
contract_hash = md5.digest() contract_hash = md5.digest()
contract = ETHContract(code, name=contract_hash.hex()) contract = ETHContract(code, name=contract_hash.hex())
self.all_contracts.append(contract) yield contract, _encode_hex(account.address), account.balance
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
def search(self, expression, callback_func): def search(self, expression, search_all, callback_func):
''' '''
searches through non-zero balance contracts searches through non-zero balance contracts
''' '''
contracts = self.get_active_contracts() for contract, address, balance in self.get_contracts(search_all):
for i in range(0, len(contracts)): if contract.matches_expression(expression):
if contracts[i].matches_expression(expression): callback_func(contract.name, contract, [address], [balance])
m = self.instance_lists[i]
callback_func(contracts[i].name, contracts[i], m.addresses, m.balances)
def eth_getBlockHeaderByNumber(self, number): def eth_getBlockHeaderByNumber(self, number):
''' '''

@ -121,10 +121,8 @@ class State():
def get_all_accounts(self): 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.iter_branch():
for addressHash, rlpdata in self.secureTrie.trie.to_dict().items():
if rlpdata != trie.BLANK_NODE: if rlpdata != trie.BLANK_NODE:
accounts.append(rlp.decode(rlpdata, Account, db=self.db, address=addressHash)) yield rlp.decode(rlpdata, Account, db=self.db, address=addressHash)
return accounts

@ -11,13 +11,15 @@ import os
import re import re
from ethereum import utils from ethereum import utils
import codecs
from solc.exceptions import SolcError from solc.exceptions import SolcError
import solc import solc
from configparser import ConfigParser
import platform
from copy import deepcopy from copy import deepcopy
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.ether import util from mythril.ether import util
from mythril.ether.contractstorage import get_persistent_storage
from mythril.ether.ethcontract import ETHContract from mythril.ether.ethcontract import ETHContract
from mythril.ether.soliditycontract import SolidityContract from mythril.ether.soliditycontract import SolidityContract
from mythril.rpc.client import EthJsonRpc from mythril.rpc.client import EthJsonRpc
@ -48,17 +50,17 @@ class Mythril(object):
Example: Example:
mythril = Mythril() mythril = Mythril()
mythril.set_db_rpc_infura() mythril.set_api_rpc_infura()
# (optional) other db adapters # (optional) other API adapters
mythril.set_db_rpc(args) mythril.set_api_rpc(args)
mythril.set_db_ipc() mythril.set_api_ipc()
mythril.set_db_rpc_localhost() mythril.set_api_rpc_localhost()
mythril.set_api_leveldb(path)
# (optional) other func # (optional) other func
mythril.analyze_truffle_project(args) mythril.analyze_truffle_project(args)
mythril.search_db(args) mythril.search_db(args)
mythril.init_db()
# load contract # load contract
mythril.load_from_bytecode(bytecode) mythril.load_from_bytecode(bytecode)
@ -90,10 +92,10 @@ class Mythril(object):
self.mythril_dir = self._init_mythril_dir() self.mythril_dir = self._init_mythril_dir()
self.signatures_file, self.sigs = self._init_signatures() self.signatures_file, self.sigs = self._init_signatures()
self.solc_binary = self._init_solc_binary(solv) self.solc_binary = self._init_solc_binary(solv)
self.leveldb_dir = self._init_config()
self.eth = None self.eth = None # ethereum API client
self.ethDb = None self.ethDb = None # ethereum LevelDB client
self.dbtype = None # track type of db (rpc,ipc,leveldb) used
self.contracts = [] # loaded contracts self.contracts = [] # loaded contracts
@ -137,6 +139,41 @@ class Mythril(object):
self.sigs = jsonsigs 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): def analyze_truffle_project(self, *args, **kwargs):
return analyze_truffle_project(*args, **kwargs) # just passthru for now return analyze_truffle_project(*args, **kwargs) # just passthru for now
@ -170,18 +207,16 @@ class Mythril(object):
solc_binary = 'solc' solc_binary = 'solc'
return solc_binary return solc_binary
def set_db_leveldb(self, leveldb): def set_api_leveldb(self, leveldb):
self.ethDb = EthLevelDB(leveldb) self.ethDb = EthLevelDB(leveldb)
self.eth = self.ethDb self.eth = self.ethDb
self.dbtype = "leveldb"
return self.eth return self.eth
def set_db_rpc_infura(self): def set_api_rpc_infura(self):
self.eth = EthJsonRpc('mainnet.infura.io', 443, True) self.eth = EthJsonRpc('mainnet.infura.io', 443, True)
logging.info("Using INFURA for RPC queries") 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': if rpc == 'ganache':
rpcconfig = ('localhost', 7545, False) rpcconfig = ('localhost', 7545, False)
else: else:
@ -197,50 +232,35 @@ class Mythril(object):
if rpcconfig: if rpcconfig:
self.eth = EthJsonRpc(rpcconfig[0], int(rpcconfig[1]), rpcconfig[2]) self.eth = EthJsonRpc(rpcconfig[0], int(rpcconfig[1]), rpcconfig[2])
self.dbtype = "rpc"
logging.info("Using RPC settings: %s" % str(rpcconfig)) logging.info("Using RPC settings: %s" % str(rpcconfig))
else: else:
raise CriticalError("Invalid RPC settings, check help for details.") raise CriticalError("Invalid RPC settings, check help for details.")
def set_db_ipc(self): def set_api_ipc(self):
try: try:
self.eth = EthIpc() self.eth = EthIpc()
self.dbtype = "ipc"
except Exception as e: except Exception as e:
raise CriticalError( 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( "IPC initialization failed. Please verify that your local Ethereum node is running, or use the -i flag to connect to INFURA. \n" + str(
e)) e))
def set_db_rpc_localhost(self): def set_api_rpc_localhost(self):
self.eth = EthJsonRpc('localhost', 8545) self.eth = EthJsonRpc('localhost', 8545)
self.dbtype = "rpc"
logging.info("Using default RPC settings: http://localhost:8545") 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): def search_callback(code_hash, code, addresses, balances):
print("Matched contract with code hash " + code_hash) print("Matched contract with code hash " + code_hash)
for i in range(0, len(addresses)): for i in range(0, len(addresses)):
print("Address: " + addresses[i] + ", balance: " + str(balances[i])) print("Address: " + addresses[i] + ", balance: " + str(balances[i]))
contract_storage, _ = get_persistent_storage(self.mythril_dir)
try: try:
if self.dbtype=="leveldb": self.ethDb.search(search, search_all, search_callback)
contract_storage.search(search, search_callback)
else:
self.ethDB.search(search, search_callback)
except SyntaxError: except SyntaxError:
raise CriticalError("Syntax error in search expression.") 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): def load_from_bytecode(self, code):
address = util.get_indexed_address(0) address = util.get_indexed_address(0)
self.contracts.append(ETHContract(code, name="MAIN")) self.contracts.append(ETHContract(code, name="MAIN"))
@ -283,6 +303,7 @@ class Mythril(object):
try: try:
signatures.add_signatures_from_file(file, self.sigs) signatures.add_signatures_from_file(file, self.sigs)
self._update_signatures(self.sigs)
contract = SolidityContract(file, contract_name, solc_args=self.solc_args) contract = SolidityContract(file, contract_name, solc_args=self.solc_args)
logging.info("Analyzing contract %s:%s" % (file, contract.name)) logging.info("Analyzing contract %s:%s" % (file, contract.name))
except FileNotFoundError: except FileNotFoundError:
@ -295,7 +316,6 @@ class Mythril(object):
self.contracts.append(contract) self.contracts.append(contract)
contracts.append(contract) contracts.append(contract)
self._update_signatures(self.sigs)
return address, contracts return address, contracts
def dump_statespace(self, contract, address=None, max_depth=12): def dump_statespace(self, contract, address=None, max_depth=12):

@ -10,7 +10,7 @@ def add_signatures_from_file(file, sigs={}):
code = f.read() 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: for f in funcs:

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

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

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

@ -7,8 +7,11 @@ TESTS_DIR = Path(__file__).parent
PROJECT_DIR = TESTS_DIR.parent PROJECT_DIR = TESTS_DIR.parent
TESTDATA = TESTS_DIR / "testdata" TESTDATA = TESTS_DIR / "testdata"
TESTDATA_INPUTS = TESTDATA / "inputs" TESTDATA_INPUTS = TESTDATA / "inputs"
TESTDATA_INPUTS_CONTRACTS = TESTDATA / "input_contracts"
TESTDATA_OUTPUTS_EXPECTED = TESTDATA / "outputs_expected" TESTDATA_OUTPUTS_EXPECTED = TESTDATA / "outputs_expected"
TESTDATA_OUTPUTS_CURRENT = TESTDATA / "outputs_current" 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" 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) read_json = json.loads(json_str)
for issue in read_json["issues"]: for issue in read_json["issues"]:
issue["debug"] = "<DEBUG-DATA>" issue["debug"] = "<DEBUG-DATA>"
return json.dumps(read_json, indent=4) return json.dumps(read_json, sort_keys=True)
def _generate_report(input_file): def _generate_report(input_file):
@ -44,18 +44,41 @@ def reports():
return results return results
def _assert_empty(changed_files): def _assert_empty(changed_files, postfix):
""" Asserts there are no changed files and otherwise builds error message""" """ Asserts there are no changed files and otherwise builds error message"""
message = "" message = ""
for input_file in changed_files: for input_file in changed_files:
output_expected = (TESTDATA_OUTPUTS_EXPECTED / (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 + ".json")).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)) 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)) message += "Found differing file for input: {} \n Difference: \n {} \n".format(str(input_file), str(difference))
assert message == "", message 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): def _get_changed_files(postfix, report_builder, reports):
""" """
@ -74,13 +97,32 @@ def _get_changed_files(postfix, report_builder, reports):
yield input_file 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): 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): 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): 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.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph from mythril.analysis.callgraph import generate_graph
from mythril.ether.ethcontract import ETHContract 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): 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]; 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. 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 ## Unchecked CALL return value
- 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
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xe11f493e` - Function name: `_function_0x5a6814ec`
- PC address: 858 - PC address: 661
### 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
### Description ### 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 ## Message call to external contract
- Type: Warning - Type: Warning
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xe1d10f79` - Function name: `_function_0xd24b08cc`
- PC address: 912 - PC address: 779
### Description ### 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 ## Transaction order dependence
@ -70,23 +48,23 @@ A possible transaction order independence vulnerability exists in function _func
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0x5a6814ec` - Function name: `_function_0xd24b08cc`
- PC address: 661 - PC address: 779
### Description ### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws. 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 - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xd24b08cc` - Function name: `_function_0xe11f493e`
- PC address: 779 - PC address: 858
### Description ### 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 ## 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. 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 ## Unchecked CALL return value
- Type: Informational - 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. 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 ==== ==== Unchecked CALL return value ====
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 ====
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0xe11f493e Function name: _function_0x5a6814ec
PC address: 858 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. 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 ==== ==== Message call to external contract ====
Type: Warning Type: Warning
Contract: Unknown Contract: Unknown
Function name: _function_0xe1d10f79 Function name: _function_0xd24b08cc
PC address: 912 PC address: 779
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 ==== ==== Transaction order dependence ====
@ -49,17 +33,17 @@ A possible transaction order independence vulnerability exists in function _func
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0x5a6814ec Function name: _function_0xd24b08cc
PC address: 661 PC address: 779
The return value of an external call is not checked. Note that execution continue even if the called contract throws. 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 Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0xd24b08cc Function name: _function_0xe11f493e
PC address: 779 PC address: 858
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 ==== ==== 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. 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 ==== ==== Unchecked CALL return value ====
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown

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

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

@ -2,7 +2,7 @@
Type: Warning Type: Warning
Contract: Unknown Contract: Unknown
Function name: withdrawfunds() Function name: withdrawfunds()
PC address: 816 PC address: 722
In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender. 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()`. 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 Type: Warning
Contract: Unknown Contract: Unknown
Function name: invest() Function name: invest()
PC address: 483 PC address: 883
A possible integer overflow exists in the function `invest()`. A possible integer overflow exists in the function `invest()`.
The addition or multiplication may result in a value higher than the maximum representable integer. 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": [ "issues": [
{ {
"title": "Use of tx.origin", "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)", "function": "transferOwnership(address)",
"type": "Warning", "type": "Warning",
"address": 317, "address": 317,

@ -9,5 +9,5 @@
### Description ### 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 See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

@ -3,7 +3,7 @@ Type: Warning
Contract: Unknown Contract: Unknown
Function name: transferOwnership(address) Function name: transferOwnership(address)
PC address: 317 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 See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin
-------------------- --------------------

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

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

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

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