Skip to content

Commit 61fa9ec

Browse files
authored
Merge pull request #2616 from nisedo/dev
Add entry-points printer to identify all externally accessible state-changing functions
2 parents cacf6f6 + 0d2d548 commit 61fa9ec

File tree

3 files changed

+100
-4
lines changed

3 files changed

+100
-4
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,11 @@ For more information, see
232232

233233
### Quick Review Printers
234234

235-
* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#human-summary)
236-
* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph)
237-
* `contract-summary`: [Print a summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary)
238-
* `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/crytic/slither/wiki/Printer-documentation#loc)
235+
* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#human-summary)
236+
* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph)
237+
* `contract-summary`: [Print a summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#contract-summary)
238+
* `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/trailofbits/slither/wiki/Printer-documentation#loc)
239+
* `entry-points`: [Print all the state-changing entry point functions of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points)
239240

240241
### In-Depth Review Printers
241242

slither/printers/all_printers.py

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
from .functions.dominator import Dominator
2626
from .summary.martin import Martin
2727
from .summary.cheatcodes import CheatcodePrinter
28+
from .summary.entry_points import PrinterEntryPoints
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""
2+
Module printing all the state-changing entry point functions of the contracts
3+
"""
4+
5+
from slither.printers.abstract_printer import AbstractPrinter
6+
from slither.core.declarations.function_contract import FunctionContract
7+
from slither.utils.colors import Colors
8+
from slither.utils.output import Output
9+
from slither.utils.myprettytable import MyPrettyTable
10+
11+
12+
class PrinterEntryPoints(AbstractPrinter):
13+
14+
ARGUMENT = "entry-points"
15+
HELP = "Print all the state-changing entry point functions of the contracts"
16+
17+
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points"
18+
19+
def output(self, _filename) -> Output:
20+
"""
21+
_filename is not used
22+
Args:
23+
_filename(string)
24+
"""
25+
all_contracts = []
26+
27+
for contract in sorted(
28+
(
29+
c
30+
for c in self.contracts
31+
if not c.is_interface
32+
and not c.is_library
33+
and not c.is_abstract
34+
and "lib/" not in c.source_mapping.filename.absolute
35+
and "node_modules/" not in c.source_mapping.filename.absolute
36+
and not any(
37+
mock in c.source_mapping.filename.absolute.lower() for mock in ["mock", "mocks"]
38+
)
39+
),
40+
key=lambda x: x.name,
41+
):
42+
entry_points = [
43+
f
44+
for f in contract.functions
45+
if (
46+
f.visibility in ["public", "external"]
47+
and isinstance(f, FunctionContract)
48+
and not f.is_constructor
49+
and not f.view
50+
and not f.pure
51+
and not f.contract_declarer.is_interface
52+
and not f.contract_declarer.is_library
53+
and not f.is_shadowed
54+
)
55+
]
56+
57+
if not entry_points:
58+
continue
59+
60+
table = MyPrettyTable(["Function", "Modifiers", "Inherited From"])
61+
contract_info = [
62+
f"\nContract {Colors.BOLD}{Colors.YELLOW}{contract.name}{Colors.END}"
63+
f" ({contract.source_mapping})"
64+
]
65+
66+
for f in sorted(
67+
entry_points,
68+
key=lambda x: (x.visibility != "external", x.visibility != "public", x.full_name),
69+
):
70+
modifier_list = [m.name for m in f.modifiers]
71+
if f.payable:
72+
modifier_list.append("payable")
73+
modifiers = ", ".join(modifier_list) if modifier_list else ""
74+
inherited = f"{f.contract_declarer.name}" if f.contract_declarer != contract else ""
75+
76+
name_parts = f.full_name.split("(", 1)
77+
function_name = (
78+
f"{Colors.BOLD}{Colors.RED}{name_parts[0]}{Colors.END}" f"({name_parts[1]}"
79+
)
80+
81+
table.add_row(
82+
[
83+
function_name,
84+
f"{Colors.GREEN}{modifiers}{Colors.END}" if modifiers else "",
85+
f"{Colors.MAGENTA}{inherited}{Colors.END}" if inherited else "",
86+
]
87+
)
88+
89+
contract_info.append(str(table))
90+
all_contracts.append("\n".join(contract_info))
91+
92+
info = "\n".join(all_contracts) if all_contracts else ""
93+
self.info(info)
94+
return self.generate_output(info)

0 commit comments

Comments
 (0)