|
|
|
"""
|
|
|
|
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 solc_select import solc_select
|
|
|
|
|
|
|
|
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
|
|
|
|
solc_select.switch_global_version("0.6.12", always_install=True)
|
|
|
|
slither = Slither("tests/test_function.sol")
|
|
|
|
functions = slither.get_contract_from_name("TestFunction")[0].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():
|
|
|
|
solc_select.switch_global_version("0.6.12", always_install=True)
|
|
|
|
slither = Slither("tests/test_function.sol")
|
|
|
|
compilation_unit = slither.compilation_units[0]
|
|
|
|
functions = compilation_unit.get_contract_from_name("TestFunctionCanSendEth")[
|
|
|
|
0
|
|
|
|
].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
|
|
|
|
|
|
|
|
|
|
|
|
def test_reentrant():
|
|
|
|
solc_select.switch_global_version("0.8.10", always_install=True)
|
|
|
|
slither = Slither("tests/test_function_reentrant.sol")
|
|
|
|
compilation_unit = slither.compilation_units[0]
|
|
|
|
functions = compilation_unit.get_contract_from_name("TestReentrant")[
|
|
|
|
0
|
|
|
|
].available_functions_as_dict()
|
|
|
|
|
|
|
|
assert functions["is_reentrant()"].is_reentrant
|
|
|
|
assert not functions["is_non_reentrant()"].is_reentrant
|
|
|
|
assert not functions["internal_and_not_reentrant()"].is_reentrant
|
|
|
|
assert not functions["internal_and_not_reentrant2()"].is_reentrant
|
|
|
|
assert functions["internal_and_could_be_reentrant()"].is_reentrant
|
|
|
|
assert functions["internal_and_reentrant()"].is_reentrant
|
|
|
|
|
|
|
|
|
|
|
|
def test_public_variable() -> None:
|
|
|
|
solc_select.switch_global_version("0.6.12", always_install=True)
|
|
|
|
slither = Slither("tests/test_function.sol")
|
|
|
|
contracts = slither.get_contract_from_name("TestFunction")
|
|
|
|
assert len(contracts) == 1
|
|
|
|
contract = contracts[0]
|
|
|
|
var = contract.get_state_variable_from_name("info")
|
|
|
|
assert var
|
|
|
|
assert var.solidity_signature == "info()"
|
|
|
|
assert var.signature_str == "info() returns(bytes32)"
|
|
|
|
assert var.visibility == "public"
|
|
|
|
assert var.type == ElementaryType("bytes32")
|