Skip to content

Commit

Permalink
Clear before PR
Browse files Browse the repository at this point in the history
  • Loading branch information
talfao committed Feb 4, 2024
1 parent 145e036 commit b434a75
Show file tree
Hide file tree
Showing 7 changed files with 1,688 additions and 1,767 deletions.
11 changes: 1 addition & 10 deletions slither/detectors/oracles/oracle_data_validation.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
from enum import Enum


from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.oracles.oracle_detector import Oracle, OracleDetector, VarInCondition




from slither.detectors.oracles.oracle_detector import OracleDetector


class OracleDataCheck(OracleDetector):
Expand All @@ -26,8 +19,6 @@ class OracleDataCheck(OracleDetector):
WIKI_EXPLOIT_SCENARIO = "---"
WIKI_RECOMMENDATION = "Validate the data returned by the oracle. For more information visit https://docs.chain.link/data-feeds/api-reference"



# This function is necessary even though there is a detector for unused return values because the variable can be used but will not be validated in conditional statements
def process_not_checked_vars(self):
result = []
Expand Down
23 changes: 3 additions & 20 deletions slither/detectors/oracles/oracle_detector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from slither.analyses.data_dependency.data_dependency import get_dependencies
from slither.core.declarations import Function
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.state_variable import StateVariable
Expand All @@ -8,18 +7,10 @@
from slither.slithir.variables import TupleVariable
from slither.detectors.oracles.supported_oracles.oracle import Oracle, VarInCondition
from slither.detectors.oracles.supported_oracles.chainlink_oracle import ChainlinkOracle
from enum import Enum

class SupportedOracles(Enum):
CHAINLINK = 0
TELLOR = 1



from slither.detectors.oracles.supported_oracles.help_functions import is_internal_call


class OracleDetector(AbstractDetector):

def find_oracles(self, contracts: Contract) -> list[Oracle]:
"""
Detects off-chain oracle contract and VAR
Expand Down Expand Up @@ -49,12 +40,10 @@ def find_oracles(self, contracts: Contract) -> list[Oracle]:
oracles.append(oracle)
return oracles


def generate_oracle(self, ir: Operation) -> Oracle:
if ChainlinkOracle().is_instance_of(ir):
return ChainlinkOracle()
return None


# This function was inspired by detector unused return values
def oracle_call(self, function: FunctionContract):
Expand Down Expand Up @@ -122,7 +111,6 @@ def map_condition_to_var(self, var, function: FunctionContract):
nodes.append(node)
return nodes


# Check if the vars occurs in require/assert statement or in conditional node
def vars_in_conditions(self, oracle: Oracle) -> bool:
vars_in_condition = []
Expand Down Expand Up @@ -161,12 +149,7 @@ def map_param_to_var(self, var, function: FunctionContract):
for var2 in origin_vars:
if var2 == var:
return param

def is_internal_call(self, node):
for ir in node.irs:
if isinstance(ir, InternalCall):
return True
return False
return None

# This function interates through all internal calls in function and checks if the var is used in condition any of them
def investigate_internal_call(self, function: FunctionContract, var) -> bool:
Expand All @@ -185,7 +168,7 @@ def investigate_internal_call(self, function: FunctionContract, var) -> bool:
if (
node.is_conditional()
and self.check_var_condition_match(original_var_as_param, node)
and not self.is_internal_call(node)
and not is_internal_call(node)
):
conditions.append(node)
if len(conditions) > 0:
Expand Down
62 changes: 0 additions & 62 deletions slither/detectors/oracles/oracle_slot0.py

This file was deleted.

22 changes: 10 additions & 12 deletions slither/detectors/oracles/supported_oracles/chainlink_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
)

from slither.slithir.variables.constant import Constant
from slither.detectors.oracles.supported_oracles.help_functions import check_revert, return_boolean


CHAINLINK_ORACLE_CALLS = [
"latestRoundData",
"getRoundData",
]


CHAINLINK_ORACLE_CALLS = ["latestRoundData","getRoundData",]
class ChainlinkVars(Enum):
ROUNDID = 0
ANSWER = 1
Expand All @@ -22,7 +28,6 @@ def __init__(self):
super().__init__(CHAINLINK_ORACLE_CALLS)
self.oracle_type = "Chainlink"


# This function checks if the updatedAt value is validated.
def check_staleness(self, var: VarInCondition) -> bool:
if var is None:
Expand All @@ -48,14 +53,10 @@ def check_RoundId(self, var: VarInCondition, var2: VarInCondition) -> bool:
elif ir.type in (BinaryType.LESS, BinaryType.LESS_EQUAL):
if ir.variable_right == var2.var and ir.variable_left == var.var:
return True
if self.check_revert(node):
return True
elif self.return_boolean(node):
return True
return check_revert(node) or return_boolean(node)

return False


# This functions validates checks of price value
def check_price(self, var: VarInCondition) -> bool:
if var is None:
Expand All @@ -75,10 +76,7 @@ def check_price(self, var: VarInCondition) -> bool:
if ir.variable_left.value == 0:
return True
# If the conditions does not match we are looking for revert or return node
if self.check_revert(node):
return True
elif self.return_boolean(node):
return True
return check_revert(node) or return_boolean(node)

return False

Expand Down Expand Up @@ -149,4 +147,4 @@ def naive_data_validation(self):
if self.is_sequencer_check(vars_order[ChainlinkVars.ANSWER.value], var):
problems = []
break
return problems
return problems
30 changes: 30 additions & 0 deletions slither/detectors/oracles/supported_oracles/help_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from slither.core.cfg.node import Node, NodeType
from slither.slithir.operations.return_operation import Return
from slither.slithir.operations import InternalCall
from slither.slithir.operations.solidity_call import SolidityCall

# Helpfull functions
def check_revert(node: Node) -> bool:
for n in node.sons:
if n.type == NodeType.EXPRESSION:
for ir in n.irs:
if isinstance(ir, SolidityCall):
if "revert" in ir.function.name:
return True
return False


def return_boolean(node: Node) -> bool:
for n in node.sons:
if n.type == NodeType.RETURN:
for ir in n.irs:
if isinstance(ir, Return):
return True
return False


def is_internal_call(node):
for ir in node.irs:
if isinstance(ir, InternalCall):
return True
return False
57 changes: 18 additions & 39 deletions slither/detectors/oracles/supported_oracles/oracle.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
from slither.slithir.operations import HighLevelCall, Operation
from slither.core.declarations import Function
from slither.core.cfg.node import Node, NodeType
from slither.slithir.operations.return_operation import Return
from slither.slithir.operations.solidity_call import SolidityCall

class VarInCondition: # This class was created to store variable and all conditional nodes where it is used
# This class was created to store variable and all conditional nodes where it is used
class VarInCondition:
def __init__(self, _var, _nodes):
self.var = _var
self.nodes_with_var = _nodes

class Oracle:
def __init__(
self,
_calls
):

class Oracle: # pylint: disable=too-few-public-methods
def __init__(self, _calls):
self.calls = _calls
self.contract = None
self.function = None
Expand All @@ -28,23 +24,20 @@ def __init__(

def get_calls(self):
return self.calls


def is_instance_of(self, ir: Operation) -> bool:
return isinstance(ir, HighLevelCall) and (
isinstance(ir.function, Function) and self.compare_call(ir.function.name)
)

def set_node(self, _node):
self.node = _node

def compare_call(self, function) -> bool:
for call in self.calls:
if call in str(function):
return True
return False

def is_instance_of(self, ir: Operation) -> bool:
return isinstance(ir, HighLevelCall) and (
isinstance(ir.function, Function)
and self.compare_call(
ir.function.name
)
)

def set_data(self, _contract, _function, _returned_vars_indexes, _interface, _oracle_api):
self.contract = _contract
Expand All @@ -56,27 +49,13 @@ def set_data(self, _contract, _function, _returned_vars_indexes, _interface, _or
# Data validation helpful functions
def naive_data_validation(self):
return []

def check_price(self, var: VarInCondition) -> bool:
if var is None:
return False
return True

def check_staleness(self, var: VarInCondition) -> bool:
if var is None:
return False
return True


def check_revert(self, node: Node) -> bool:
for n in node.sons:
if n.type == NodeType.EXPRESSION:
for ir in n.irs:
if isinstance(ir, SolidityCall):
if "revert" in ir.function.name:
return True
return False

def return_boolean(self, node: Node) -> bool:
for n in node.sons:
if n.type == NodeType.RETURN:
for ir in n.irs:
if isinstance(ir, Return):
return True

Loading

0 comments on commit b434a75

Please sign in to comment.