Merge branch 'dev-ci' into dev-echidna-printer-fix

pull/763/head
Josselin 4 years ago
commit 0dbcae7692
  1. 48
      .github/workflows/black.yml
  2. 8
      .github/workflows/ci.yml
  3. 8
      .github/workflows/detectors.yml
  4. 26
      .github/workflows/linter.yml
  5. 4
      .github/workflows/parser.yml
  6. 49
      .github/workflows/pylint.yml
  7. 8
      CONTRIBUTING.md
  8. 5
      README.md
  9. 4
      plugin_example/setup.py
  10. 2
      scripts/ci_test_cli.sh
  11. 2
      scripts/ci_test_erc.sh
  12. 2
      scripts/ci_test_find_paths.sh
  13. 2
      scripts/ci_test_kspec.sh
  14. 2
      scripts/ci_test_printers.sh
  15. 2
      scripts/ci_test_simil.sh
  16. 2
      scripts/ci_test_upgradability.sh
  17. 15
      slither/__main__.py
  18. 19
      slither/analyses/data_dependency/data_dependency.py
  19. 5
      slither/analyses/write/are_variables_written.py
  20. 8
      slither/core/cfg/node.py
  21. 23
      slither/core/declarations/function.py
  22. 4
      slither/core/solidity_types/function_type.py
  23. 11
      slither/core/solidity_types/user_defined_type.py
  24. 3
      slither/detectors/attributes/locked_ether.py
  25. 8
      slither/detectors/functions/arbitrary_send.py
  26. 14
      slither/detectors/naming_convention/naming_convention.py
  27. 4
      slither/detectors/operations/block_timestamp.py
  28. 3
      slither/detectors/reentrancy/reentrancy.py
  29. 12
      slither/detectors/reentrancy/reentrancy_benign.py
  30. 10
      slither/detectors/reentrancy/reentrancy_eth.py
  31. 12
      slither/detectors/reentrancy/reentrancy_events.py
  32. 18
      slither/detectors/reentrancy/reentrancy_no_gas.py
  33. 7
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  34. 6
      slither/detectors/statements/incorrect_strict_equality.py
  35. 4
      slither/detectors/statements/unprotected_upgradeable.py
  36. 7
      slither/formatters/attributes/constant_pragma.py
  37. 7
      slither/formatters/naming_convention/naming_convention.py
  38. 58
      slither/printers/call/call_graph.py
  39. 6
      slither/printers/functions/authorization.py
  40. 6
      slither/printers/summary/evm.py
  41. 19
      slither/printers/summary/function.py
  42. 9
      slither/printers/summary/human_summary.py
  43. 5
      slither/printers/summary/require_calls.py
  44. 26
      slither/slithir/convert.py
  45. 6
      slither/slithir/operations/binary.py
  46. 6
      slither/slithir/operations/library_call.py
  47. 9
      slither/slithir/tmp_operations/tmp_call.py
  48. 18
      slither/slithir/utils/ssa.py
  49. 9
      slither/slithir/utils/utils.py
  50. 3
      slither/solc_parsing/declarations/contract.py
  51. 8
      slither/solc_parsing/declarations/function.py
  52. 5
      slither/solc_parsing/declarations/structure_contract.py
  53. 5
      slither/solc_parsing/declarations/structure_top_level.py
  54. 15
      slither/solc_parsing/expressions/expression_parsing.py
  55. 12
      slither/solc_parsing/slitherSolc.py
  56. 3
      slither/solc_parsing/solidity_types/type_parsing.py
  57. 11
      slither/solc_parsing/yul/parse_yul.py
  58. 3
      slither/tools/erc_conformance/__main__.py
  59. 13
      slither/tools/flattening/__main__.py
  60. 0
      slither/tools/flattening/export/__init__.py
  61. 4
      slither/tools/flattening/export/export.py
  62. 15
      slither/tools/flattening/flattening.py
  63. 11
      slither/tools/kspec_coverage/__main__.py
  64. 3
      slither/tools/possible_paths/__main__.py
  65. 3
      slither/tools/possible_paths/possible_paths.py
  66. 4
      slither/tools/properties/__main__.py
  67. 6
      slither/tools/properties/properties/erc20.py
  68. 11
      slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py
  69. 5
      slither/tools/similarity/__main__.py
  70. 11
      slither/tools/slither_format/__main__.py
  71. 5
      slither/tools/slither_format/slither_format.py
  72. 5
      slither/tools/upgradeability/__main__.py
  73. 43
      slither/utils/erc.py
  74. 12
      slither/utils/expression_manipulations.py
  75. 4
      slither/utils/inheritance_analysis.py
  76. 44
      slither/utils/output.py
  77. 12
      slither/visitors/slithir/expression_to_slithir.py
  78. 0
      tests/__init__.py
  79. 61
      tests/detectors/reentrancy-benign/reentrancy-benign.sol
  80. 4580
      tests/detectors/reentrancy-benign/reentrancy-benign.sol.0.4.26.ReentrancyBenign.json
  81. 10
      tests/test_ast_parsing.py
  82. 5
      tests/test_detectors.py
  83. 261
      tests/test_function.py
  84. 129
      tests/test_function.sol
  85. 45
      trophies.md

@ -0,0 +1,48 @@
---
name: Lint Code Base
defaults:
run:
# To load bashrc
shell: bash -ieo pipefail {0}
on:
pull_request:
branches: [master, dev]
schedule:
# run CI every day even if no PRs/merges occur
- cron: '0 12 * * *'
jobs:
build:
name: Lint Code Base
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Set up Python 3.6
uses: actions/setup-python@v2
with:
python-version: 3.6
- name: Install dependencies
run: |
pip install .
pip install deepdiff numpy
mkdir -p .github/linters
cp pyproject.toml .github/linters
- name: Black
uses: docker://github/super-linter:v3
if: always()
env:
# run linter on everything to catch preexisting problems
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Run only black
VALIDATE_PYTHON_BLACK: true
PYTHON_BLACK_CONFIG_FILE: pyproject.toml

@ -45,11 +45,9 @@ jobs:
# Used by ci_test.sh
pip install deepdiff
git clone https://github.com/crytic/solc-select.git
./solc-select/scripts/install.sh
export PATH=/home/runner/.solc-select:$PATH
echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc
solc use 0.5.1
pip install solc-select
solc-select install all
solc-select use 0.5.1
- name: Run Tests
env:

@ -33,11 +33,9 @@ jobs:
pip install deepdiff
pip install pytest
git clone https://github.com/crytic/solc-select.git
./solc-select/scripts/install.sh
export PATH=/home/runner/.solc-select:$PATH
echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc
pip install solc-select
solc-select install all
solc-select use 0.7.3
- name: Test with pytest
run: |
pytest tests/test_detectors.py

@ -35,31 +35,6 @@ jobs:
mkdir -p .github/linters
cp pyproject.toml .github/linters
- name: Pylint
uses: docker://github/super-linter:v3
if: always()
env:
# run linter on everything to catch preexisting problems
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Run only pylint
VALIDATE_PYTHON: true
VALIDATE_PYTHON_PYLINT: true
PYTHON_PYLINT_CONFIG_FILE: pyproject.toml
- name: Black
uses: docker://github/super-linter:v3
if: always()
env:
# run linter on everything to catch preexisting problems
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Run only black
VALIDATE_PYTHON_BLACK: true
PYTHON_BLACK_CONFIG_FILE: pyproject.toml
- name: Lint everything else
uses: docker://github/super-linter:v3
if: always()
@ -80,4 +55,5 @@ jobs:
VALIDATE_DOCKERFILE: false
VALIDATE_DOCKERFILE_HADOLINT: false
VALIDATE_EDITORCONFIG: false
VALIDATE_JSCPD: false
SHELLCHECK_OPTS: "-e SC1090"

@ -34,9 +34,13 @@ jobs:
pip install pytest
git clone https://github.com/crytic/solc-select.git
cd solc-select
git checkout 857d6fa883d9283454be1cb2d869a8f9962b27b8
cd ..
./solc-select/scripts/install.sh
export PATH=/home/runner/.solc-select:$PATH
echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc
solc use 0.7.3
- name: Test with pytest
run: |

@ -0,0 +1,49 @@
---
name: Lint Code Base
defaults:
run:
# To load bashrc
shell: bash -ieo pipefail {0}
on:
pull_request:
branches: [master, dev]
schedule:
# run CI every day even if no PRs/merges occur
- cron: '0 12 * * *'
jobs:
build:
name: Lint Code Base
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Set up Python 3.6
uses: actions/setup-python@v2
with:
python-version: 3.6
- name: Install dependencies
run: |
pip install .
pip install deepdiff numpy
mkdir -p .github/linters
cp pyproject.toml .github/linters
- name: Pylint
uses: docker://github/super-linter:v3
if: always()
env:
# run linter on everything to catch preexisting problems
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Run only pylint
VALIDATE_PYTHON: true
VALIDATE_PYTHON_PYLINT: true
PYTHON_PYLINT_CONFIG_FILE: pyproject.toml

@ -32,12 +32,12 @@ To run the unit tests, you need
Several linters and security checkers are run on the PRs.
To run them locally:
To run them locally in the root dir of the repository:
- `pylint slither --rcfile pyproject.toml`
- `black slither --config pyproject.toml`
- `pylint slither tests --rcfile pyproject.toml`
- `black . --config pyproject.toml`
We use black `19.10b0`.
We use pylint `2.8.2` black `20.8b1`.
### Detectors tests
For each new detector, at least one regression tests must be present.

@ -17,7 +17,7 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s
## Features
* Detects vulnerable Solidity code with low false positives
* Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md))
* Identifies where the error condition occurs in the source code
* Easily integrates into continuous integration and Truffle builds
* Built-in 'printers' quickly report crucial contract information
@ -30,7 +30,7 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s
## Bugs and Optimizations Detection
Run Slither on a Truffle/Embark/Dapp/Etherlime application:
Run Slither on a Truffle/Embark/Dapp/Etherlime/Hardhat application:
```bash
slither .
```
@ -217,5 +217,6 @@ Slither is licensed and distributed under the AGPLv3 license. [Contact us](mailt
- [ETHPLOIT: From Fuzzing to Efficient Exploit Generation against Smart Contracts](https://wcventure.github.io/FuzzingPaper/Paper/SANER20_ETHPLOIT.pdf), Qingzhao Zhang, Yizhuo Wang, Juanru Li, Siqi Ma - SANER 20
- [Verification of Ethereum Smart Contracts: A Model Checking Approach](http://www.ijmlc.org/vol10/977-AM0059.pdf), Tam Bang, Hoang H Nguyen, Dung Nguyen, Toan Trieu, Tho Quan - IJMLC 20
- [Smart Contract Repair](https://arxiv.org/pdf/1912.05823.pdf), 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), Ben Mariano, Yanju Chen, Yu Feng, Shuvendu Lahiri, Isil Dillig - ASE 20
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/).

@ -9,5 +9,7 @@ setup(
packages=find_packages(),
python_requires=">=3.6",
install_requires=["slither-analyzer==0.1"],
entry_points={"slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin",},
entry_points={
"slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin",
},
)

@ -2,7 +2,7 @@
### Test
solc use 0.7.0
solc-select use 0.7.0
if ! slither "tests/config/test.sol" --solc-ast --ignore-return-value; then
echo "--solc-ast failed"

@ -4,7 +4,7 @@
DIR_TESTS="tests/check-erc"
solc use 0.5.0
solc-select use 0.5.0
slither-check-erc "$DIR_TESTS/erc20.sol" ERC20 > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ]

@ -4,7 +4,7 @@
DIR_TESTS="tests/possible_paths"
solc use "0.5.0"
solc-select use "0.5.0"
slither-find-paths "$DIR_TESTS/paths.sol" A.destination > test_possible_paths.txt 2>&1
DIFF=$(diff test_possible_paths.txt "$DIR_TESTS/paths.txt")
if [ "$DIFF" != "" ]

@ -2,7 +2,7 @@
DIR_TESTS="tests/check-kspec"
solc use "0.5.0"
solc-select use "0.5.0"
slither-check-kspec "$DIR_TESTS/safeAdd/safeAdd.sol" "$DIR_TESTS/safeAdd/spec.md" > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ]

@ -10,6 +10,6 @@ if ! slither "tests/*.json" --print all --json -; then
exit 1
fi
solc use "0.5.1"
solc-select use "0.5.1"
slither examples/scripts/test_evm_api.sol --print evm

@ -7,7 +7,7 @@ pip3.6 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip
### Test slither-simil
solc use "0.4.25"
solc-select use "0.4.25"
DIR_TESTS="tests/simil"
slither-simil info "" --filename $DIR_TESTS/../complex_func.sol --fname Complex.complexExternalWrites > test_1.txt 2>&1

@ -3,7 +3,7 @@
### Test slither-check-upgradeability
DIR_TESTS="tests/check-upgradeability"
solc use "0.5.0"
solc-select use "0.5.0"
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")

@ -412,7 +412,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
)
group_misc.add_argument(
"--markdown-root", help="URL for markdown generation", action="store", default="",
"--markdown-root",
help="URL for markdown generation",
action="store",
default="",
)
group_misc.add_argument(
@ -447,7 +450,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
)
group_misc.add_argument(
"--solc-ast", help="Provide the contract as a json AST", action="store_true", default=False,
"--solc-ast",
help="Provide the contract as a json AST",
action="store_true",
default=False,
)
group_misc.add_argument(
@ -500,7 +506,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
)
parser.add_argument(
"--perf", help=argparse.SUPPRESS, action="store_true", default=False,
"--perf",
help=argparse.SUPPRESS,
action="store_true",
default=False,
)
# if the json is splitted in different files

@ -136,7 +136,9 @@ def is_tainted_ssa(variable, context, only_unprotected=False, ignore_generic_tai
def get_dependencies(
variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False,
variable: Variable,
context: Union[Contract, Function],
only_unprotected: bool = False,
) -> Set[Variable]:
"""
Return the variables for which `variable` depends on.
@ -171,7 +173,9 @@ def get_all_dependencies(
def get_dependencies_ssa(
variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False,
variable: Variable,
context: Union[Contract, Function],
only_unprotected: bool = False,
) -> Set[Variable]:
"""
Return the variables for which `variable` depends on (SSA version).
@ -382,7 +386,16 @@ def convert_variable_to_non_ssa(v):
return v.non_ssa_version
assert isinstance(
v,
(Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,),
(
Constant,
SolidityVariable,
Contract,
Enum,
SolidityFunction,
Structure,
Function,
Type,
),
)
return v

@ -35,7 +35,10 @@ class State: # pylint: disable=too-few-public-methods
# pylint: disable=too-many-branches
def _visit(
node: Node, state: State, variables_written: Set[Variable], variables_to_write: List[Variable],
node: Node,
state: State,
variables_written: Set[Variable],
variables_to_write: List[Variable],
):
"""
Explore all the nodes to look for values not written when the node's function return

@ -800,11 +800,15 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
###################################################################################
@property
def phi_origins_local_variables(self,) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
def phi_origins_local_variables(
self,
) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
return self._phi_origins_local_variables
@property
def phi_origins_state_variables(self,) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
def phi_origins_state_variables(
self,
) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
return self._phi_origins_state_variables
# @property

@ -43,7 +43,6 @@ if TYPE_CHECKING:
from slither.core.expressions.expression import Expression
from slither.slithir.operations import Operation
from slither.slither import Slither
from slither.core.cfg.node import NodeType
from slither.core.slither_core import SlitherCore
LOGGER = logging.getLogger("Function")
@ -52,7 +51,10 @@ ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
class ModifierStatements:
def __init__(
self, modifier: Union["Contract", "Function"], entry_point: "Node", nodes: List["Node"],
self,
modifier: Union["Contract", "Function"],
entry_point: "Node",
nodes: List["Node"],
):
self._modifier = modifier
self._entry_point = entry_point
@ -299,17 +301,18 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
def can_send_eth(self) -> bool:
"""
Check if the function can send eth
Check if the function or any internal (not external) functions called by it can send eth
:return bool:
"""
from slither.slithir.operations import Call
if self._can_send_eth is None:
self._can_send_eth = False
for ir in self.all_slithir_operations():
if isinstance(ir, Call) and ir.can_send_eth():
self._can_send_eth = True
return True
return self._can_reenter
return self._can_send_eth
@property
def slither(self) -> "SlitherCore":
@ -1147,7 +1150,9 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
@staticmethod
def _explore_func_conditional(
func: "Function", f: Callable[["Node"], List[SolidityVariable]], include_loop: bool,
func: "Function",
f: Callable[["Node"], List[SolidityVariable]],
include_loop: bool,
):
ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
return [item for sublist in ret for item in sublist]
@ -1594,10 +1599,14 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
return ret
def get_last_ssa_state_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]:
def get_last_ssa_state_variables_instances(
self,
) -> Dict[str, Set["SlithIRVariable"]]:
return self._get_last_ssa_variable_instances(target_state=True, target_local=False)
def get_last_ssa_local_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]:
def get_last_ssa_local_variables_instances(
self,
) -> Dict[str, Set["SlithIRVariable"]]:
return self._get_last_ssa_variable_instances(target_state=False, target_local=True)
@staticmethod

@ -6,7 +6,9 @@ from slither.core.variables.function_type_variable import FunctionTypeVariable
class FunctionType(Type):
def __init__(
self, params: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable],
self,
params: List[FunctionTypeVariable],
return_values: List[FunctionTypeVariable],
):
assert all(isinstance(x, FunctionTypeVariable) for x in params)
assert all(isinstance(x, FunctionTypeVariable) for x in return_values)

@ -59,12 +59,13 @@ class UserDefinedType(Type):
raise SlitherException(to_log)
def __str__(self):
from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum
from slither.core.declarations.structure_contract import StructureContract
from slither.core.declarations.enum_contract import EnumContract
if isinstance(self.type, (Enum, Structure)):
return str(self.type.contract) + "." + str(self.type.name)
return str(self.type.name)
type_used = self.type
if isinstance(type_used, (EnumContract, StructureContract)):
return str(type_used.contract) + "." + str(type_used.name)
return str(type_used.name)
def __eq__(self, other):
if not isinstance(other, UserDefinedType):

@ -53,7 +53,8 @@ Every Ether sent to `Locked` will be lost."""
for node in function.nodes:
for ir in node.irs:
if isinstance(
ir, (Send, Transfer, HighLevelCall, LowLevelCall, NewContract),
ir,
(Send, Transfer, HighLevelCall, LowLevelCall, NewContract),
):
if ir.call_value and ir.call_value != 0:
return False

@ -41,7 +41,9 @@ def arbitrary_send(func):
if ir.variable_right == SolidityVariableComposed("msg.sender"):
return False
if is_dependent(
ir.variable_right, SolidityVariableComposed("msg.sender"), func.contract,
ir.variable_right,
SolidityVariableComposed("msg.sender"),
func.contract,
):
return False
if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)):
@ -54,7 +56,9 @@ def arbitrary_send(func):
if ir.call_value == SolidityVariableComposed("msg.value"):
continue
if is_dependent(
ir.call_value, SolidityVariableComposed("msg.value"), func.contract,
ir.call_value,
SolidityVariableComposed("msg.value"),
func.contract,
):
continue

@ -86,10 +86,14 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
if func.is_constructor:
continue
if not self.is_mixed_case(func.name):
if func.visibility in [
if (
func.visibility
in [
"internal",
"private",
] and self.is_mixed_case_with_underscore(func.name):
]
and self.is_mixed_case_with_underscore(func.name)
):
continue
if func.name.startswith("echidna_") or func.name.startswith("crytic_"):
continue
@ -125,7 +129,11 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
res = self.generate_result(info)
res.add(
var, {"target": "variable", "convention": "l_O_I_should_not_be_used",},
var,
{
"target": "variable",
"convention": "l_O_I_should_not_be_used",
},
)
results.append(res)

@ -36,7 +36,9 @@ def _timestamp(func: Function) -> List[Node]:
return sorted(list(ret), key=lambda x: x.node_id)
def _detect_dangerous_timestamp(contract: Contract,) -> List[Tuple[Function, List[Node]]]:
def _detect_dangerous_timestamp(
contract: Contract,
) -> List[Tuple[Function, List[Node]]]:
"""
Args:
contract (Contract)

@ -127,7 +127,8 @@ class AbstractState:
)
self._reads = union_dict(self._reads, father.context[detector.KEY].reads)
self._reads_prior_calls = union_dict(
self.reads_prior_calls, father.context[detector.KEY].reads_prior_calls,
self.reads_prior_calls,
father.context[detector.KEY].reads_prior_calls,
)
def analyze_node(self, node, detector):

@ -63,7 +63,11 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
if v in node.context[self.KEY].reads_prior_calls[c]
]
not_read_then_written = {
FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
FindingValue(
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items()
if v not in read_then_written
}
@ -126,7 +130,8 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
#
@ -138,7 +143,8 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
# Add all variables written via nodes which write them.

@ -63,7 +63,9 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
continue
read_then_written |= {
FindingValue(
v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c]
@ -128,7 +130,8 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
# If the calls are not the same ones that send eth, add the eth sending nodes.
@ -138,7 +141,8 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
# Add all variables written via nodes which write them.

@ -61,7 +61,11 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
send_eth=to_hashable(node.context[self.KEY].send_eth),
)
finding_vars = {
FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
FindingValue(
e,
e.node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (e, nodes) in node.context[self.KEY].events.items()
}
if finding_vars:
@ -115,7 +119,8 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
#
@ -127,7 +132,8 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
for finding_value in events:

@ -72,11 +72,19 @@ Only report reentrancy that is based on `transfer` or `send`."""
send_eth=to_hashable(node.context[self.KEY].send_eth),
)
finding_vars = {
FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
FindingValue(
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items()
}
finding_vars |= {
FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
FindingValue(
e,
e.node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (e, nodes) in node.context[self.KEY].events.items()
}
if finding_vars:
@ -151,7 +159,8 @@ Only report reentrancy that is based on `transfer` or `send`."""
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
#
@ -163,7 +172,8 @@ Only report reentrancy that is based on `transfer` or `send`."""
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
# Add all variables written via nodes which write them.

@ -58,7 +58,9 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
continue
read_then_written |= {
FindingValue(
v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c]
@ -114,7 +116,8 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
for call_list_info in calls_list:
if call_list_info != call_info:
res.add(
call_list_info, {"underlying_type": "external_calls_sending_eth"},
call_list_info,
{"underlying_type": "external_calls_sending_eth"},
)
# Add all variables written via nodes which write them.

@ -60,13 +60,13 @@ contract Crowdsale{
return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL
@staticmethod
def is_any_tainted(variables, taints, function):
def is_any_tainted(variables, taints, function) -> bool:
return any(
[
(
is_dependent_ssa(var, taint, function.contract)
for var in variables
for taint in taints
]
)
)
def taint_balance_equalities(self, functions):

@ -79,7 +79,9 @@ class UnprotectedUpgradeable(AbstractDetector):
" is an upgradeable contract that does not protect its initiliaze functions: ",
]
+ initiliaze_functions
+ [". Anyone can delete the contract with: ",]
+ [
". Anyone can delete the contract with: ",
]
+ functions_that_can_destroy
)

@ -70,5 +70,10 @@ def _patch(
in_file_str = slither.source_code[in_file].encode("utf8")
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end]
create_patch(
result, in_file, int(modify_loc_start), int(modify_loc_end), old_str_of_interest, pragma,
result,
in_file,
int(modify_loc_start),
int(modify_loc_end),
old_str_of_interest,
pragma,
)

@ -575,7 +575,12 @@ def _explore_irs(slither, irs, result, target, convert):
loc_end = loc_start + len(old_str)
create_patch(
result, filename_source_code, loc_start, loc_end, old_str, new_str,
result,
filename_source_code,
loc_start,
loc_end,
old_str,
new_str,
)

@ -33,21 +33,39 @@ def _edge(from_node, to_node):
# return dot language string to add graph node (with optional label)
def _node(node, label=None):
return " ".join((f'"{node}"', f'[label="{label}"]' if label is not None else "",))
return " ".join(
(
f'"{node}"',
f'[label="{label}"]' if label is not None else "",
)
)
# pylint: disable=too-many-arguments
def _process_internal_call(
contract, function, internal_call, contract_calls, solidity_functions, solidity_calls,
contract,
function,
internal_call,
contract_calls,
solidity_functions,
solidity_calls,
):
if isinstance(internal_call, (Function)):
contract_calls[contract].add(
_edge(_function_node(contract, function), _function_node(contract, internal_call),)
_edge(
_function_node(contract, function),
_function_node(contract, internal_call),
)
)
elif isinstance(internal_call, (SolidityFunction)):
solidity_functions.add(_node(_solidity_function_node(internal_call)),)
solidity_functions.add(
_node(_solidity_function_node(internal_call)),
)
solidity_calls.add(
_edge(_function_node(contract, function), _solidity_function_node(internal_call),)
_edge(
_function_node(contract, function),
_solidity_function_node(internal_call),
)
)
@ -84,7 +102,12 @@ def _render_solidity_calls(solidity_functions, solidity_calls):
def _process_external_call(
contract, function, external_call, contract_functions, external_calls, all_contracts,
contract,
function,
external_call,
contract_functions,
external_calls,
all_contracts,
):
external_contract, external_function = external_call
@ -94,7 +117,10 @@ def _process_external_call(
# add variable as node to respective contract
if isinstance(external_function, (Variable)):
contract_functions[external_contract].add(
_node(_function_node(external_contract, external_function), external_function.name,)
_node(
_function_node(external_contract, external_function),
external_function.name,
)
)
external_calls.add(
@ -116,15 +142,27 @@ def _process_function(
external_calls,
all_contracts,
):
contract_functions[contract].add(_node(_function_node(contract, function), function.name),)
contract_functions[contract].add(
_node(_function_node(contract, function), function.name),
)
for internal_call in function.internal_calls:
_process_internal_call(
contract, function, internal_call, contract_calls, solidity_functions, solidity_calls,
contract,
function,
internal_call,
contract_calls,
solidity_functions,
solidity_calls,
)
for external_call in function.high_level_calls:
_process_external_call(
contract, function, external_call, contract_functions, external_calls, all_contracts,
contract,
function,
external_call,
contract_functions,
external_calls,
all_contracts,
)

@ -52,7 +52,11 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter):
state_variables_written = [v.name for v in function.all_state_variables_written()]
msg_sender_condition = self.get_msg_sender_checks(function)
table.add_row(
[function.name, str(state_variables_written), str(msg_sender_condition),]
[
function.name,
str(state_variables_written),
str(msg_sender_condition),
]
)
all_tables.append((contract.name, table))
txt += str(table) + "\n"

@ -101,7 +101,8 @@ class PrinterEVM(AbstractPrinter):
)
txt += green(
"\t\tSource line {}: {}\n".format(
node_source_line, contract_file_lines[node_source_line - 1].rstrip(),
node_source_line,
contract_file_lines[node_source_line - 1].rstrip(),
)
)
txt += magenta("\t\tEVM Instructions:\n")
@ -123,7 +124,8 @@ class PrinterEVM(AbstractPrinter):
)
txt += green(
"\t\tSource line {}: {}\n".format(
node_source_line, contract_file_lines[node_source_line - 1].rstrip(),
node_source_line,
contract_file_lines[node_source_line - 1].rstrip(),
)
)
txt += magenta("\t\tEVM Instructions:\n")

@ -65,11 +65,26 @@ class FunctionSummary(AbstractPrinter):
internal_calls = self._convert(internal_calls)
external_calls = self._convert(external_calls)
table.add_row(
[f_name, visi, modifiers, read, write, internal_calls, external_calls,]
[
f_name,
visi,
modifiers,
read,
write,
internal_calls,
external_calls,
]
)
txt += "\n \n" + str(table)
table = MyPrettyTable(
["Modifiers", "Visibility", "Read", "Write", "Internal Calls", "External Calls",]
[
"Modifiers",
"Visibility",
"Read",
"Write",
"Internal Calls",
"External Calls",
]
)
for (
_c_name,

@ -379,7 +379,14 @@ class PrinterHumanSummary(AbstractPrinter):
)
table.add_row(
[contract.name, number_functions, ercs, erc20_info, is_complex, features,]
[
contract.name,
number_functions,
ercs,
erc20_info,
is_complex,
features,
]
)
self.info(txt + "\n" + str(table))

@ -46,7 +46,10 @@ class RequireOrAssert(AbstractPrinter):
]
require = [ir.node for ir in require]
table.add_row(
[function.name, self._convert([str(m.expression) for m in set(require)]),]
[
function.name,
self._convert([str(m.expression) for m in set(require)]),
]
)
txt += "\n" + str(table)
self.info(txt)

@ -210,7 +210,8 @@ def convert_arguments(arguments):
def is_temporary(ins):
return isinstance(
ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
ins,
(Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
)
@ -624,7 +625,8 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals
# We dont need to check for function collision, as solc prevents the use of selector
# if there are multiple functions with the same name
f = next(
(f for f in type_t.functions if f.name == ir.variable_right), None,
(f for f in type_t.functions if f.name == ir.variable_right),
None,
)
if f:
ir.lvalue.set_type(f)
@ -835,7 +837,10 @@ def extract_tmp_call(ins, contract): # pylint: disable=too-many-locals
ins.called = SolidityFunction("blockhash(uint256)")
elif str(ins.called) == "this.balance":
s = SolidityCall(
SolidityFunction("this.balance()"), ins.nbr_arguments, ins.lvalue, ins.type_call,
SolidityFunction("this.balance()"),
ins.nbr_arguments,
ins.lvalue,
ins.type_call,
)
s.set_expression(ins.expression)
return s
@ -1153,7 +1158,11 @@ def look_for_library(contract, ir, using_for, t):
lib_contract = contract.slither.get_contract_from_name(str(destination))
if lib_contract:
lib_call = LibraryCall(
lib_contract, ir.function_name, ir.nbr_arguments, ir.lvalue, ir.type_call,
lib_contract,
ir.function_name,
ir.nbr_arguments,
ir.lvalue,
ir.type_call,
)
lib_call.set_expression(ir.expression)
lib_call.set_node(ir.node)
@ -1386,7 +1395,14 @@ def remove_temporary(result):
ins
for ins in result
if not isinstance(
ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure,),
ins,
(
Argument,
TmpNewElementaryType,
TmpNewContract,
TmpNewArray,
TmpNewStructure,
),
)
]

@ -175,7 +175,11 @@ class Binary(OperationWithLValue):
while isinstance(points, ReferenceVariable):
points = points.points_to
return "{}(-> {}) = {} {} {}".format(
str(self.lvalue), points, self.variable_left, self.type_str, self.variable_right,
str(self.lvalue),
points,
self.variable_left,
self.type_str,
self.variable_right,
)
return "{}({}) = {} {} {}".format(
str(self.lvalue),

@ -38,5 +38,9 @@ class LibraryCall(HighLevelCall):
lvalue = "{}({}) = ".format(self.lvalue, self.lvalue.type)
txt = "{}LIBRARY_CALL, dest:{}, function:{}, arguments:{} {}"
return txt.format(
lvalue, self.destination, self.function_name, [str(x) for x in arguments], gas,
lvalue,
self.destination,
self.function_name,
[str(x) for x in arguments],
gas,
)

@ -13,7 +13,14 @@ class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attribu
def __init__(self, called, nbr_arguments, result, type_call):
assert isinstance(
called,
(Contract, Variable, SolidityVariableComposed, SolidityFunction, Structure, Event,),
(
Contract,
Variable,
SolidityVariableComposed,
SolidityFunction,
Structure,
Event,
),
)
super().__init__()
self._called = called

@ -173,7 +173,9 @@ def add_ssa_ir(function, all_state_variables_instances):
init_state_variables_instances = dict(all_state_variables_instances)
initiate_all_local_variables_instances(
function.nodes, init_local_variables_instances, all_init_local_variables_instances,
function.nodes,
init_local_variables_instances,
all_init_local_variables_instances,
)
generate_ssa_irs(
@ -506,7 +508,8 @@ def add_phi_origins(node, local_variables_definition, state_variables_definition
# We keep the instance as we want to avoid to add __hash__ on v.name in Variable
# That might work for this used, but could create collision for other uses
local_variables_definition = dict(
local_variables_definition, **{v.name: (v, node) for v in node.local_variables_written},
local_variables_definition,
**{v.name: (v, node) for v in node.local_variables_written},
)
state_variables_definition = dict(
state_variables_definition,
@ -598,7 +601,16 @@ def get(
return tuple_variables_instances[variable.index]
assert isinstance(
variable,
(Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,),
(
Constant,
SolidityVariable,
Contract,
Enum,
SolidityFunction,
Structure,
Function,
Type,
),
) # type for abi.decode(.., t)
return variable

@ -25,5 +25,12 @@ def is_valid_rvalue(v):
def is_valid_lvalue(v):
return isinstance(
v, (StateVariable, LocalVariable, TemporaryVariable, ReferenceVariable, TupleVariable,),
v,
(
StateVariable,
LocalVariable,
TemporaryVariable,
ReferenceVariable,
TupleVariable,
),
)

@ -411,7 +411,8 @@ class ContractSolc:
assert isinstance(underlying_function, FunctionContract)
elem.set_contract_declarer(underlying_function.contract_declarer)
elem.set_offset(
element_parser.function_not_parsed["src"], self._contract.slither,
element_parser.function_not_parsed["src"],
self._contract.slither,
)
elem_parser = Cls_parser(

@ -454,7 +454,10 @@ class FunctionSolc:
return key in attributes and not attributes[key]
if attributes and any(
map(has_hint, ["condition", "initializationExpression", "loopExpression"],)
map(
has_hint,
["condition", "initializationExpression", "loopExpression"],
)
):
# if we have attribute hints, rely on those
@ -602,7 +605,8 @@ class FunctionSolc:
link_underlying_nodes(node_startDoWhile, node_condition)
else:
link_nodes(
node_startDoWhile.underlying_node, node_condition.underlying_node.sons[0],
node_startDoWhile.underlying_node,
node_condition.underlying_node.sons[0],
)
link_underlying_nodes(statement, node_condition)
link_underlying_nodes(node_condition, node_endDoWhile)

@ -19,7 +19,10 @@ class StructureContractSolc: # pylint: disable=too-few-public-methods
# elems = [(type, name)]
def __init__( # pylint: disable=too-many-arguments
self, st: Structure, struct: Dict, contract_parser: "ContractSolc",
self,
st: Structure,
struct: Dict,
contract_parser: "ContractSolc",
):
if contract_parser.is_compact_ast:

@ -19,7 +19,10 @@ class StructureTopLevelSolc: # pylint: disable=too-few-public-methods
# elems = [(type, name)]
def __init__( # pylint: disable=too-many-arguments
self, st: Structure, struct: Dict, slither_parser: "SlitherSolc",
self,
st: Structure,
struct: Dict,
slither_parser: "SlitherSolc",
):
if slither_parser.is_compact_ast:

@ -269,7 +269,14 @@ def find_variable(
referenced_declaration: Optional[int] = None,
is_super=False,
) -> Union[
Variable, Function, Contract, SolidityVariable, SolidityFunction, Event, Enum, Structure,
Variable,
Function,
Contract,
SolidityVariable,
SolidityFunction,
Event,
Enum,
Structure,
]:
from slither.solc_parsing.declarations.function import FunctionSolc
from slither.solc_parsing.declarations.contract import ContractSolc
@ -312,9 +319,9 @@ def find_variable(
if ret:
return ret
function_parser: Optional[FunctionSolc] = caller_context if isinstance(
caller_context, FunctionSolc
) else None
function_parser: Optional[FunctionSolc] = (
caller_context if isinstance(caller_context, FunctionSolc) else None
)
ret = _find_variable_in_function_parser(var_name, function_parser, referenced_declaration)
if ret:
return ret

@ -410,7 +410,9 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract]
def _analyze_first_part(
self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
self,
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
):
for lib in libraries:
self._parse_struct_var_modifiers_functions(lib)
@ -435,7 +437,9 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract]
def _analyze_second_part(
self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
self,
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
):
for lib in libraries:
self._analyze_struct_events(lib)
@ -462,7 +466,9 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract]
def _analyze_third_part(
self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
self,
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
):
for lib in libraries:
self._analyze_variables_modifiers_functions(lib)

@ -155,7 +155,8 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t
found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([ a-zA-Z0-9\.\[\]]*)\)", name)
else:
found = re.findall(
"mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)", name,
"mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)",
name,
)
assert len(found) == 1
from_ = found[0][0]

@ -165,7 +165,10 @@ class YulScope(metaclass=abc.ABCMeta):
self._yul_local_functions.append(func)
def get_yul_local_function_from_name(self, func_name):
return next((v for v in self._yul_local_functions if v.underlying.name == func_name), None,)
return next(
(v for v in self._yul_local_functions if v.underlying.name == func_name),
None,
)
class YulLocalVariable: # pylint: disable=too-few-public-methods
@ -457,7 +460,11 @@ def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
"name": "eq",
},
"arguments": [
{"nodeType": "YulIdentifier", "src": case_ast["src"], "name": switch_expr_var,},
{
"nodeType": "YulIdentifier",
"src": case_ast["src"],
"name": switch_expr_var,
},
value_ast,
],
},

@ -31,7 +31,8 @@ def parse_args():
:return: Returns the arguments for the program.
"""
parser = argparse.ArgumentParser(
description="Check the ERC 20 conformance", usage="slither-check-erc project contractName",
description="Check the ERC 20 conformance",
usage="slither-check-erc project contractName",
)
parser.add_argument("project", help="The codebase to be tested.")

@ -41,7 +41,9 @@ def parse_args():
group_export = parser.add_argument_group("Export options")
group_export.add_argument(
"--dir", help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).", default=None,
"--dir",
help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).",
default=None,
)
group_export.add_argument(
@ -52,7 +54,10 @@ def parse_args():
)
parser.add_argument(
"--zip", help="Export all the files to a zip file", action="store", default=None,
"--zip",
help="Export all the files to a zip file",
action="store",
default=None,
)
parser.add_argument(
@ -69,7 +74,9 @@ def parse_args():
)
group_patching.add_argument(
"--convert-private", help="Convert private variables to internal.", action="store_true",
"--convert-private",
help="Convert private variables to internal.",
action="store_true",
)
group_patching.add_argument(

@ -24,7 +24,9 @@ def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"):
"""
logger.info(f"Export {zip_filename}")
with zipfile.ZipFile(
zip_filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
zip_filename,
"w",
compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
) as file_desc:
for f in files:
file_desc.writestr(str(f.filename), f.content)

@ -108,7 +108,10 @@ class Flattening:
regex = re.search(r"((\sexternal)\s+)|(\sexternal)$|(\)external)$", attributes)
if regex:
to_patch.append(
Patch(attributes_start + regex.span()[0] + 1, "public_to_external",)
Patch(
attributes_start + regex.span()[0] + 1,
"public_to_external",
)
)
else:
raise SlitherException(f"External keyword not found {f.name} {attributes}")
@ -119,7 +122,10 @@ class Flattening:
calldata_end = calldata_start + var.source_mapping["length"]
calldata_idx = content[calldata_start:calldata_end].find(" calldata ")
to_patch.append(
Patch(calldata_start + calldata_idx + 1, "calldata_to_memory",)
Patch(
calldata_start + calldata_idx + 1,
"calldata_to_memory",
)
)
if self._private_to_internal:
@ -133,7 +139,10 @@ class Flattening:
regex = re.search(r" private ", attributes)
if regex:
to_patch.append(
Patch(attributes_start + regex.span()[0] + 1, "private_to_internal",)
Patch(
attributes_start + regex.span()[0] + 1,
"private_to_internal",
)
)
else:
raise SlitherException(

@ -22,18 +22,23 @@ def parse_args():
:return: Returns the arguments for the program.
"""
parser = argparse.ArgumentParser(
description="slither-kspec-coverage", usage="slither-kspec-coverage contract.sol kspec.md",
description="slither-kspec-coverage",
usage="slither-kspec-coverage contract.sol kspec.md",
)
parser.add_argument(
"contract", help="The filename of the contract or truffle directory to analyze."
)
parser.add_argument(
"kspec", help="The filename of the Klab spec markdown for the analyzed contract(s)",
"kspec",
help="The filename of the Klab spec markdown for the analyzed contract(s)",
)
parser.add_argument(
"--version", help="displays the current version", version="0.1.0", action="version",
"--version",
help="displays the current version",
version="0.1.0",
action="version",
)
parser.add_argument(
"--json",

@ -21,7 +21,8 @@ def parse_args():
:return: Returns the arguments for the program.
"""
parser = argparse.ArgumentParser(
description="PossiblePaths", usage="possible_paths.py filename [contract.function targets]",
description="PossiblePaths",
usage="possible_paths.py filename [contract.function targets]",
)
parser.add_argument(

@ -18,7 +18,8 @@ def resolve_function(slither, contract_name, function_name):
# Obtain the target function
target_function = next(
(function for function in contract.functions if function.name == function_name), None,
(function for function in contract.functions if function.name == function_name),
None,
)
# Verify we have resolved the function specified.

@ -105,7 +105,9 @@ def parse_args():
)
parser.add_argument(
"--address-attacker", help=f"Attacker address. Default {ATTACKER_ADDRESS}", default=None,
"--address-attacker",
help=f"Attacker address. Default {ATTACKER_ADDRESS}",
default=None,
)
# Add default arguments from crytic-compile

@ -107,7 +107,11 @@ def generate_erc20(
# Generate the Test contract
initialization_recommendation = _initialization_recommendation(type_property)
contract_filename, contract_name = generate_test_contract(
contract, type_property, output_dir, property_file, initialization_recommendation,
contract,
type_property,
output_dir,
property_file,
initialization_recommendation,
)
# Generate Echidna config file

@ -15,7 +15,10 @@ logger = logging.getLogger("Slither")
def generate_truffle_test(
contract: Contract, type_property: str, unit_tests: List[Property], addresses: Addresses,
contract: Contract,
type_property: str,
unit_tests: List[Property],
addresses: Addresses,
) -> str:
test_contract = f"Test{contract.name}{type_property}"
filename_init = f"Initialization{test_contract}.js"
@ -35,7 +38,11 @@ def generate_truffle_test(
)
generate_unit_test(
test_contract, filename, unit_tests, output_dir, addresses,
test_contract,
filename,
unit_tests,
output_dir,
addresses,
)
log_info = "\n"

@ -54,7 +54,10 @@ def parse_args():
)
parser.add_argument(
"--version", help="displays the current version", version="0.0", action="version",
"--version",
help="displays the current version",
version="0.0",
action="version",
)
cryticparser.init(parser)

@ -41,10 +41,17 @@ def parse_args():
default=False,
)
parser.add_argument(
"--verbose-json", "-j", help="verbose json output", action="store_true", default=False,
"--verbose-json",
"-j",
help="verbose json output",
action="store_true",
default=False,
)
parser.add_argument(
"--version", help="displays the current version", version="0.1.0", action="version",
"--version",
help="displays the current version",
version="0.1.0",
action="version",
)
parser.add_argument(

@ -65,7 +65,10 @@ def slither_format(slither, **kwargs): # pylint: disable=too-many-locals
logger.info(f"Issue: {one_line_description}")
logger.info(f"Generated: ({export_result})")
for (_, diff,) in result["patches_diff"].items():
for (
_,
diff,
) in result["patches_diff"].items():
filename = f"fix_{counter}.patch"
path = Path(export_result, filename)
logger.info(f"\t- {filename}")

@ -57,7 +57,10 @@ def parse_args():
)
parser.add_argument(
"--markdown-root", help="URL for markdown generation", action="store", default="",
"--markdown-root",
help="URL for markdown generation",
action="store",
default="",
)
parser.add_argument(

@ -63,7 +63,14 @@ ERC223 = [
ERC("totalSupply", [], "uint256", True, True, []),
ERC("balanceOf", ["address"], "uint256", True, True, []),
ERC("transfer", ["address", "uint256"], "bool", False, True, [ERC223_transfer_event]),
ERC("transfer", ["address", "uint256", "bytes"], "bool", False, True, [ERC223_transfer_event],),
ERC(
"transfer",
["address", "uint256", "bytes"],
"bool",
False,
True,
[ERC223_transfer_event],
),
ERC(
"transfer",
["address", "uint256", "bytes", "string"],
@ -118,10 +125,22 @@ ERC721 = [
[ERC721_transfer_event],
),
ERC(
"transferFrom", ["address", "address", "uint256"], "", False, True, [ERC721_transfer_event],
"transferFrom",
["address", "address", "uint256"],
"",
False,
True,
[ERC721_transfer_event],
),
ERC("approve", ["address", "uint256"], "", False, True, [ERC721_approval_event]),
ERC("setApprovalForAll", ["address", "bool"], "", False, True, [ERC721_approvalforall_event],),
ERC(
"setApprovalForAll",
["address", "bool"],
"",
False,
True,
[ERC721_approvalforall_event],
),
ERC("getApproved", ["uint256"], "address", True, True, []),
ERC("isApprovedForAll", ["address", "address"], "bool", True, True, []),
] + ERC165
@ -140,7 +159,14 @@ ERC721_signatures = erc_to_signatures(ERC721)
# https://eips.ethereum.org/EIPS/eip-1820
ERC1820_EVENTS: List = []
ERC1820 = [
ERC("canImplementInterfaceForAddress", ["bytes32", "address"], "bytes32", True, True, [],)
ERC(
"canImplementInterfaceForAddress",
["bytes32", "address"],
"bytes32",
True,
True,
[],
)
]
ERC1820_signatures = erc_to_signatures(ERC1820)
@ -181,7 +207,14 @@ ERC777 = [
ERC("granularity", [], "uint256", True, True, []),
ERC("defaultOperators", [], "address[]", True, True, []),
ERC("isOperatorFor", ["address", "address"], "bool", True, True, []),
ERC("authorizeOperator", ["address"], "", False, True, [ERC777_authorizedOperator_event],),
ERC(
"authorizeOperator",
["address"],
"",
False,
True,
[ERC777_authorizedOperator_event],
),
ERC("revokeOperator", ["address"], "", False, True, [ERC777_revokedoperator_event]),
ERC("send", ["address", "uint256", "bytes"], "", False, True, [ERC777_sent_event]),
ERC(

@ -110,21 +110,27 @@ class SplitTernaryExpression:
if self.apply_copy(next_expr, true_expression, false_expression, f_call):
# always on last arguments added
self.copy_expression(
next_expr, true_expression.arguments[-1], false_expression.arguments[-1],
next_expr,
true_expression.arguments[-1],
false_expression.arguments[-1],
)
elif isinstance(expression, TypeConversion):
next_expr = expression.expression
if self.apply_copy(next_expr, true_expression, false_expression, f_expression):
self.copy_expression(
expression.expression, true_expression.expression, false_expression.expression,
expression.expression,
true_expression.expression,
false_expression.expression,
)
elif isinstance(expression, UnaryOperation):
next_expr = expression.expression
if self.apply_copy(next_expr, true_expression, false_expression, f_expression):
self.copy_expression(
expression.expression, true_expression.expression, false_expression.expression,
expression.expression,
true_expression.expression,
false_expression.expression,
)
else:

@ -10,7 +10,9 @@ if TYPE_CHECKING:
from slither.core.variables.state_variable import StateVariable
def detect_c3_function_shadowing(contract: "Contract",) -> Dict["Function", Set["Function"]]:
def detect_c3_function_shadowing(
contract: "Contract",
) -> Dict["Function", Set["Function"]]:
"""
Detects and obtains functions which are indirectly shadowed via multiple inheritance by C3 linearization
properties, despite not directly inheriting from each other.

@ -78,7 +78,9 @@ def output_to_zip(filename: str, error: Optional[str], results: Dict, zip_type:
logger.info(yellow(f"{filename} exists already, the overwrite is prevented"))
else:
with ZipFile(
filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
filename,
"w",
compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
) as file_desc:
file_desc.writestr("slither_results.json", json.dumps(json_result).encode("utf8"))
@ -355,7 +357,11 @@ class Output:
additional_fields = {}
type_specific_fields = {"parent": _create_parent_element(enum)}
element = _create_base_element(
"enum", enum.name, enum.source_mapping, type_specific_fields, additional_fields,
"enum",
enum.name,
enum.source_mapping,
type_specific_fields,
additional_fields,
)
self._data["elements"].append(element)
@ -371,7 +377,11 @@ class Output:
additional_fields = {}
type_specific_fields = {"parent": _create_parent_element(struct)}
element = _create_base_element(
"struct", struct.name, struct.source_mapping, type_specific_fields, additional_fields,
"struct",
struct.name,
struct.source_mapping,
type_specific_fields,
additional_fields,
)
self._data["elements"].append(element)
@ -390,7 +400,11 @@ class Output:
"signature": event.full_name,
}
element = _create_base_element(
"event", event.name, event.source_mapping, type_specific_fields, additional_fields,
"event",
event.name,
event.source_mapping,
type_specific_fields,
additional_fields,
)
self._data["elements"].append(element)
@ -410,7 +424,11 @@ class Output:
}
node_name = str(node.expression) if node.expression else ""
element = _create_base_element(
"node", node_name, node.source_mapping, type_specific_fields, additional_fields,
"node",
node_name,
node.source_mapping,
type_specific_fields,
additional_fields,
)
self._data["elements"].append(element)
@ -461,7 +479,10 @@ class Output:
###################################################################################
def add_pretty_table(
self, content: MyPrettyTable, name: str, additional_fields: Optional[Dict] = None,
self,
content: MyPrettyTable,
name: str,
additional_fields: Optional[Dict] = None,
):
if additional_fields is None:
additional_fields = {}
@ -478,7 +499,11 @@ class Output:
###################################################################################
def add_other(
self, name: str, source_mapping, slither, additional_fields: Optional[Dict] = None,
self,
name: str,
source_mapping,
slither,
additional_fields: Optional[Dict] = None,
):
# If this a tuple with (filename, start, end), convert it to a source mapping.
if additional_fields is None:
@ -489,7 +514,10 @@ class Output:
source_id = next(
(
source_unit_id
for (source_unit_id, source_unit_filename,) in slither.source_units.items()
for (
source_unit_id,
source_unit_filename,
) in slither.source_units.items()
if source_unit_filename == filename
),
-1,

@ -370,9 +370,17 @@ class ExpressionToSlithIR(ExpressionVisitor):
assert isinstance(type_expression_found, ElementaryTypeNameExpression)
type_found = type_expression_found.type
if expression.member_name == "min:":
op = Assignment(val, Constant(str(type_found.min), type_found), type_found,)
op = Assignment(
val,
Constant(str(type_found.min), type_found),
type_found,
)
else:
op = Assignment(val, Constant(str(type_found.max), type_found), type_found,)
op = Assignment(
val,
Constant(str(type_found.max), type_found),
type_found,
)
self._result.append(op)
set_val(expression, val)
return

@ -0,0 +1,61 @@
pragma solidity ^0.4.0;
contract ReentrancyBenign {
uint8 anotherVariableToChange;
uint8 counter = 0;
function bad0() public {
if (!(msg.sender.call())) {
revert();
}
counter += 1;
}
function bad1(address target) public {
(bool success) = target.call();
require(success);
counter += 1;
}
function bad2(address target) public {
(bool success) = target.call();
if (success) {
address(target).call.value(1000)();
counter += 1;
}
else {
revert();
}
}
function bad3(address target) public {
externalCaller(target);
varChanger();
ethSender(target);
}
function bad4(address target) public {
externalCaller(target);
ethSender(address(0));
varChanger();
address(target).call.value(2)();
}
function bad5(address target) public {
ethSender(address(0));
varChanger();
ethSender(address(0));
}
function externalCaller(address target) private {
address(target).call();
}
function ethSender(address target) private {
address(target).call.value(1)();
}
function varChanger() private {
anotherVariableToChange++;
}
}

@ -470,7 +470,15 @@ def get_tests(solc_versions) -> Dict[str, List[str]]:
return tests
Item = namedtuple("TestItem", ["test_id", "base_ver", "solc_ver", "is_legacy",],)
Item = namedtuple(
"TestItem",
[
"test_id",
"base_ver",
"solc_ver",
"is_legacy",
],
)
def get_all_test() -> List[Item]:

@ -53,6 +53,11 @@ def id_test(test_item: Test):
ALL_TESTS = [
Test(
all_detectors.ReentrancyBenign,
"tests/detectors/reentrancy-benign/reentrancy-benign.sol",
"0.4.26",
),
Test(
all_detectors.ReentrancyReadBeforeWritten,
"tests/detectors/reentrancy-before-write/reentrancy-write.sol",

@ -0,0 +1,261 @@
"""
tests for `slither.core.declarations.Function`.
tests that `tests/test_function.sol` gets translated into correct
`slither.core.declarations.Function` objects or its subclasses
and that these objects behave correctly.
"""
from slither import Slither
from slither.core.declarations.function import FunctionType
from slither.core.solidity_types.elementary_type import ElementaryType
def test_functions():
# pylint: disable=too-many-statements
slither = Slither("tests/test_function.sol")
functions = slither.contracts_as_dict["TestFunction"].available_functions_as_dict()
f = functions["external_payable(uint256)"]
assert f.name == "external_payable"
assert f.full_name == "external_payable(uint256)"
assert f.canonical_name == "TestFunction.external_payable(uint256)"
assert f.solidity_signature == "external_payable(uint256)"
assert f.signature_str == "external_payable(uint256) returns(uint256)"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is True
assert f.visibility == "external"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters[0].name == "_a"
assert f.parameters[0].type == ElementaryType("uint256")
assert f.return_type[0] == ElementaryType("uint256")
f = functions["public_reenter()"]
assert f.name == "public_reenter"
assert f.full_name == "public_reenter()"
assert f.canonical_name == "TestFunction.public_reenter()"
assert f.solidity_signature == "public_reenter()"
assert f.signature_str == "public_reenter() returns()"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is True
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "public"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters == []
assert f.return_type is None
f = functions["public_payable_reenter_send(bool)"]
assert f.name == "public_payable_reenter_send"
assert f.full_name == "public_payable_reenter_send(bool)"
assert f.canonical_name == "TestFunction.public_payable_reenter_send(bool)"
assert f.solidity_signature == "public_payable_reenter_send(bool)"
assert f.signature_str == "public_payable_reenter_send(bool) returns()"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is True
assert f.can_send_eth() is True
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is True
assert f.visibility == "public"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters[0].name == "_b"
assert f.parameters[0].type == ElementaryType("bool")
assert f.return_type is None
f = functions["external_send(uint8)"]
assert f.name == "external_send"
assert f.full_name == "external_send(uint8)"
assert f.canonical_name == "TestFunction.external_send(uint8)"
assert f.solidity_signature == "external_send(uint8)"
assert f.signature_str == "external_send(uint8) returns()"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is True
assert f.can_send_eth() is True
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "external"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters[0].name == "_c"
assert f.parameters[0].type == ElementaryType("uint8")
assert f.return_type is None
f = functions["internal_assembly(bytes)"]
assert f.name == "internal_assembly"
assert f.full_name == "internal_assembly(bytes)"
assert f.canonical_name == "TestFunction.internal_assembly(bytes)"
assert f.solidity_signature == "internal_assembly(bytes)"
assert f.signature_str == "internal_assembly(bytes) returns(uint256)"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is True
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "internal"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters[0].name == "_d"
assert f.parameters[0].type == ElementaryType("bytes")
assert f.return_type[0] == ElementaryType("uint256")
f = functions["fallback()"]
assert f.name == "fallback"
assert f.full_name == "fallback()"
assert f.canonical_name == "TestFunction.fallback()"
assert f.solidity_signature == "fallback()"
assert f.signature_str == "fallback() returns()"
assert f.function_type == FunctionType.FALLBACK
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is True
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "external"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is True
assert f.parameters == []
assert f.return_type is None
f = functions["receive()"]
assert f.name == "receive"
assert f.full_name == "receive()"
assert f.canonical_name == "TestFunction.receive()"
assert f.solidity_signature == "receive()"
assert f.signature_str == "receive() returns()"
assert f.function_type == FunctionType.RECEIVE
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is True
assert f.payable is True
assert f.visibility == "external"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is True
assert f.parameters == []
assert f.return_type is None
f = functions["constructor(address)"]
assert f.name == "constructor"
assert f.full_name == "constructor(address)"
assert f.canonical_name == "TestFunction.constructor(address)"
assert f.solidity_signature == "constructor(address)"
assert f.signature_str == "constructor(address) returns()"
assert f.function_type == FunctionType.CONSTRUCTOR
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is True
assert f.visibility == "public"
assert f.view is False
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is True
assert f.parameters[0].name == "_e"
assert f.parameters[0].type == ElementaryType("address")
assert f.return_type is None
f = functions["private_view()"]
assert f.name == "private_view"
assert f.full_name == "private_view()"
assert f.canonical_name == "TestFunction.private_view()"
assert f.solidity_signature == "private_view()"
assert f.signature_str == "private_view() returns(bool)"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "private"
assert f.view is True
assert f.pure is False
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters == []
assert f.return_type[0] == ElementaryType("bool")
f = functions["public_pure()"]
assert f.name == "public_pure"
assert f.full_name == "public_pure()"
assert f.canonical_name == "TestFunction.public_pure()"
assert f.solidity_signature == "public_pure()"
assert f.signature_str == "public_pure() returns(bool)"
assert f.function_type == FunctionType.NORMAL
assert f.contains_assembly is False
assert f.can_reenter() is False
assert f.can_send_eth() is False
assert f.is_constructor is False
assert f.is_fallback is False
assert f.is_receive is False
assert f.payable is False
assert f.visibility == "public"
assert f.view is True
assert f.pure is True
assert f.is_implemented is True
assert f.is_empty is False
assert f.parameters == []
assert f.return_type[0] == ElementaryType("bool")
def test_function_can_send_eth():
slither = Slither("tests/test_function.sol")
functions = slither.contracts_as_dict["TestFunctionCanSendEth"].available_functions_as_dict()
assert functions["send_direct()"].can_send_eth() is True
assert functions["transfer_direct()"].can_send_eth() is True
assert functions["call_direct()"].can_send_eth() is True
assert functions["highlevel_call_direct()"].can_send_eth() is True
assert functions["send_via_internal()"].can_send_eth() is True
assert functions["transfer_via_internal()"].can_send_eth() is True
assert functions["call_via_internal()"].can_send_eth() is True
assert functions["highlevel_call_via_internal()"].can_send_eth() is True
assert functions["send_via_external()"].can_send_eth() is False
assert functions["transfer_via_external()"].can_send_eth() is False
assert functions["call_via_external()"].can_send_eth() is False
assert functions["highlevel_call_via_external()"].can_send_eth() is False

@ -0,0 +1,129 @@
pragma solidity ^0.6.12;
// solidity source used by tests/test_function.py.
// tests/test_function.py tests that the functions below get translated into correct
// `slither.core.declarations.Function` objects or its subclasses
// and that these objects behave correctly.
contract TestFunction {
bool entered = false;
function external_payable(uint _a) external payable returns (uint) {
return 1;
}
function public_reenter() public {
msg.sender.call("");
}
function public_payable_reenter_send(bool _b) public payable {
msg.sender.call{value: 1}("");
}
function external_send(uint8 _c) external {
require(!entered);
entered = true;
msg.sender.call{value: 1}("");
}
function internal_assembly(bytes calldata _d) internal returns (uint) {
uint256 chain;
assembly {
chain := chainid()
}
return chain;
}
fallback() external {
}
receive() external payable {
}
constructor(address payable _e) public payable {
}
function private_view() private view returns (bool) {
return entered;
}
function public_pure() public pure returns (bool) {
return true;
}
}
contract TestFunctionCanSendEth {
function send_direct() internal {
address(1).send(1);
}
function transfer_direct() internal {
address(1).transfer(1);
}
function call_direct() internal {
address(1).call{value: 1}("");
}
function highlevel_call_direct() internal {
TestFunctionCanSendEthOther(address(5)).i_am_payable{value: 1}();
}
function send_via_internal() public {
send_direct();
}
function transfer_via_internal() public {
transfer_direct();
}
function call_via_internal() public {
call_direct();
}
function highlevel_call_via_internal() public {
highlevel_call_direct();
}
function send_via_external() public {
TestFunctionCanSendEthOther(address(5)).send_direct();
}
function transfer_via_external() public {
TestFunctionCanSendEthOther(address(5)).transfer_direct();
}
function call_via_external() public {
TestFunctionCanSendEthOther(address(5)).call_direct();
}
function highlevel_call_via_external() public {
TestFunctionCanSendEthOther(address(5)).highlevel_call_direct();
}
}
contract TestFunctionCanSendEthOther {
function i_am_payable() external payable {
}
function send_direct() external {
address(1).send(1);
}
function transfer_direct() external {
address(1).transfer(1);
}
function call_direct() external {
address(1).call{value: 1}("");
}
function highlevel_call_direct() external {
TestFunctionCanSendEthOther(address(5)).i_am_payable{value: 1}();
}
}

@ -0,0 +1,45 @@
# Slither Trophies
The following lists security vulnerabilities that were found by Slither.
If you found a security vulnerability using Slither,
please submit a PR with the relevant information.
| Project | Vulnerability | Date |
|--|--|--|
[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Incorrect constructor name | July 2018
[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Deletion of a mapping with structure | July 2018
[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Uninitialized state variables | July 2018
[Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) | Missing return value check | Oct 2018
[Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) | Reentrancy | Nov 2018
[Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) | Deletion of a mapping with structure | Jul 2019
[Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) | Missing return value | Jul 2019
[Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) | Reentrancy (events out of order) | Sep 2019
[0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) | Missing return value | Oct 2019
[Token mint](https://certificate.quantstamp.com/full/token-mint) | Reentrancies | Dec 2019
[Airswap](https://certificate.quantstamp.com/full/airswap) | Missing return value check | Feb 2020
[Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) | Dangerous strict equality | Mar 2020
[E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Missing return value | May 2020
[E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Empty return value | May 2020
[DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Modifier can return the default value | May 2020
[DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Dangerous strict equality allows the contract to be trapped | May 2020
[DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Abi `encodedPacked` collision | May 2020
[EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | `msg.value` is used two times to compute a price | May 2020
[HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Reentrancy | May 2020
[Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) | Dangerous `block.timestamp` usage | Jun 2020
[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | Uninitialized state variable | Jul 2020
[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | State variable shadowing | Jul 2020
[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | Reentrancy | Jul 2020
[Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) | Duplicate contract name | Aug 2020
[PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) | Multiple reentrancies | Aug 2020
[Linkswap](https://certificate.quantstamp.com/full/linkswap) | Lack of return value check | Nov 2020
[Linkswap](https://certificate.quantstamp.com/full/linkswap) | Uninitialized state variable | Nov 2020
[Cryptex](https://certificate.quantstamp.com/full/cryptex) | Lack of return value check | Nov 2020
[Hermez](https://github.com/trailofbits/publications/blob/master/reviews/hermez.pdf) | Reentrancy | Nov 2020
[Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) | Contract locking ethers | Nov 2020
[Idle](https://certificate.quantstamp.com/full/idle-finance) | Dangerous divide before multiply operations | Dec 2020
[RariCapital](https://certificate.quantstamp.com/full/rari-capital) | Lack of return value check | Dec 2020
[RariCapital](https://certificate.quantstamp.com/full/rari-capital) | Uninitialized state variable | Dec 2020
[wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) | Reentrancy | Dec 2020
[Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) | Reentrancy | Jan 2021
[Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) | Variable shadowing | Jan 2021
[OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) | Reentrancy | Jan 2021
Loading…
Cancel
Save