Repository: crytic/slither

Issue:
Add "now" to the timestamp detector
https://github.com/crytic/slither/blob/7cb6cf4870036f780088fa7dfec83ae3220322e2/slither/detectors/operations/block_timestamp.py#L39-L44

This could also warns about the use of `now`


Discussion:

Resolving patch:
diff --git a/slither/detectors/operations/block_timestamp.py b/slither/detectors/operations/block_timestamp.py
--- a/slither/detectors/operations/block_timestamp.py
+++ b/slither/detectors/operations/block_timestamp.py
@@ -2,15 +2,51 @@
     Module detecting dangerous use of block.timestamp
 
 """
-from slither.core.declarations import Function
-from slither.analyses.data_dependency.data_dependency import is_tainted, is_dependent
-from slither.core.declarations.solidity_variables import (SolidityFunction,
-                                                          SolidityVariableComposed)
+from typing import List, Tuple
+
+from slither.analyses.data_dependency.data_dependency import is_dependent
+from slither.core.cfg.node import Node
+from slither.core.declarations import Function, Contract
+from slither.core.declarations.solidity_variables import (SolidityVariableComposed, SolidityVariable)
 from slither.detectors.abstract_detector import (AbstractDetector,
                                                  DetectorClassification)
 from slither.slithir.operations import Binary, BinaryType
 
 
+def _timestamp(func: Function) -> List[Node]:
+    ret = set()
+    for node in func.nodes:
+        if node.contains_require_or_assert():
+            for var in node.variables_read:
+                if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract):
+                    ret.add(node)
+                if is_dependent(var, SolidityVariable('now'), func.contract):
+                    ret.add(node)
+        for ir in node.irs:
+            if isinstance(ir, Binary) and BinaryType.return_bool(ir.type):
+                for var in ir.read:
+                    if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract):
+                        ret.add(node)
+                    if is_dependent(var, SolidityVariable('now'), func.contract):
+                        ret.add(node)
+    return list(ret)
+
+
+def _detect_dangerous_timestamp(contract: Contract) -> List[Tuple[Function, List[Node]]]:
+    """
+    Args:
+        contract (Contract)
+    Returns:
+        list((Function), (list (Node)))
+    """
+    ret = []
+    for f in [f for f in contract.functions if f.contract_declarer == contract]:
+        nodes = _timestamp(f)
+        if nodes:
+            ret.append((f, nodes))
+    return ret
+
+
 class Timestamp(AbstractDetector):
     """
     """
@@ -22,51 +58,18 @@ class Timestamp(AbstractDetector):
 
     WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#block-timestamp'
 
-
     WIKI_TITLE = 'Block timestamp'
     WIKI_DESCRIPTION = 'Dangerous usage of `block.timestamp`. `block.timestamp` can be manipulated by miners.'
     WIKI_EXPLOIT_SCENARIO = '''"Bob's contract relies on `block.timestamp` for its randomness. Eve is a miner and manipulates `block.timestamp` to exploit Bob's contract.'''
     WIKI_RECOMMENDATION = 'Avoid relying on `block.timestamp`.'
 
-    def timestamp(self, func):
-        """
-        """
-
-        ret = set()
-        for node in func.nodes:
-            if node.contains_require_or_assert():
-                for var in node.variables_read:
-                    if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract):
-                        ret.add(node)
-            for ir in node.irs:
-                if isinstance(ir, Binary) and BinaryType.return_bool(ir.type):
-                    for var in ir.read:
-                        if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract):
-                            ret.add(node)
-        return list(ret)
-
-
-    def detect_dangerous_timestamp(self, contract):
-        """
-        Args:
-            contract (Contract)
-        Returns:
-            list((Function), (list (Node)))
-        """
-        ret = []
-        for f in [f for f in contract.functions if f.contract_declarer == contract]:
-            nodes = self.timestamp(f)
-            if nodes:
-                ret.append((f, nodes))
-        return ret
-
     def _detect(self):
         """
         """
         results = []
 
         for c in self.contracts:
-            dangerous_timestamp = self.detect_dangerous_timestamp(c)
+            dangerous_timestamp = _detect_dangerous_timestamp(c)
             for (func, nodes) in dangerous_timestamp:
 
                 info = [func, " uses timestamp for comparisons\n"]


Test patch: