Merge branch 'dev' into top-level-yul-identifier

pull/1188/head
Josselin Feist 2 years ago
commit 8509db796e
  1. 14
      .github/workflows/ci.yml
  2. 23
      .github/workflows/pip-audit.yml
  3. 11
      Dockerfile
  4. 14
      README.md
  5. 2
      scripts/ci_test_kspec.sh
  6. 4
      scripts/ci_test_simil.sh
  7. 2
      scripts/ci_test_truffle.sh
  8. 8
      setup.py
  9. 43
      slither/__main__.py
  10. 4
      slither/core/cfg/node.py
  11. 2
      slither/core/children/child_node.py
  12. 23
      slither/core/declarations/contract.py
  13. 11
      slither/core/declarations/enum.py
  14. 2
      slither/core/declarations/solidity_variables.py
  15. 9
      slither/core/slither_core.py
  16. 3
      slither/core/solidity_types/type_information.py
  17. 6
      slither/detectors/all_detectors.py
  18. 4
      slither/detectors/assembly/shift_parameter_mixup.py
  19. 2
      slither/detectors/attributes/incorrect_solc.py
  20. 0
      slither/detectors/erc/erc20/__init__.py
  21. 95
      slither/detectors/erc/erc20/arbitrary_send_erc20.py
  22. 45
      slither/detectors/erc/erc20/arbitrary_send_erc20_no_permit.py
  23. 53
      slither/detectors/erc/erc20/arbitrary_send_erc20_permit.py
  24. 0
      slither/detectors/erc/erc20/incorrect_erc20_interface.py
  25. 6
      slither/detectors/functions/arbitrary_send_eth.py
  26. 2
      slither/detectors/naming_convention/naming_convention.py
  27. 12
      slither/detectors/statements/too_many_digits.py
  28. 2
      slither/detectors/statements/unprotected_upgradeable.py
  29. 4
      slither/detectors/variables/similar_variables.py
  30. 2
      slither/formatters/attributes/constant_pragma.py
  31. 3
      slither/formatters/attributes/incorrect_solc.py
  32. 6
      slither/formatters/naming_convention/naming_convention.py
  33. 2
      slither/printers/summary/variable_order.py
  34. 2
      slither/slither.py
  35. 24
      slither/slithir/convert.py
  36. 2
      slither/solc_parsing/expressions/expression_parsing.py
  37. 4
      slither/solc_parsing/slither_compilation_unit_solc.py
  38. 6
      slither/solc_parsing/solidity_types/type_parsing.py
  39. 4
      slither/solc_parsing/yul/parse_yul.py
  40. 1
      slither/tools/erc_conformance/erc/ercs.py
  41. 4
      slither/tools/kspec_coverage/analysis.py
  42. 4
      slither/tools/read_storage/README.md
  43. 6
      slither/tools/upgradeability/checks/initialization.py
  44. 8
      slither/utils/colors.py
  45. 49
      slither/utils/erc.py
  46. 2
      slither/utils/integer_conversion.py
  47. 2
      slither/utils/output.py
  48. 16
      slither/visitors/slithir/expression_to_slithir.py
  49. BIN
      tests/ast-parsing/compile/assembly-all.sol-0.8.13-compact.zip
  50. BIN
      tests/ast-parsing/compile/assembly-all.sol-0.8.14-compact.zip
  51. BIN
      tests/ast-parsing/compile/assembly-all.sol-0.8.15-compact.zip
  52. BIN
      tests/ast-parsing/compile/assignment-0.4.7.sol-0.8.13-compact.zip
  53. BIN
      tests/ast-parsing/compile/assignment-0.4.7.sol-0.8.14-compact.zip
  54. BIN
      tests/ast-parsing/compile/assignment-0.4.7.sol-0.8.15-compact.zip
  55. BIN
      tests/ast-parsing/compile/break-all.sol-0.8.13-compact.zip
  56. BIN
      tests/ast-parsing/compile/break-all.sol-0.8.14-compact.zip
  57. BIN
      tests/ast-parsing/compile/break-all.sol-0.8.15-compact.zip
  58. BIN
      tests/ast-parsing/compile/call_to_variable-all.sol-0.8.13-compact.zip
  59. BIN
      tests/ast-parsing/compile/call_to_variable-all.sol-0.8.14-compact.zip
  60. BIN
      tests/ast-parsing/compile/call_to_variable-all.sol-0.8.15-compact.zip
  61. BIN
      tests/ast-parsing/compile/comment-all.sol-0.8.13-compact.zip
  62. BIN
      tests/ast-parsing/compile/comment-all.sol-0.8.14-compact.zip
  63. BIN
      tests/ast-parsing/compile/comment-all.sol-0.8.15-compact.zip
  64. BIN
      tests/ast-parsing/compile/complex_imports/import_aliases/test.sol-0.8.13-compact.zip
  65. BIN
      tests/ast-parsing/compile/complex_imports/import_aliases/test.sol-0.8.14-compact.zip
  66. BIN
      tests/ast-parsing/compile/complex_imports/import_aliases/test.sol-0.8.15-compact.zip
  67. BIN
      tests/ast-parsing/compile/conditional-all.sol-0.8.13-compact.zip
  68. BIN
      tests/ast-parsing/compile/conditional-all.sol-0.8.14-compact.zip
  69. BIN
      tests/ast-parsing/compile/conditional-all.sol-0.8.15-compact.zip
  70. BIN
      tests/ast-parsing/compile/continue-all.sol-0.8.13-compact.zip
  71. BIN
      tests/ast-parsing/compile/continue-all.sol-0.8.14-compact.zip
  72. BIN
      tests/ast-parsing/compile/continue-all.sol-0.8.15-compact.zip
  73. BIN
      tests/ast-parsing/compile/contract-0.6.0.sol-0.8.13-compact.zip
  74. BIN
      tests/ast-parsing/compile/contract-0.6.0.sol-0.8.14-compact.zip
  75. BIN
      tests/ast-parsing/compile/contract-0.6.0.sol-0.8.15-compact.zip
  76. BIN
      tests/ast-parsing/compile/custom_error-0.4.0.sol-0.8.13-compact.zip
  77. BIN
      tests/ast-parsing/compile/custom_error-0.4.0.sol-0.8.14-compact.zip
  78. BIN
      tests/ast-parsing/compile/custom_error-0.4.0.sol-0.8.15-compact.zip
  79. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.10-compact.zip
  80. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.11-compact.zip
  81. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.12-compact.zip
  82. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.4-compact.zip
  83. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.5-compact.zip
  84. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.6-compact.zip
  85. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.7-compact.zip
  86. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.8-compact.zip
  87. BIN
      tests/ast-parsing/compile/custom_error_with_state_variable.sol-0.8.9-compact.zip
  88. BIN
      tests/ast-parsing/compile/dowhile-0.4.5.sol-0.8.13-compact.zip
  89. BIN
      tests/ast-parsing/compile/dowhile-0.4.5.sol-0.8.14-compact.zip
  90. BIN
      tests/ast-parsing/compile/dowhile-0.4.5.sol-0.8.15-compact.zip
  91. BIN
      tests/ast-parsing/compile/emit-0.5.0.sol-0.8.13-compact.zip
  92. BIN
      tests/ast-parsing/compile/emit-0.5.0.sol-0.8.14-compact.zip
  93. BIN
      tests/ast-parsing/compile/emit-0.5.0.sol-0.8.15-compact.zip
  94. BIN
      tests/ast-parsing/compile/enum-0.8.0.sol-0.8.13-compact.zip
  95. BIN
      tests/ast-parsing/compile/enum-0.8.0.sol-0.8.14-compact.zip
  96. BIN
      tests/ast-parsing/compile/enum-0.8.0.sol-0.8.15-compact.zip
  97. BIN
      tests/ast-parsing/compile/event-all.sol-0.8.13-compact.zip
  98. BIN
      tests/ast-parsing/compile/event-all.sol-0.8.14-compact.zip
  99. BIN
      tests/ast-parsing/compile/event-all.sol-0.8.15-compact.zip
  100. BIN
      tests/ast-parsing/compile/for-all.sol-0.8.13-compact.zip
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,8 +3,7 @@ name: CI
defaults:
run:
# To load bashrc
shell: bash -ieo pipefail {0}
shell: bash
on:
push:
@ -52,16 +51,10 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Set up shell
if: runner.os == 'Windows'
run: |
echo 'C:\msys64\mingw64\bin' >> "$GITHUB_PATH"
echo 'C:\msys64\usr\bin' >> "$GITHUB_PATH"
- name: Set up Python 3.6
- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: 3.6
python-version: 3.8
- name: Install dependencies
run: |
@ -87,6 +80,7 @@ jobs:
- name: Run Tests
env:
PYTHONUTF8: 1
TEST_TYPE: ${{ matrix.type }}
GITHUB_ETHERSCAN: ${{ secrets.GITHUB_ETHERSCAN }}
run: |

@ -11,18 +11,25 @@ on:
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Python 3.10
uses: actions/setup-python@v3
uses: actions/checkout@v3
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install pip-audit
- name: Install Slither
run: |
python -m venv /tmp/pip-audit-env
source /tmp/pip-audit-env/bin/activate
python -m pip install --upgrade pip
python -m pip install pip-audit
- name: Run pip-audit
run: |
python -m pip install .
pip-audit --desc -v
- name: Run pip-audit
uses: trailofbits/gh-action-pip-audit@v0.0.4
with:
virtual-environment: /tmp/pip-audit-env

@ -1,4 +1,4 @@
FROM ubuntu:bionic
FROM ubuntu:focal
LABEL name=slither
LABEL src="https://github.com/trailofbits/slither"
@ -6,11 +6,12 @@ LABEL creator=trailofbits
LABEL dockerfile_maintenance=trailofbits
LABEL desc="Static Analyzer for Solidity"
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y git python3 python3-setuptools wget software-properties-common
RUN export DEBIAN_FRONTEND=noninteractive \
&& apt-get update \
&& apt-get upgrade -yq \
&& apt-get install -yq gcc git python3 python3-dev python3-setuptools wget software-properties-common
RUN wget https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux \
RUN wget -q https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux \
&& chmod +x solc-static-linux \
&& mv solc-static-linux /usr/bin/solc

@ -40,9 +40,12 @@ Run Slither on a single file:
slither tests/uninitialized.sol
```
For GitHub action integration, see [slither-action](https://github.com/marketplace/actions/slither-action). For additional configuration, see the [usage](https://github.com/trailofbits/slither/wiki/Usage) documentation.
### Integration
- For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action).
- To generate a Markdown report, use `slither [target] --checklist`.
- To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`)
Use [solc-select](https://github.com/crytic/solc-select) if your contracts require older versions of solc.
Use [solc-select](https://github.com/crytic/solc-select) if your contracts require older versions of solc. For additional configuration, see the [usage](https://github.com/trailofbits/slither/wiki/Usage) documentation.
### Detectors
@ -51,7 +54,7 @@ Num | Detector | What it Detects | Impact | Confidence
--- | --- | --- | --- | ---
1 | `abiencoderv2-array` | [Storage abiencoderv2 array](https://github.com/crytic/slither/wiki/Detector-Documentation#storage-abiencoderv2-array) | High | High
2 | `array-by-reference` | [Modifying storage array by value](https://github.com/crytic/slither/wiki/Detector-Documentation#modifying-storage-array-by-value) | High | High
3 | `incorrect-shift` | [The order of parameters in a shift instruction is incorrect.](https://github.com/crytic/slither/wiki/Detector-Documentation#shift-parameter-mixup) | High | High
3 | `incorrect-shift` | [The order of parameters in a shift instruction is incorrect.](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-shift-in-assembly) | High | High
4 | `multiple-constructors` | [Multiple constructor schemes](https://github.com/crytic/slither/wiki/Detector-Documentation#multiple-constructor-schemes) | High | High
5 | `name-reused` | [Contract's name reused](https://github.com/crytic/slither/wiki/Detector-Documentation#name-reused) | High | High
6 | `public-mappings-nested` | [Public mappings with nested variables](https://github.com/crytic/slither/wiki/Detector-Documentation#public-mappings-with-nested-variables) | High | High
@ -121,7 +124,7 @@ Num | Detector | What it Detects | Impact | Confidence
70 | `costly-loop` | [Costly operations in a loop](https://github.com/crytic/slither/wiki/Detector-Documentation#costly-operations-inside-a-loop) | Informational | Medium
71 | `dead-code` | [Functions that are not used](https://github.com/crytic/slither/wiki/Detector-Documentation#dead-code) | Informational | Medium
72 | `reentrancy-unlimited-gas` | [Reentrancy vulnerabilities through send and transfer](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-4) | Informational | Medium
73 | `similar-names` | [Variable names are too similar](https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-are-too-similar) | Informational | Medium
73 | `similar-names` | [Variable names are too similar](https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-too-similar) | Informational | Medium
74 | `too-many-digits` | [Conformance to numeric notation best practices](https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits) | Informational | Medium
75 | `constable-states` | [State variables that could be declared constant](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant) | Optimization | High
76 | `external-function` | [Public function that could be declared external](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external) | Optimization | High
@ -225,5 +228,8 @@ Title | Usage | Authors | Venue
[Smart Contract Repair](https://arxiv.org/pdf/1912.05823.pdf) | Rely on Slither’s vulnerabilities detectors | Xiao Liang Yu, Omar Al-Bataineh, David Lo, Abhik Roychoudhury | TOSEM 20
[Demystifying Loops in Smart Contracts](https://www.microsoft.com/en-us/research/uploads/prod/2020/08/loops_solidity__camera_ready-5f3fec3f15c69.pdf) | Leverage data dependency through Slither | Ben Mariano, Yanju Chen, Yu Feng, Shuvendu Lahiri, Isil Dillig | ASE 20
[Trace-Based Dynamic Gas Estimation of Loops in Smart Contracts](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9268144) | Use Slither’s CFG to detect loops | Chunmiao Li, Shijie Nie, Yang Cao, Yijun Yu, Zhenjiang Hu | IEEE Open J. Comput. Soc. 1 (2020)
[SAILFISH: Vetting Smart Contract State-Inconsistency Bugs in Seconds](https://arxiv.org/pdf/2104.08638.pdf) | Rely on SlithIR to build a *storage dependency graph* | Priyanka Bose, Dipanjan Das, Yanju Chen, Yu Feng, Christopher Kruegel, and Giovanni Vigna | S&P 22
[SolType: Refinement Types for Arithmetic Overflow in Solidity](https://arxiv.org/abs/2110.00677) | Use Slither as frontend to build refinement type system | Bryan Tan, Benjamin Mariano, Shuvendu K. Lahiri, Isil Dillig, Yu Feng | POPL 22
[Do Not Rug on Me: Leveraging Machine Learning Techniques for Automated Scam Detection](https://www.mdpi.com/2227-7390/10/6/949) | Use Slither to extract tokens' features (mintable, pausable, ..) | Mazorra, Bruno, Victor Adan, and Vanesa Daza | Mathematics 10.6 (2022)
If you are using Slither on an academic work, consider applying to the [Crytic $10k Research Prize](https://blog.trailofbits.com/2019/11/13/announcing-the-crytic-10k-research-prize/).

@ -7,7 +7,7 @@ slither-check-kspec "$DIR_TESTS/safeAdd/safeAdd.sol" "$DIR_TESTS/safeAdd/spec.md
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability 1 failed"
echo "slither-check-kspec 1 failed"
cat test_1.txt
echo ""
cat "$DIR_TESTS/test_1.txt"

@ -2,8 +2,8 @@
### Install requisites
pip3.6 install pybind11
pip3.6 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip
pip3 install pybind11
pip3 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip
### Test slither-simil

@ -15,7 +15,7 @@ npm install -g truffle
truffle unbox metacoin
slither .
if [ $? -eq 9 ]
if [ $? -eq 6 ]
then
exit 0
fi

@ -8,16 +8,16 @@ setup(
description="Slither is a Solidity static analysis framework written in Python 3.",
url="https://github.com/crytic/slither",
author="Trail of Bits",
version="0.8.2",
version="0.8.3",
packages=find_packages(),
python_requires=">=3.6",
install_requires=[
"prettytable>=0.7.2",
"pysha3>=1.0.2",
"crytic-compile>=0.2.3",
# "crytic-compile",
# "crytic-compile>=0.2.3",
"crytic-compile",
],
# dependency_links=["git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile"],
dependency_links=["git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile"],
license="AGPL-3.0",
long_description=long_description,
entry_points={

@ -299,6 +299,9 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
group_detector = parser.add_argument_group("Detectors")
group_printer = parser.add_argument_group("Printers")
group_checklist = parser.add_argument_group(
"Checklist (consider using https://github.com/crytic/slither-action)"
)
group_misc = parser.add_argument_group("Additional options")
group_detector.add_argument(
@ -312,7 +315,7 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
group_printer.add_argument(
"--print",
help="Comma-separated list fo contract information printers, "
help="Comma-separated list of contract information printers, "
f"available printers: {', '.join(d.ARGUMENT for d in printer_classes)}",
action="store",
dest="printers_to_run",
@ -392,6 +395,28 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
default=defaults_flag_in_config["show_ignored_findings"],
)
group_checklist.add_argument(
"--checklist",
help="Generate a markdown page with the detector results",
action="store_true",
default=False,
)
group_checklist.add_argument(
"--checklist-limit",
help="Limite the number of results per detector in the markdown file",
action="store",
default="",
)
group_checklist.add_argument(
"--markdown-root",
type=check_and_sanitize_markdown_root,
help="URL for markdown generation",
action="store",
default="",
)
group_misc.add_argument(
"--json",
help='Export the results as a JSON file ("--json -" to export to stdout)',
@ -429,14 +454,6 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
default=defaults_flag_in_config["zip_type"],
)
group_misc.add_argument(
"--markdown-root",
type=check_and_sanitize_markdown_root,
help="URL for markdown generation",
action="store",
default="",
)
group_misc.add_argument(
"--disable-color",
help="Disable output colorization",
@ -487,12 +504,6 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
parser.add_argument("--markdown", help=argparse.SUPPRESS, action=OutputMarkdown, default=False)
group_misc.add_argument(
"--checklist", help=argparse.SUPPRESS, action="store_true", default=False
)
group_misc.add_argument("--checklist-limit", help=argparse.SUPPRESS, action="store", default="")
parser.add_argument(
"--wiki-detectors", help=argparse.SUPPRESS, action=OutputWiki, default=False
)
@ -648,7 +659,7 @@ def main_impl(all_detector_classes, all_printer_classes):
cp.enable()
# Set colorization option
set_colorization_enabled(not args.disable_color)
set_colorization_enabled(False if args.disable_color else sys.stdout.isatty())
# Define some variables for potential JSON output
json_results = {}

@ -39,12 +39,11 @@ from slither.slithir.variables import (
TupleVariable,
)
from slither.all_exceptions import SlitherException
from slither.core.declarations import Contract
from slither.core.declarations import Contract, Function
from slither.core.expressions.expression import Expression
if TYPE_CHECKING:
from slither.core.declarations import Function
from slither.slithir.variables.variable import SlithIRVariable
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.utils.type_helpers import (
@ -917,6 +916,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
)
elif isinstance(ir, LibraryCall):
assert isinstance(ir.destination, Contract)
assert isinstance(ir.function, Function)
self._high_level_calls.append((ir.destination, ir.function))
self._library_calls.append((ir.destination, ir.function))

@ -28,4 +28,4 @@ class ChildNode:
@property
def compilation_unit(self) -> "SlitherCompilationUnit":
return self.contract.compilation_unit
return self.node.compilation_unit

@ -21,6 +21,8 @@ from slither.utils.erc import (
ERC777_signatures,
ERC1155_signatures,
ERC2612_signatures,
ERC1363_signatures,
ERC4524_signatures,
ERC4626_signatures,
)
from slither.utils.tests_pattern import is_test_contract
@ -903,6 +905,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
("ERC721", self.is_erc721),
("ERC777", self.is_erc777),
("ERC2612", self.is_erc2612),
("ERC1363", self.is_erc1363),
("ERC4626", self.is_erc4626),
]
@ -998,6 +1001,26 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
full_names = self.functions_signatures
return all(s in full_names for s in ERC2612_signatures)
def is_erc1363(self) -> bool:
"""
Check if the contract is an erc1363
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc1363
"""
full_names = self.functions_signatures
return all(s in full_names for s in ERC1363_signatures)
def is_erc4524(self) -> bool:
"""
Check if the contract is an erc4524
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc4524
"""
full_names = self.functions_signatures
return all(s in full_names for s in ERC4524_signatures)
@property
def is_token(self) -> bool:
"""

@ -9,6 +9,9 @@ class Enum(SourceMapping):
self._name = name
self._canonical_name = canonical_name
self._values = values
self._min = 0
# The max value of an Enum is the index of the last element
self._max = len(values) - 1
@property
def canonical_name(self) -> str:
@ -22,5 +25,13 @@ class Enum(SourceMapping):
def values(self) -> List[str]:
return self._values
@property
def min(self) -> int:
return self._min
@property
def max(self) -> int:
return self._max
def __str__(self):
return self.name

@ -104,7 +104,7 @@ class SolidityVariable(Context):
# dev function, will be removed once the code is stable
def _check_name(self, name: str): # pylint: disable=no-self-use
assert name in SOLIDITY_VARIABLES or name.endswith("_slot") or name.endswith("_offset")
assert name in SOLIDITY_VARIABLES or name.endswith(("_slot", "_offset"))
@property
def state_variable(self):

@ -4,6 +4,7 @@
import json
import logging
import os
import pathlib
import posixpath
import re
from typing import Optional, Dict, List, Set, Union
@ -218,8 +219,12 @@ class SlitherCore(Context):
for elem in r["elements"]
if "source_mapping" in elem
]
source_mapping_elements = map(
lambda x: posixpath.normpath(x) if x else x, source_mapping_elements
# Use POSIX-style paths so that filter_paths works across different
# OSes. Convert to a list so elements don't get consumed and are lost
# while evaluating the first pattern
source_mapping_elements = list(
map(lambda x: pathlib.Path(x).resolve().as_posix() if x else x, source_mapping_elements)
)
matching = False

@ -13,8 +13,9 @@ class TypeInformation(Type):
def __init__(self, c):
# pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum
assert isinstance(c, (Contract, ElementaryType))
assert isinstance(c, (Contract, ElementaryType, Enum))
super().__init__()
self._type = c

@ -6,7 +6,9 @@ from .variables.uninitialized_local_variables import UninitializedLocalVars
from .attributes.constant_pragma import ConstantPragma
from .attributes.incorrect_solc import IncorrectSolc
from .attributes.locked_ether import LockedEther
from .functions.arbitrary_send import ArbitrarySend
from .functions.arbitrary_send_eth import ArbitrarySendEth
from .erc.erc20.arbitrary_send_erc20_no_permit import ArbitrarySendErc20NoPermit
from .erc.erc20.arbitrary_send_erc20_permit import ArbitrarySendErc20Permit
from .functions.suicidal import Suicidal
# from .functions.complex_function import ComplexFunction
@ -34,7 +36,7 @@ from .shadowing.builtin_symbols import BuiltinSymbolShadowing
from .operations.block_timestamp import Timestamp
from .statements.calls_in_loop import MultipleCallsInLoop
from .statements.incorrect_strict_equality import IncorrectStrictEquality
from .erc.incorrect_erc20_interface import IncorrectERC20InterfaceDetection
from .erc.erc20.incorrect_erc20_interface import IncorrectERC20InterfaceDetection
from .erc.incorrect_erc721_interface import IncorrectERC721InterfaceDetection
from .erc.unindexed_event_parameters import UnindexedERC20EventParameters
from .statements.deprecated_calls import DeprecatedStandards

@ -13,7 +13,9 @@ class ShiftParameterMixup(AbstractDetector):
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#shift-parameter-mixup"
WIKI = (
"https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-shift-in-assembly"
)
WIKI_TITLE = "Incorrect shift in assembly."
WIKI_DESCRIPTION = "Detect if the values in a shift operation are reversed"

@ -14,7 +14,7 @@ from slither.formatters.attributes.incorrect_solc import custom_format
# 4: version number
# pylint: disable=anomalous-backslash-in-string
PATTERN = re.compile("(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
PATTERN = re.compile(r"(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
class IncorrectSolc(AbstractDetector):

@ -0,0 +1,95 @@
from typing import List
from slither.core.cfg.node import Node
from slither.core.declarations.solidity_variables import SolidityVariable
from slither.slithir.operations import HighLevelCall, LibraryCall
from slither.core.declarations import Contract, Function, SolidityVariableComposed
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.compilation_unit import SlitherCompilationUnit
class ArbitrarySendErc20:
"""Detects instances where ERC20 can be sent from an arbitrary from address."""
def __init__(self, compilation_unit: SlitherCompilationUnit):
self._compilation_unit = compilation_unit
self._no_permit_results: List[Node] = []
self._permit_results: List[Node] = []
@property
def compilation_unit(self) -> SlitherCompilationUnit:
return self._compilation_unit
@property
def no_permit_results(self) -> List[Node]:
return self._no_permit_results
@property
def permit_results(self) -> List[Node]:
return self._permit_results
def _detect_arbitrary_from(self, contract: Contract):
for f in contract.functions:
all_high_level_calls = [
f_called[1].solidity_signature
for f_called in f.high_level_calls
if isinstance(f_called[1], Function)
]
all_library_calls = [f_called[1].solidity_signature for f_called in f.library_calls]
if (
"transferFrom(address,address,uint256)" in all_high_level_calls
or "safeTransferFrom(address,address,address,uint256)" in all_library_calls
):
if (
"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"
in all_high_level_calls
):
ArbitrarySendErc20._arbitrary_from(f.nodes, self._permit_results)
else:
ArbitrarySendErc20._arbitrary_from(f.nodes, self._no_permit_results)
@staticmethod
def _arbitrary_from(nodes: List[Node], results: List[Node]):
"""Finds instances of (safe)transferFrom that do not use msg.sender or address(this) as from parameter."""
for node in nodes:
for ir in node.irs:
if (
isinstance(ir, HighLevelCall)
and isinstance(ir.function, Function)
and ir.function.solidity_signature == "transferFrom(address,address,uint256)"
and not (
is_dependent(
ir.arguments[0],
SolidityVariableComposed("msg.sender"),
node.function.contract,
)
or is_dependent(
ir.arguments[0],
SolidityVariable("this"),
node.function.contract,
)
)
):
results.append(ir.node)
elif (
isinstance(ir, LibraryCall)
and ir.function.solidity_signature
== "safeTransferFrom(address,address,address,uint256)"
and not (
is_dependent(
ir.arguments[1],
SolidityVariableComposed("msg.sender"),
node.function.contract,
)
or is_dependent(
ir.arguments[1],
SolidityVariable("this"),
node.function.contract,
)
)
):
results.append(ir.node)
def detect(self):
"""Detect transfers that use arbitrary `from` parameter."""
for c in self.compilation_unit.contracts_derived:
self._detect_arbitrary_from(c)

@ -0,0 +1,45 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
from .arbitrary_send_erc20 import ArbitrarySendErc20
class ArbitrarySendErc20NoPermit(AbstractDetector):
"""
Detect when `msg.sender` is not used as `from` in transferFrom
"""
ARGUMENT = "arbitrary-send-erc20"
HELP = "transferFrom uses arbitrary `from`"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/trailofbits/slither/wiki/Detector-Documentation#arbitrary-send-erc20"
WIKI_TITLE = "Arbitrary `from` in transferFrom"
WIKI_DESCRIPTION = "Detect when `msg.sender` is not used as `from` in transferFrom."
WIKI_EXPLOIT_SCENARIO = """
```solidity
function a(address from, address to, uint256 amount) public {
erc20.transferFrom(from, to, am);
}
```
Alice approves this contract to spend her ERC20 tokens. Bob can call `a` and specify Alice's address as the `from` parameter in `transferFrom`, allowing him to transfer Alice's tokens to himself."""
WIKI_RECOMMENDATION = """
Use `msg.sender` as `from` in transferFrom.
"""
def _detect(self) -> List[Output]:
""""""
results: List[Output] = []
arbitrary_sends = ArbitrarySendErc20(self.compilation_unit)
arbitrary_sends.detect()
for node in arbitrary_sends.no_permit_results:
func = node.function
info = [func, " uses arbitrary from in transferFrom: ", node, "\n"]
res = self.generate_result(info)
results.append(res)
return results

@ -0,0 +1,53 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
from .arbitrary_send_erc20 import ArbitrarySendErc20
class ArbitrarySendErc20Permit(AbstractDetector):
"""
Detect when `msg.sender` is not used as `from` in transferFrom along with the use of permit.
"""
ARGUMENT = "arbitrary-send-erc20-permit"
HELP = "transferFrom uses arbitrary from with permit"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = "https://github.com/trailofbits/slither/wiki/Detector-Documentation#arbitrary-send-erc20-permit"
WIKI_TITLE = "Arbitrary `from` in transferFrom used with permit"
WIKI_DESCRIPTION = (
"Detect when `msg.sender` is not used as `from` in transferFrom and permit is used."
)
WIKI_EXPLOIT_SCENARIO = """
```solidity
function bad(address from, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s, address to) public {
erc20.permit(from, address(this), value, deadline, v, r, s);
erc20.transferFrom(from, to, value);
}
```
If an ERC20 token does not implement permit and has a fallback function e.g. WETH, transferFrom allows an attacker to transfer all tokens approved for this contract."""
WIKI_RECOMMENDATION = """
Ensure that the underlying ERC20 token correctly implements a permit function.
"""
def _detect(self) -> List[Output]:
""""""
results: List[Output] = []
arbitrary_sends = ArbitrarySendErc20(self.compilation_unit)
arbitrary_sends.detect()
for node in arbitrary_sends.permit_results:
func = node.function
info = [
func,
" uses arbitrary from in transferFrom in combination with permit: ",
node,
"\n",
]
res = self.generate_result(info)
results.append(res)
return results

@ -90,8 +90,8 @@ def detect_arbitrary_send(contract: Contract):
return ret
class ArbitrarySend(AbstractDetector):
ARGUMENT = "arbitrary-send"
class ArbitrarySendEth(AbstractDetector):
ARGUMENT = "arbitrary-send-eth"
HELP = "Functions that send Ether to arbitrary destinations"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.MEDIUM
@ -104,7 +104,7 @@ class ArbitrarySend(AbstractDetector):
# region wiki_exploit_scenario
WIKI_EXPLOIT_SCENARIO = """
```solidity
contract ArbitrarySend{
contract ArbitrarySendEth{
address destination;
function setDestination(){
destination = msg.sender;

@ -94,7 +94,7 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
"private",
] and self.is_mixed_case_with_underscore(func.name):
continue
if func.name.startswith("echidna_") or func.name.startswith("crytic_"):
if func.name.startswith(("echidna_", "crytic_")):
continue
info = ["Function ", func, " is not in mixedCase\n"]

@ -2,9 +2,19 @@
Module detecting numbers with too many digits.
"""
import re
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.variables import Constant
_HEX_ADDRESS_REGEXP = re.compile("(0[xX])?[0-9a-fA-F]{40}")
def is_hex_address(value) -> bool:
"""
Checks if the given string of text type is an address in hexadecimal encoded form.
"""
return _HEX_ADDRESS_REGEXP.fullmatch(value) is not None
class TooManyDigits(AbstractDetector):
"""
@ -58,7 +68,7 @@ Use:
if isinstance(read, Constant):
# read.value can return an int or a str. Convert it to str
value_as_str = read.original_value
if "00000" in value_as_str:
if "00000" in value_as_str and not is_hex_address(value_as_str):
# Info to be printed
ret.append(node)
return ret

@ -102,7 +102,7 @@ class UnprotectedUpgradeable(AbstractDetector):
info = (
[
contract,
" is an upgradeable contract that does not protect its initiliaze functions: ",
" is an upgradeable contract that does not protect its initialize functions: ",
]
+ initialize_functions
+ [

@ -17,7 +17,9 @@ class SimilarVarsDetection(AbstractDetector):
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-are-too-similar"
WIKI = (
"https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-too-similar"
)
WIKI_TITLE = "Variable names too similar"
WIKI_DESCRIPTION = "Detect variables with names that are too similar."

@ -13,7 +13,7 @@ REPLACEMENT_VERSIONS = ["^0.4.25", "^0.5.3"]
# 2: version number
# 3: version number
# 4: version number
PATTERN = re.compile("(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
PATTERN = re.compile(r"(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
def custom_format(slither, result):

@ -13,8 +13,7 @@ REPLACEMENT_VERSIONS = ["^0.4.25", "^0.5.3"]
# 3: version number
# 4: version number
# pylint: disable=anomalous-backslash-in-string
PATTERN = re.compile("(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
PATTERN = re.compile(r"(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
def custom_format(slither, result):

@ -300,10 +300,10 @@ def _patch(compilation_unit: SlitherCompilationUnit, result, element, _target):
# group 2: beginning of the to type
# nested mapping are within the group 1
# RE_MAPPING = '[ ]*mapping[ ]*\([ ]*([\=\>\(\) a-zA-Z0-9\._\[\]]*)[ ]*=>[ ]*([a-zA-Z0-9\._\[\]]*)\)'
RE_MAPPING_FROM = b"([a-zA-Z0-9\._\[\]]*)"
RE_MAPPING_TO = b"([\=\>\(\) a-zA-Z0-9\._\[\]\ ]*)"
RE_MAPPING_FROM = rb"([a-zA-Z0-9\._\[\]]*)"
RE_MAPPING_TO = rb"([\=\>\(\) a-zA-Z0-9\._\[\]\ ]*)"
RE_MAPPING = (
b"[ ]*mapping[ ]*\([ ]*" + RE_MAPPING_FROM + b"[ ]*" + b"=>" + b"[ ]*" + RE_MAPPING_TO + b"\)"
rb"[ ]*mapping[ ]*\([ ]*" + RE_MAPPING_FROM + b"[ ]*" + b"=>" + b"[ ]*" + RE_MAPPING_TO + rb"\)"
)

@ -28,7 +28,7 @@ class VariableOrder(AbstractPrinter):
txt += f"\n{contract.name}:\n"
table = MyPrettyTable(["Name", "Type", "Slot", "Offset"])
for variable in contract.state_variables_ordered:
if not variable.is_constant:
if not variable.is_constant and not variable.is_immutable:
slot, offset = contract.compilation_unit.storage_layout_of(contract, variable)
table.add_row([variable.canonical_name, str(variable.type), slot, offset])

@ -53,7 +53,7 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
Keyword Args:
solc (str): solc binary location (default 'solc')
disable_solc_warnings (bool): True to disable solc warnings (default false)
solc_arguments (str): solc arguments (default '')
solc_args (str): solc arguments (default '')
ast_format (str): ast format (default '--ast-compact-json')
filter_paths (list(str)): list of path to filter (default [])
triage_mode (bool): if true, switch to triage mode (default false)

@ -817,12 +817,28 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]): # pylint: dis
# lib L { event E()}
# ...
# emit L.E();
if str(ins.ori.variable_right) in [f.name for f in ins.ori.variable_left.events]:
if str(ins.ori.variable_right) in ins.ori.variable_left.events_as_dict:
eventcall = EventCall(ins.ori.variable_right)
eventcall.set_expression(ins.expression)
eventcall.call_id = ins.call_id
return eventcall
# lib Lib { error Error()} ... revert Lib.Error()
if str(ins.ori.variable_right) in ins.ori.variable_left.custom_errors_as_dict:
custom_error = ins.ori.variable_left.custom_errors_as_dict[
str(ins.ori.variable_right)
]
assert isinstance(
custom_error,
CustomError,
)
sol_function = SolidityCustomRevert(custom_error)
solidity_call = SolidityCall(
sol_function, ins.nbr_arguments, ins.lvalue, ins.type_call
)
solidity_call.set_expression(ins.expression)
return solidity_call
libcall = LibraryCall(
ins.ori.variable_left,
ins.ori.variable_right,
@ -1369,7 +1385,11 @@ def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract):
if len(candidates) == 1:
func = candidates[0]
if func is None:
# We can discard if there are arguments here because libraries only support constant variables
# And constant variables cannot have non-value type
# i.e. "uint[2] constant arr = [1,2];" is not possible in Solidity
# If this were to change, the following condition might be broken
if func is None and not ir.arguments:
# TODO: handle collision with multiple state variables/functions
func = lib_contract.get_state_variable_from_name(ir.function_name)
if func is None and candidates:

@ -445,7 +445,7 @@ def parse_expression(expression: Dict, caller_context: CallerContextExpression)
t = expression["attributes"]["type"]
if t:
found = re.findall("[struct|enum|function|modifier] \(([\[\] ()a-zA-Z0-9\.,_]*)\)", t)
found = re.findall(r"[struct|enum|function|modifier] \(([\[\] ()a-zA-Z0-9\.,_]*)\)", t)
assert len(found) <= 1
if found:
value = value + "(" + found[0] + ")"

@ -679,12 +679,12 @@ Please rename it, this name is reserved for Slither's internals"""
for func in contract.functions + contract.modifiers:
try:
func.generate_slithir_and_analyze()
except AttributeError:
except AttributeError as e:
# This can happens for example if there is a call to an interface
# And the interface is redefined due to contract's name reuse
# But the available version misses some functions
self._underlying_contract_to_parser[contract].log_incorrect_parsing(
f"Impossible to generate IR for {contract.name}.{func.name}"
f"Impossible to generate IR for {contract.name}.{func.name}:\n {e}"
)
contract.convert_expression_to_slithir_ssa()

@ -112,7 +112,7 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t
if not var_type:
if name.startswith("function "):
found = re.findall(
"function \(([ ()\[\]a-zA-Z0-9\.,]*?)\)(?: payable)?(?: (?:external|internal|pure|view))?(?: returns \(([a-zA-Z0-9() \.,]*)\))?",
r"function \(([ ()\[\]a-zA-Z0-9\.,]*?)\)(?: payable)?(?: (?:external|internal|pure|view))?(?: returns \(([a-zA-Z0-9() \.,]*)\))?",
name,
)
assert len(found) == 1
@ -159,10 +159,10 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t
if name.startswith("mapping("):
# nested mapping declared with var
if name.count("mapping(") == 1:
found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([ a-zA-Z0-9\.\[\]]*)\)", name)
found = re.findall(r"mapping\(([a-zA-Z0-9\.]*) => ([ a-zA-Z0-9\.\[\]]*)\)", name)
else:
found = re.findall(
"mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)",
r"mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)",
name,
)
assert len(found) == 1

@ -738,7 +738,7 @@ def _parse_yul_magic_suffixes(name: str, root: YulScope) -> Optional[Expression]
# Currently SlithIR doesnt support raw access to memory
# So things like .offset/.slot will return the variable
# Instaed of the actual offset/slot
if name.endswith("_slot") or name.endswith(".slot"):
if name.endswith(("_slot", ".slot")):
potential_name = name[:-5]
variable_found = _check_for_state_variable_name(root, potential_name)
if variable_found:
@ -746,7 +746,7 @@ def _parse_yul_magic_suffixes(name: str, root: YulScope) -> Optional[Expression]
var = root.function.get_local_variable_from_name(potential_name)
if var and var.is_storage:
return Identifier(var)
if name.endswith("_offset") or name.endswith(".offset"):
if name.endswith(("_offset", ".offset")):
potential_name = name[:-7]
variable_found = _check_for_state_variable_name(root, potential_name)
if variable_found:

@ -192,6 +192,7 @@ def generic_erc_checks(contract, erc_functions, erc_events, ret, explored=None):
logger.info("## Check functions")
for erc_function in erc_functions:
_check_signature(erc_function, contract, ret)
if erc_events:
logger.info("\n## Check events")
for erc_event in erc_events:
_check_events(erc_event, contract, ret)

@ -22,8 +22,8 @@ def _get_all_covered_kspec_functions(target: str) -> Set[Tuple[str, str]]:
# Create a set of our discovered functions which are covered
covered_functions: Set[Tuple[str, str]] = set()
BEHAVIOUR_PATTERN = re.compile("behaviour\s+(\S+)\s+of\s+(\S+)")
INTERFACE_PATTERN = re.compile("interface\s+([^\r\n]+)")
BEHAVIOUR_PATTERN = re.compile(r"behaviour\s+(\S+)\s+of\s+(\S+)")
INTERFACE_PATTERN = re.compile(r"interface\s+([^\r\n]+)")
# Read the file contents
with open(target, "r", encoding="utf8") as target_file:

@ -46,13 +46,13 @@ slither-read-storage 0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 --layout --rpc-u
To view only the slot of the `slot0` structure variable, pass `--variable-name slot0`:
```shell
slither-read-storage 0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 --variable-name slot0 --rpc-url https://mainnet.infura.io/v3/04942f7970ef41cc847a147bc64e460e --value
slither-read-storage 0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 --variable-name slot0 --rpc-url $RPC_URL --value
```
To view a member of the `slot0` struct, pass `--struct-var tick`
```shell
slither-read-storage 0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 --variable-name slot0 --rpc-url https://mainnet.infura.io/v3/04942f7970ef41cc847a147bc64e460e --value --struct-var tick
slither-read-storage 0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 --variable-name slot0 --rpc-url $RPC_URL --value --struct-var tick
```
Retrieve the ERC20 balance slot of an account:

@ -15,7 +15,7 @@ class MultipleInitTarget(Exception):
pass
def _has_initiliaze_modifier(function: Function):
def _has_initialize_modifier(function: Function):
if not function.modifiers:
return False
return any((m.name == "initializer") for m in function.modifiers)
@ -25,7 +25,7 @@ def _get_initialize_functions(contract):
return [
f
for f in contract.functions
if (f.name == "initialize" or _has_initiliaze_modifier(f)) and f.is_implemented
if (f.name == "initialize" or _has_initialize_modifier(f)) and f.is_implemented
]
@ -313,7 +313,7 @@ contract DerivedDerived is Derived{
}
```
`Base.initialize(uint)` is called two times in `DerivedDerived.initiliaze` execution, leading to a potential corruption.
`Base.initialize(uint)` is called two times in `DerivedDerived.initialize` execution, leading to a potential corruption.
"""
# endregion wiki_exploit_scenario

@ -1,5 +1,6 @@
from functools import partial
import platform
import sys
class Colors: # pylint: disable=too-few-public-methods
@ -73,7 +74,7 @@ def set_colorization_enabled(enabled: bool):
if enabled and platform.system() == "Windows":
Colors.COLORIZATION_ENABLED = enable_windows_virtual_terminal_sequences()
else:
# This is not windows so we can enable color immediately.
# This is not windows, or colorization is being disabled, so we can adjust the state immediately.
Colors.COLORIZATION_ENABLED = enabled
@ -83,6 +84,5 @@ red = partial(colorize, Colors.RED)
blue = partial(colorize, Colors.BLUE)
magenta = partial(colorize, Colors.MAGENTA)
# We enable colorization by default (this call is important as it will enable color mode on Windows by default),
# regardless of whether Slither is interacted with from CLI or another script.
set_colorization_enabled(True)
# We enable colorization by default if the output is a tty
set_colorization_enabled(sys.stdout.isatty())

@ -340,6 +340,53 @@ ERC2612 = [
ERC2612_signatures = erc_to_signatures(ERC2612)
# Review
# https://eips.ethereum.org/EIPS/eip-1363
# Must have ERC20 and ERC165
ERC1363_EVENTS = []
ERC1363 = (
[
ERC("transferAndCall", ["address", "uint256"], "bool", False, True, []),
ERC("transferAndCall", ["address", "uint256", "bytes"], "bool", False, True, []),
ERC("transferFromAndCall", ["address", "address", "uint256"], "bool", False, True, []),
ERC(
"transferFromAndCall",
["address", "address", "uint256", "bytes"],
"bool",
False,
True,
[],
),
ERC("approveAndCall", ["address", "uint256"], "bool", False, True, []),
ERC("approveAndCall", ["address", "uint256", "bytes"], "bool", False, True, []),
]
+ ERC20
+ ERC165
)
ERC1363_signatures = erc_to_signatures(ERC1363)
# Review
# https://eips.ethereum.org/EIPS/eip-4524
# Must have ERC20 and ERC165
ERC4524_EVENTS = []
ERC4524 = (
[
ERC("safeTransfer", ["address", "uint256"], "bool", False, True, []),
ERC("safeTransfer", ["address", "uint256", "bytes"], "bool", False, True, []),
ERC("safeTransferFrom", ["address", "address", "uint256"], "bool", False, True, []),
ERC(
"safeTransferFrom", ["address", "address", "uint256", "bytes"], "bool", False, True, []
),
]
+ ERC20
+ ERC165
)
ERC4524_signatures = erc_to_signatures(ERC4524)
# Final
# https://eips.ethereum.org/EIPS/eip-4626
# Must have ERC20
@ -405,5 +452,7 @@ ERCS = {
"ERC777": (ERC777, ERC777_EVENTS),
"ERC1155": (ERC1155, ERC1155_EVENTS),
"ERC2612": (ERC2612, ERC2612_EVENTS),
"ERC1363": (ERC1363, ERC1363_EVENTS),
"ERC4524": (ERC4524, ERC4524_EVENTS),
"ERC4626": (ERC4626, ERC4626_EVENTS),
}

@ -7,7 +7,7 @@ from slither.exceptions import SlitherError
def convert_string_to_int(val: Union[str, int]) -> int:
if isinstance(val, int):
return val
if val.startswith("0x") or val.startswith("0X"):
if val.startswith(("0x", "0X")):
return int(val, 16)
if "e" in val or "E" in val:

@ -160,7 +160,7 @@ def output_to_sarif(
],
}
for detector in results["detectors"]:
for detector in results.get("detectors", []):
_output_result_to_sarif(detector, detectors_classes, sarif)
if filename == "-":

@ -9,6 +9,7 @@ from slither.core.declarations import (
SolidityFunction,
Contract,
)
from slither.core.declarations.enum import Enum
from slither.core.expressions import (
AssignmentOperationType,
UnaryOperationType,
@ -403,18 +404,25 @@ class ExpressionToSlithIR(ExpressionVisitor):
assert len(expression.expression.arguments) == 1
val = TemporaryVariable(self._node)
type_expression_found = expression.expression.arguments[0]
assert isinstance(type_expression_found, ElementaryTypeNameExpression)
if isinstance(type_expression_found, ElementaryTypeNameExpression):
type_found = type_expression_found.type
if expression.member_name == "min:":
constant_type = type_found
else:
# type(enum).max/min
assert isinstance(type_expression_found, Identifier)
type_found = type_expression_found.value
assert isinstance(type_found, Enum)
constant_type = None
if expression.member_name == "min":
op = Assignment(
val,
Constant(str(type_found.min), type_found),
Constant(str(type_found.min), constant_type),
type_found,
)
else:
op = Assignment(
val,
Constant(str(type_found.max), type_found),
Constant(str(type_found.max), constant_type),
type_found,
)
self._result.append(op)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save