mirror of https://github.com/crytic/slither
parent
c9fa73b216
commit
bfe38cfd79
@ -0,0 +1,17 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
|
||||
from slither import Slither |
||||
from slither.utils.arithmetic import unchecked_arithemtic_usage |
||||
|
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" / "arithmetic_usage" |
||||
|
||||
|
||||
def test_arithmetic_usage() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(TEST_DATA_DIR, "test.sol").as_posix()) |
||||
|
||||
assert { |
||||
f.source_mapping.content_hash for f in unchecked_arithemtic_usage(slither.contracts[0]) |
||||
} == {"2b4bc73cf59d486dd9043e840b5028b679354dd9", "e4ecd4d0fda7e762d29aceb8425f2c5d4d0bf962"} |
@ -0,0 +1,60 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
|
||||
from slither import Slither |
||||
|
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
CUSTOM_COMMENTS_TEST_DATA_DIR = Path(TEST_DATA_DIR, "custom_comments") |
||||
|
||||
|
||||
def test_upgradeable_comments() -> None: |
||||
solc_select.switch_global_version("0.8.10", always_install=True) |
||||
slither = Slither(Path(CUSTOM_COMMENTS_TEST_DATA_DIR, "upgrade.sol").as_posix()) |
||||
compilation_unit = slither.compilation_units[0] |
||||
proxy = compilation_unit.get_contract_from_name("Proxy")[0] |
||||
|
||||
assert proxy.is_upgradeable_proxy |
||||
|
||||
v0 = compilation_unit.get_contract_from_name("V0")[0] |
||||
|
||||
assert v0.is_upgradeable |
||||
print(v0.upgradeable_version) |
||||
assert v0.upgradeable_version == "version-0" |
||||
|
||||
v1 = compilation_unit.get_contract_from_name("V1")[0] |
||||
assert v0.is_upgradeable |
||||
assert v1.upgradeable_version == "version_1" |
||||
|
||||
|
||||
def test_contract_comments() -> None: |
||||
comments = " @title Test Contract\n @dev Test comment" |
||||
|
||||
solc_select.switch_global_version("0.8.10", always_install=True) |
||||
slither = Slither(Path(CUSTOM_COMMENTS_TEST_DATA_DIR, "contract_comment.sol").as_posix()) |
||||
compilation_unit = slither.compilation_units[0] |
||||
contract = compilation_unit.get_contract_from_name("A")[0] |
||||
|
||||
assert contract.comments == comments |
||||
|
||||
# Old solc versions have a different parsing of comments |
||||
# the initial space (after *) is also not kept on every line |
||||
comments = "@title Test Contract\n@dev Test comment" |
||||
solc_select.switch_global_version("0.5.16", always_install=True) |
||||
slither = Slither(Path(CUSTOM_COMMENTS_TEST_DATA_DIR, "contract_comment.sol").as_posix()) |
||||
compilation_unit = slither.compilation_units[0] |
||||
contract = compilation_unit.get_contract_from_name("A")[0] |
||||
|
||||
assert contract.comments == comments |
||||
|
||||
# Test with legacy AST |
||||
comments = "@title Test Contract\n@dev Test comment" |
||||
solc_select.switch_global_version("0.5.16", always_install=True) |
||||
slither = Slither( |
||||
Path(CUSTOM_COMMENTS_TEST_DATA_DIR, "contract_comment.sol").as_posix(), |
||||
solc_force_legacy_json=True, |
||||
) |
||||
compilation_unit = slither.compilation_units[0] |
||||
contract = compilation_unit.get_contract_from_name("A")[0] |
||||
|
||||
assert contract.comments == comments |
@ -0,0 +1,106 @@ |
||||
from pathlib import Path |
||||
from slither import Slither |
||||
from slither.visitors.expression.constants_folding import ConstantFolding |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
CONSTANT_FOLDING_TEST_ROOT = Path(TEST_DATA_DIR, "constant_folding") |
||||
|
||||
|
||||
def test_constant_folding_unary(): |
||||
file = Path(CONSTANT_FOLDING_TEST_ROOT, "constant_folding_unary.sol").as_posix() |
||||
Slither(file) |
||||
|
||||
|
||||
def test_constant_folding_rational(): |
||||
s = Slither(Path(CONSTANT_FOLDING_TEST_ROOT, "constant_folding_rational.sol").as_posix()) |
||||
contract = s.get_contract_from_name("C")[0] |
||||
|
||||
variable_a = contract.get_state_variable_from_name("a") |
||||
assert str(variable_a.type) == "uint256" |
||||
assert str(ConstantFolding(variable_a.expression, "uint256").result()) == "10" |
||||
|
||||
variable_b = contract.get_state_variable_from_name("b") |
||||
assert str(variable_b.type) == "int128" |
||||
assert str(ConstantFolding(variable_b.expression, "int128").result()) == "2" |
||||
|
||||
variable_c = contract.get_state_variable_from_name("c") |
||||
assert str(variable_c.type) == "int64" |
||||
assert str(ConstantFolding(variable_c.expression, "int64").result()) == "3" |
||||
|
||||
variable_d = contract.get_state_variable_from_name("d") |
||||
assert str(variable_d.type) == "int256" |
||||
assert str(ConstantFolding(variable_d.expression, "int256").result()) == "1500" |
||||
|
||||
variable_e = contract.get_state_variable_from_name("e") |
||||
assert str(variable_e.type) == "uint256" |
||||
assert ( |
||||
str(ConstantFolding(variable_e.expression, "uint256").result()) |
||||
== "57896044618658097711785492504343953926634992332820282019728792003956564819968" |
||||
) |
||||
|
||||
variable_f = contract.get_state_variable_from_name("f") |
||||
assert str(variable_f.type) == "uint256" |
||||
assert ( |
||||
str(ConstantFolding(variable_f.expression, "uint256").result()) |
||||
== "115792089237316195423570985008687907853269984665640564039457584007913129639935" |
||||
) |
||||
|
||||
variable_g = contract.get_state_variable_from_name("g") |
||||
assert str(variable_g.type) == "int64" |
||||
assert str(ConstantFolding(variable_g.expression, "int64").result()) == "-7" |
||||
|
||||
|
||||
def test_constant_folding_binary_expressions(): |
||||
sl = Slither(Path(CONSTANT_FOLDING_TEST_ROOT, "constant_folding_binop.sol").as_posix()) |
||||
contract = sl.get_contract_from_name("BinOp")[0] |
||||
|
||||
variable_a = contract.get_state_variable_from_name("a") |
||||
assert str(variable_a.type) == "uint256" |
||||
assert str(ConstantFolding(variable_a.expression, "uint256").result()) == "0" |
||||
|
||||
variable_b = contract.get_state_variable_from_name("b") |
||||
assert str(variable_b.type) == "uint256" |
||||
assert str(ConstantFolding(variable_b.expression, "uint256").result()) == "3" |
||||
|
||||
variable_c = contract.get_state_variable_from_name("c") |
||||
assert str(variable_c.type) == "uint256" |
||||
assert str(ConstantFolding(variable_c.expression, "uint256").result()) == "3" |
||||
|
||||
variable_d = contract.get_state_variable_from_name("d") |
||||
assert str(variable_d.type) == "bool" |
||||
assert str(ConstantFolding(variable_d.expression, "bool").result()) == "False" |
||||
|
||||
variable_e = contract.get_state_variable_from_name("e") |
||||
assert str(variable_e.type) == "bool" |
||||
assert str(ConstantFolding(variable_e.expression, "bool").result()) == "False" |
||||
|
||||
variable_f = contract.get_state_variable_from_name("f") |
||||
assert str(variable_f.type) == "bool" |
||||
assert str(ConstantFolding(variable_f.expression, "bool").result()) == "True" |
||||
|
||||
variable_g = contract.get_state_variable_from_name("g") |
||||
assert str(variable_g.type) == "bool" |
||||
assert str(ConstantFolding(variable_g.expression, "bool").result()) == "False" |
||||
|
||||
variable_h = contract.get_state_variable_from_name("h") |
||||
assert str(variable_h.type) == "bool" |
||||
assert str(ConstantFolding(variable_h.expression, "bool").result()) == "False" |
||||
|
||||
variable_i = contract.get_state_variable_from_name("i") |
||||
assert str(variable_i.type) == "bool" |
||||
assert str(ConstantFolding(variable_i.expression, "bool").result()) == "True" |
||||
|
||||
variable_j = contract.get_state_variable_from_name("j") |
||||
assert str(variable_j.type) == "bool" |
||||
assert str(ConstantFolding(variable_j.expression, "bool").result()) == "False" |
||||
|
||||
variable_k = contract.get_state_variable_from_name("k") |
||||
assert str(variable_k.type) == "bool" |
||||
assert str(ConstantFolding(variable_k.expression, "bool").result()) == "True" |
||||
|
||||
variable_l = contract.get_state_variable_from_name("l") |
||||
assert str(variable_l.type) == "uint256" |
||||
assert ( |
||||
str(ConstantFolding(variable_l.expression, "uint256").result()) |
||||
== "115792089237316195423570985008687907853269984665640564039457584007913129639935" |
||||
) |
@ -0,0 +1,43 @@ |
||||
import inspect |
||||
from pathlib import Path |
||||
import pytest |
||||
|
||||
from crytic_compile import CryticCompile |
||||
from crytic_compile.platform.solc_standard_json import SolcStandardJson |
||||
from solc_select import solc_select |
||||
|
||||
from slither import Slither |
||||
from slither.core.variables.state_variable import StateVariable |
||||
from slither.detectors import all_detectors |
||||
from slither.detectors.abstract_detector import AbstractDetector |
||||
from slither.slithir.operations import InternalCall, LibraryCall |
||||
from slither.utils.arithmetic import unchecked_arithemtic_usage |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
CONTRACT_DECL_TEST_ROOT = Path(TEST_DATA_DIR, "contract_declaration") |
||||
|
||||
|
||||
def test_abstract_contract() -> None: |
||||
solc_select.switch_global_version("0.8.0", always_install=True) |
||||
slither = Slither(Path(CONTRACT_DECL_TEST_ROOT, "abstract.sol").as_posix()) |
||||
assert not slither.contracts[0].is_fully_implemented |
||||
|
||||
solc_select.switch_global_version("0.5.0", always_install=True) |
||||
slither = Slither(Path(CONTRACT_DECL_TEST_ROOT, "implicit_abstract.sol").as_posix()) |
||||
assert not slither.contracts[0].is_fully_implemented |
||||
|
||||
slither = Slither( |
||||
Path(CONTRACT_DECL_TEST_ROOT, "implicit_abstract.sol").as_posix(), |
||||
solc_force_legacy_json=True, |
||||
) |
||||
assert not slither.contracts[0].is_fully_implemented |
||||
|
||||
|
||||
def test_private_variable() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(CONTRACT_DECL_TEST_ROOT, "private_variable.sol").as_posix()) |
||||
contract_c = slither.get_contract_from_name("C")[0] |
||||
f = contract_c.functions[0] |
||||
var_read = f.variables_read[0] |
||||
assert isinstance(var_read, StateVariable) |
||||
assert str(var_read.contract) == "B" |
@ -0,0 +1,29 @@ |
||||
function protected(uint a, uint b) returns(uint){ |
||||
return (a + b) * (a + b); |
||||
} |
||||
|
||||
function not_protected_asm(uint a, uint b) returns(uint){ |
||||
uint c; |
||||
assembly{ |
||||
c := mul(add(a,b), add(a,b)) |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
function not_protected_unchecked(uint a, uint b) returns(uint){ |
||||
uint c; |
||||
unchecked{ |
||||
return (a + b) * (a + b); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract A{ |
||||
|
||||
function f(uint a, uint b) public{ |
||||
protected(a,b); |
||||
not_protected_asm(a, b); |
||||
not_protected_unchecked(a, b); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,88 @@ |
||||
pragma solidity ^0.4.24; |
||||
|
||||
contract Complex { |
||||
int numberOfSides = 7; |
||||
string shape; |
||||
uint i0 = 0; |
||||
uint i1 = 0; |
||||
uint i2 = 0; |
||||
uint i3 = 0; |
||||
uint i4 = 0; |
||||
uint i5 = 0; |
||||
uint i6 = 0; |
||||
uint i7 = 0; |
||||
uint i8 = 0; |
||||
uint i9 = 0; |
||||
uint i10 = 0; |
||||
|
||||
|
||||
function computeShape() external { |
||||
if (numberOfSides <= 2) { |
||||
shape = "Cant be a shape!"; |
||||
} else if (numberOfSides == 3) { |
||||
shape = "Triangle"; |
||||
} else if (numberOfSides == 4) { |
||||
shape = "Square"; |
||||
} else if (numberOfSides == 5) { |
||||
shape = "Pentagon"; |
||||
} else if (numberOfSides == 6) { |
||||
shape = "Hexagon"; |
||||
} else if (numberOfSides == 7) { |
||||
shape = "Heptagon"; |
||||
} else if (numberOfSides == 8) { |
||||
shape = "Octagon"; |
||||
} else if (numberOfSides == 9) { |
||||
shape = "Nonagon"; |
||||
} else if (numberOfSides == 10) { |
||||
shape = "Decagon"; |
||||
} else if (numberOfSides == 11) { |
||||
shape = "Hendecagon"; |
||||
} else { |
||||
shape = "Your shape is more than 11 sides."; |
||||
} |
||||
} |
||||
|
||||
function complexExternalWrites() external { |
||||
Increment test1 = new Increment(); |
||||
test1.increaseBy1(); |
||||
test1.increaseBy1(); |
||||
test1.increaseBy1(); |
||||
test1.increaseBy1(); |
||||
test1.increaseBy1(); |
||||
|
||||
Increment test2 = new Increment(); |
||||
test2.increaseBy1(); |
||||
|
||||
address test3 = new Increment(); |
||||
test3.call(bytes4(keccak256("increaseBy2()"))); |
||||
|
||||
address test4 = new Increment(); |
||||
test4.call(bytes4(keccak256("increaseBy2()"))); |
||||
} |
||||
|
||||
function complexStateVars() external { |
||||
i0 = 1; |
||||
i1 = 1; |
||||
i2 = 1; |
||||
i3 = 1; |
||||
i4 = 1; |
||||
i5 = 1; |
||||
i6 = 1; |
||||
i7 = 1; |
||||
i8 = 1; |
||||
i9 = 1; |
||||
i10 = 1; |
||||
} |
||||
} |
||||
|
||||
contract Increment { |
||||
uint i = 0; |
||||
|
||||
function increaseBy1() public { |
||||
i += 1; |
||||
} |
||||
|
||||
function increaseBy2() public { |
||||
i += 2; |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
contract BinOp { |
||||
uint a = 1 & 2; |
||||
uint b = 1 ^ 2; |
||||
uint c = 1 | 2; |
||||
bool d = 2 < 1; |
||||
bool e = 1 > 2; |
||||
bool f = 1 <= 2; |
||||
bool g = 1 >= 2; |
||||
bool h = 1 == 2; |
||||
bool i = 1 != 2; |
||||
bool j = true && false; |
||||
bool k = true || false; |
||||
uint l = uint(1) - uint(2); |
||||
} |
@ -0,0 +1,9 @@ |
||||
contract C { |
||||
uint256 constant a = 2.5 + 7 + 0.5; |
||||
int128 b = 6 / 3.0; |
||||
int64 constant c = 5 * 0.5 + 0.5; |
||||
int256 d = 1e3 + 5E2; |
||||
uint256 e = 2 ** 255; |
||||
uint256 f = 115792089237316195423570985008687907853269984665640564039457584_007_913_129_639_935; |
||||
int64 constant g = -7.0; |
||||
} |
@ -0,0 +1,7 @@ |
||||
contract C { |
||||
int8 constant a = -7; |
||||
function f() public pure { |
||||
uint[-a] memory x; |
||||
x[0] = 2; |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
pragma solidity ^0.8.0; |
||||
|
||||
abstract contract ExplicitAbstract{ |
||||
function f() virtual public; |
||||
} |
@ -0,0 +1,5 @@ |
||||
pragma solidity ^0.5.0; |
||||
|
||||
contract ImplicitAbstract{ |
||||
function f() public; |
||||
} |
@ -0,0 +1,13 @@ |
||||
contract A{ |
||||
uint private v = 10; |
||||
} |
||||
|
||||
contract B{ |
||||
uint v = 20; |
||||
} |
||||
|
||||
contract C is B, A{ |
||||
function f() public view returns(uint) { |
||||
return v; |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
/** |
||||
* @title Test Contract |
||||
* @dev Test comment |
||||
*/ |
||||
contract A{ |
||||
|
||||
} |
@ -0,0 +1,16 @@ |
||||
/// @custom:security isDelegatecallProxy |
||||
contract Proxy{ |
||||
|
||||
} |
||||
|
||||
/// @custom:security isUpgradeable |
||||
/// @custom:version name=version-0 |
||||
contract V0{ |
||||
|
||||
} |
||||
|
||||
/// @custom:security isUpgradeable |
||||
/// @custom:version name=version_1 |
||||
contract V1{ |
||||
|
||||
} |
@ -0,0 +1,27 @@ |
||||
contract ContractWithDeprecatedReferences { |
||||
bytes32 globalBlockHash = block.blockhash(0); |
||||
|
||||
// Deprecated: Change constant -> view |
||||
function functionWithDeprecatedThrow() public constant { |
||||
// Deprecated: Change msg.gas -> gasleft() |
||||
if(msg.gas == msg.value) { |
||||
// Deprecated: Change throw -> revert() |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
// Deprecated: Change constant -> view |
||||
function functionWithDeprecatedReferences() public constant { |
||||
// Deprecated: Change sha3() -> keccak256() |
||||
bytes32 sha3Result = sha3("test deprecated sha3 usage"); |
||||
|
||||
// Deprecated: Change block.blockhash() -> blockhash() |
||||
bytes32 blockHashResult = block.blockhash(0); |
||||
|
||||
// Deprecated: Change callcode() -> delegatecall() |
||||
address(this).callcode(); |
||||
|
||||
// Deprecated: Change suicide() -> selfdestruct() |
||||
suicide(address(0)); |
||||
} |
||||
} |
@ -0,0 +1,130 @@ |
||||
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; |
||||
bytes32 public info; |
||||
|
||||
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,36 @@ |
||||
contract TestReentrant{ |
||||
|
||||
modifier nonReentrant(){ |
||||
_; |
||||
} |
||||
|
||||
function is_reentrant() public{ |
||||
internal_and_could_be_reentrant(); |
||||
internal_and_reentrant(); |
||||
} |
||||
|
||||
function is_non_reentrant() nonReentrant() public{ |
||||
internal_and_could_be_reentrant(); |
||||
internal_and_not_reentrant2(); |
||||
} |
||||
|
||||
function internal_and_not_reentrant() nonReentrant() internal{ |
||||
|
||||
} |
||||
|
||||
function internal_and_not_reentrant2() internal{ |
||||
|
||||
} |
||||
|
||||
// Called by a protected and unprotected function |
||||
function internal_and_could_be_reentrant() internal{ |
||||
|
||||
} |
||||
|
||||
// Called by a protected and unprotected function |
||||
function internal_and_reentrant() internal{ |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,100 @@ |
||||
contract TestContractVar { |
||||
|
||||
} |
||||
|
||||
contract A { |
||||
uint public public_var = 1; |
||||
uint internal private_var = 1; |
||||
TestContractVar public public_contract; |
||||
TestContractVar internal private_contract; |
||||
|
||||
uint public shadowed_public_var = 1; |
||||
uint internal shadowed_private_var = 1; |
||||
TestContractVar public shadowed_public_contract; |
||||
TestContractVar internal shadowed_private_contract; |
||||
|
||||
function getValue() public pure returns (uint) { |
||||
return 0; |
||||
} |
||||
function notRedefined() public returns (uint) { |
||||
return getValue(); |
||||
} |
||||
|
||||
modifier testModifier { |
||||
assert(true); |
||||
_; |
||||
} |
||||
function testFunction() testModifier public returns (uint) { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
contract B is A { |
||||
// This function overshadows A directly, and overshadows C indirectly (via 'G'->'D') |
||||
function getValue() public pure returns (uint) { |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
contract Good is A, B { |
||||
|
||||
} |
||||
|
||||
contract C is A { |
||||
|
||||
// This function overshadows A directly, and overshadows B indirectly (via 'G') |
||||
function getValue() public pure returns (uint) { |
||||
return super.getValue() + 1; |
||||
} |
||||
} |
||||
|
||||
contract D is B { |
||||
// This should overshadow A's definitions. |
||||
uint public shadowed_public_var = 2; |
||||
uint internal shadowed_private_var = 2; |
||||
TestContractVar public shadowed_public_contract; |
||||
TestContractVar internal shadowed_private_contract; |
||||
} |
||||
|
||||
contract E { |
||||
// Variables cannot indirectly shadow, so this should not be counted. |
||||
uint public public_var = 2; |
||||
uint internal private_var = 2; |
||||
TestContractVar public public_contract; |
||||
TestContractVar internal private_contract; |
||||
|
||||
// This should overshadow A's definition indirectly (via 'G'). |
||||
modifier testModifier { |
||||
assert(false); |
||||
_; |
||||
} |
||||
} |
||||
|
||||
contract F is B { |
||||
// This should overshadow A's definitions. |
||||
uint public shadowed_public_var = 2; |
||||
uint internal shadowed_private_var = 2; |
||||
TestContractVar public shadowed_public_contract; |
||||
TestContractVar internal shadowed_private_contract; |
||||
|
||||
// This should overshadow B's definition directly, as well as B's and C's indirectly (via 'G') |
||||
// (graph only outputs directly if both, so B direct and C indirect should be reported). |
||||
function getValue() public pure returns (uint) { |
||||
return 1; |
||||
} |
||||
|
||||
// This should indirectly shadow definition in A directly, and E indirectly (via 'G') |
||||
modifier testModifier { |
||||
assert(false); |
||||
_; |
||||
} |
||||
} |
||||
|
||||
contract G is B, C, D, E, F { |
||||
// This should overshadow definitions in A, D, and F |
||||
uint public shadowed_public_var = 3; |
||||
uint internal shadowed_private_var = 3; |
||||
TestContractVar public shadowed_public_contract; |
||||
|
||||
// This contract's multiple inheritance chain should cause indirect shadowing (c3 linearization shadowing). |
||||
} |
@ -0,0 +1,22 @@ |
||||
contract A{ |
||||
|
||||
// ëëëëëëëëëëëëë这这这这这这这这这这 |
||||
|
||||
address unused; |
||||
|
||||
|
||||
address unused2; |
||||
|
||||
|
||||
// ই এই এই এইই এই এই এইই এই এই এই |
||||
|
||||
address unused3; |
||||
|
||||
|
||||
address unused4; |
||||
|
||||
// 这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这这 |
||||
address used; |
||||
|
||||
|
||||
} |
@ -0,0 +1,19 @@ |
||||
pragma solidity 0.8.16; |
||||
|
||||
type aliasTopLevel is uint; |
||||
|
||||
contract C |
||||
{ |
||||
type aliasContractLevel is uint; |
||||
} |
||||
|
||||
contract Test |
||||
{ |
||||
aliasTopLevel a; |
||||
C.aliasContractLevel b; |
||||
} |
||||
|
||||
function f(aliasTopLevel, C.aliasContractLevel) |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,19 @@ |
||||
pragma solidity 0.8.16; |
||||
|
||||
interface A |
||||
{ |
||||
function a() external; |
||||
} |
||||
|
||||
contract C |
||||
{ |
||||
function g(address _address) private |
||||
{ |
||||
A(_address).a(); |
||||
} |
||||
} |
||||
|
||||
function f(address _address) |
||||
{ |
||||
A(_address).a(); |
||||
} |
@ -0,0 +1,35 @@ |
||||
contract A{ |
||||
|
||||
function f() public virtual { |
||||
|
||||
} |
||||
|
||||
function test() public { |
||||
f(); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract B is A{ |
||||
|
||||
function f() public override { |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
contract C is A{ |
||||
|
||||
function f() public override { |
||||
|
||||
} |
||||
|
||||
function test2() public { |
||||
f(); |
||||
} |
||||
|
||||
} |
||||
|
||||
contract D is A{ |
||||
|
||||
} |
@ -0,0 +1 @@ |
||||
[{"inputs":[],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}] |
File diff suppressed because one or more lines are too long
@ -0,0 +1,576 @@ |
||||
{ |
||||
"packedUint": { |
||||
"name": "packedUint", |
||||
"type_string": "uint248", |
||||
"slot": 0, |
||||
"size": 248, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": {} |
||||
}, |
||||
"packedBool": { |
||||
"name": "packedBool", |
||||
"type_string": "bool", |
||||
"slot": 0, |
||||
"size": 8, |
||||
"offset": 248, |
||||
"value": true, |
||||
"elems": {} |
||||
}, |
||||
"_packedStruct": { |
||||
"name": "_packedStruct", |
||||
"type_string": "StorageLayout.PackedStruct", |
||||
"slot": 1, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": "0000000000000000000000000000000000000000000000000000000000000101", |
||||
"elems": { |
||||
"b": { |
||||
"name": "_packedStruct.b", |
||||
"type_string": "bool", |
||||
"slot": 1, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": true, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "_packedStruct.a", |
||||
"type_string": "uint248", |
||||
"slot": 1, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 1, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"mappingPackedStruct": { |
||||
"name": "mappingPackedStruct", |
||||
"type_string": "mapping(uint256 => StorageLayout.PackedStruct)", |
||||
"slot": 2, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 0, |
||||
"elems": {} |
||||
}, |
||||
"deepMappingPackedStruct": { |
||||
"name": "deepMappingPackedStruct", |
||||
"type_string": "mapping(address => mapping(uint256 => StorageLayout.PackedStruct))", |
||||
"slot": 3, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 0, |
||||
"elems": {} |
||||
}, |
||||
"deepMappingElementaryTypes": { |
||||
"name": "deepMappingElementaryTypes", |
||||
"type_string": "mapping(address => mapping(uint256 => bool))", |
||||
"slot": 4, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 0, |
||||
"elems": {} |
||||
}, |
||||
"mappingDynamicArrayOfStructs": { |
||||
"name": "mappingDynamicArrayOfStructs", |
||||
"type_string": "mapping(address => StorageLayout.PackedStruct[])", |
||||
"slot": 5, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 0, |
||||
"elems": {} |
||||
}, |
||||
"_address": { |
||||
"name": "_address", |
||||
"type_string": "address", |
||||
"slot": 6, |
||||
"size": 160, |
||||
"offset": 0, |
||||
"value": "0xae17D2dD99e07CA3bF2571CCAcEAA9e2Aefc2Dc6", |
||||
"elems": {} |
||||
}, |
||||
"_string": { |
||||
"name": "_string", |
||||
"type_string": "string", |
||||
"slot": 7, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": "slither-read-storage", |
||||
"elems": {} |
||||
}, |
||||
"packedUint8": { |
||||
"name": "packedUint8", |
||||
"type_string": "uint8", |
||||
"slot": 8, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": 8, |
||||
"elems": {} |
||||
}, |
||||
"packedBytes": { |
||||
"name": "packedBytes", |
||||
"type_string": "bytes8", |
||||
"slot": 8, |
||||
"size": 64, |
||||
"offset": 8, |
||||
"value": "6161616161616161", |
||||
"elems": {} |
||||
}, |
||||
"_enumA": { |
||||
"name": "_enumA", |
||||
"type_string": "StorageLayout.Enum", |
||||
"slot": 8, |
||||
"size": 8, |
||||
"offset": 72, |
||||
"value": "00", |
||||
"elems": {} |
||||
}, |
||||
"_enumB": { |
||||
"name": "_enumB", |
||||
"type_string": "StorageLayout.Enum", |
||||
"slot": 8, |
||||
"size": 8, |
||||
"offset": 80, |
||||
"value": "01", |
||||
"elems": {} |
||||
}, |
||||
"_enumC": { |
||||
"name": "_enumC", |
||||
"type_string": "StorageLayout.Enum", |
||||
"slot": 8, |
||||
"size": 8, |
||||
"offset": 88, |
||||
"value": "02", |
||||
"elems": {} |
||||
}, |
||||
"fixedArray": { |
||||
"name": "fixedArray", |
||||
"type_string": "uint256[3]", |
||||
"slot": 9, |
||||
"size": 768, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": { |
||||
"0": { |
||||
"name": "fixedArray[0]", |
||||
"type_string": "uint256", |
||||
"slot": 9, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "fixedArray[1]", |
||||
"type_string": "uint256", |
||||
"slot": 10, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 2, |
||||
"elems": {} |
||||
}, |
||||
"2": { |
||||
"name": "fixedArray[2]", |
||||
"type_string": "uint256", |
||||
"slot": 11, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 3, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"dynamicArrayOfFixedArrays": { |
||||
"name": "dynamicArrayOfFixedArrays", |
||||
"type_string": "uint256[3][]", |
||||
"slot": 12, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 2, |
||||
"elems": { |
||||
"0": { |
||||
"name": "dynamicArrayOfFixedArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386055, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": { |
||||
"0": { |
||||
"name": "dynamicArrayOfFixedArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386055, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "dynamicArrayOfFixedArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386056, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 2, |
||||
"elems": {} |
||||
}, |
||||
"2": { |
||||
"name": "dynamicArrayOfFixedArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386057, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 3, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"1": { |
||||
"name": "dynamicArrayOfFixedArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386058, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 4, |
||||
"elems": { |
||||
"0": { |
||||
"name": "dynamicArrayOfFixedArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386058, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 4, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "dynamicArrayOfFixedArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386059, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 5, |
||||
"elems": {} |
||||
}, |
||||
"2": { |
||||
"name": "dynamicArrayOfFixedArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 101051993584849178915136821395265346177868384823507754984078593667947067386060, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 6, |
||||
"elems": {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"fixedArrayofDynamicArrays": { |
||||
"name": "fixedArrayofDynamicArrays", |
||||
"type_string": "uint256[][3]", |
||||
"slot": 13, |
||||
"size": 768, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": { |
||||
"0": { |
||||
"name": "fixedArrayofDynamicArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 13, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": { |
||||
"0": { |
||||
"name": "fixedArrayofDynamicArrays[0]", |
||||
"type_string": "uint256", |
||||
"slot": 97569884605916225051403212656556507955018248777258318895762758024193532305077, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 7, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"1": { |
||||
"name": "fixedArrayofDynamicArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 14, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 2, |
||||
"elems": { |
||||
"0": { |
||||
"name": "fixedArrayofDynamicArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 84800337471693920904250232874319843718400766719524250287777680170677855896573, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 8, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "fixedArrayofDynamicArrays[1]", |
||||
"type_string": "uint256", |
||||
"slot": 84800337471693920904250232874319843718400766719524250287777680170677855896574, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 9, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"2": { |
||||
"name": "fixedArrayofDynamicArrays[2]", |
||||
"type_string": "uint256", |
||||
"slot": 15, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 3, |
||||
"elems": { |
||||
"0": { |
||||
"name": "fixedArrayofDynamicArrays[2]", |
||||
"type_string": "uint256", |
||||
"slot": 63806209331542711802848847270949280092855778197726125910674179583545433573378, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 10, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "fixedArrayofDynamicArrays[2]", |
||||
"type_string": "uint256", |
||||
"slot": 63806209331542711802848847270949280092855778197726125910674179583545433573379, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 11, |
||||
"elems": {} |
||||
}, |
||||
"2": { |
||||
"name": "fixedArrayofDynamicArrays[2]", |
||||
"type_string": "uint256", |
||||
"slot": 63806209331542711802848847270949280092855778197726125910674179583545433573380, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 12, |
||||
"elems": {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"multidimensionalArray": { |
||||
"name": "multidimensionalArray", |
||||
"type_string": "uint256[][]", |
||||
"slot": 16, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 3, |
||||
"elems": { |
||||
"0": { |
||||
"name": "multidimensionalArray[0]", |
||||
"type_string": "uint256", |
||||
"slot": 12396694973890998440467380340983585058878106250672390494374587083972727727730, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 1, |
||||
"elems": { |
||||
"0": { |
||||
"name": "multidimensionalArray[0]", |
||||
"type_string": "uint256", |
||||
"slot": 93856215500098298973000561543003607329881518401177956003908346942307446808932, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 13, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"1": { |
||||
"name": "multidimensionalArray[1]", |
||||
"type_string": "uint256", |
||||
"slot": 12396694973890998440467380340983585058878106250672390494374587083972727727731, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 2, |
||||
"elems": { |
||||
"0": { |
||||
"name": "multidimensionalArray[1]", |
||||
"type_string": "uint256", |
||||
"slot": 48332168562525185806884758054388614910060623018875025120987491603435926351511, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 14, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "multidimensionalArray[1]", |
||||
"type_string": "uint256", |
||||
"slot": 48332168562525185806884758054388614910060623018875025120987491603435926351512, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 15, |
||||
"elems": {} |
||||
} |
||||
} |
||||
}, |
||||
"2": { |
||||
"name": "multidimensionalArray[2]", |
||||
"type_string": "uint256", |
||||
"slot": 12396694973890998440467380340983585058878106250672390494374587083972727727732, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 3, |
||||
"elems": { |
||||
"0": { |
||||
"name": "multidimensionalArray[2]", |
||||
"type_string": "uint256", |
||||
"slot": 69037578548663760355678879060995014288537668748590083357305779656188235687653, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 16, |
||||
"elems": {} |
||||
}, |
||||
"1": { |
||||
"name": "multidimensionalArray[2]", |
||||
"type_string": "uint256", |
||||
"slot": 69037578548663760355678879060995014288537668748590083357305779656188235687654, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 17, |
||||
"elems": {} |
||||
}, |
||||
"2": { |
||||
"name": "multidimensionalArray[2]", |
||||
"type_string": "uint256", |
||||
"slot": 69037578548663760355678879060995014288537668748590083357305779656188235687655, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": 18, |
||||
"elems": {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"dynamicArrayOfStructs": { |
||||
"name": "dynamicArrayOfStructs", |
||||
"type_string": "StorageLayout.PackedStruct[]", |
||||
"slot": 17, |
||||
"size": 256, |
||||
"offset": 0, |
||||
"value": "0000000000000000000000000000000000000000000000000000000000000002", |
||||
"elems": { |
||||
"0": { |
||||
"b": { |
||||
"name": "dynamicArrayOfStructs[0]", |
||||
"type_string": "bool", |
||||
"slot": 22581645139872629890233439717971975110198959689450188087151966948260709403752, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": true, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "dynamicArrayOfStructs[0]", |
||||
"type_string": "uint248", |
||||
"slot": 22581645139872629890233439717971975110198959689450188087151966948260709403752, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 1, |
||||
"elems": {} |
||||
} |
||||
}, |
||||
"1": { |
||||
"b": { |
||||
"name": "dynamicArrayOfStructs[1]", |
||||
"type_string": "bool", |
||||
"slot": 22581645139872629890233439717971975110198959689450188087151966948260709403753, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": false, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "dynamicArrayOfStructs[1]", |
||||
"type_string": "uint248", |
||||
"slot": 22581645139872629890233439717971975110198959689450188087151966948260709403753, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 10, |
||||
"elems": {} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"fixedArrayOfStructs": { |
||||
"name": "fixedArrayOfStructs", |
||||
"type_string": "StorageLayout.PackedStruct[3]", |
||||
"slot": 18, |
||||
"size": 768, |
||||
"offset": 0, |
||||
"value": "0000000000000000000000000000000000000000000000000000000000000101", |
||||
"elems": { |
||||
"0": { |
||||
"b": { |
||||
"name": "fixedArrayOfStructs[0]", |
||||
"type_string": "bool", |
||||
"slot": 18, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": true, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "fixedArrayOfStructs[0]", |
||||
"type_string": "uint248", |
||||
"slot": 18, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 1, |
||||
"elems": {} |
||||
} |
||||
}, |
||||
"1": { |
||||
"b": { |
||||
"name": "fixedArrayOfStructs[1]", |
||||
"type_string": "bool", |
||||
"slot": 19, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": false, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "fixedArrayOfStructs[1]", |
||||
"type_string": "uint248", |
||||
"slot": 19, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 10, |
||||
"elems": {} |
||||
} |
||||
}, |
||||
"2": { |
||||
"b": { |
||||
"name": "fixedArrayOfStructs[2]", |
||||
"type_string": "bool", |
||||
"slot": 20, |
||||
"size": 8, |
||||
"offset": 0, |
||||
"value": false, |
||||
"elems": {} |
||||
}, |
||||
"a": { |
||||
"name": "fixedArrayOfStructs[2]", |
||||
"type_string": "uint248", |
||||
"slot": 20, |
||||
"size": 248, |
||||
"offset": 8, |
||||
"value": 0, |
||||
"elems": {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,74 @@ |
||||
// overwrite abi and bin: |
||||
// solc tests/storage-layout/storage_layout-0.8.10.sol --abi --bin -o tests/storage-layout --overwrite |
||||
contract StorageLayout { |
||||
uint248 packedUint = 1; |
||||
bool packedBool = true; |
||||
|
||||
struct PackedStruct { |
||||
bool b; |
||||
uint248 a; |
||||
} |
||||
PackedStruct _packedStruct = PackedStruct(packedBool, packedUint); |
||||
|
||||
mapping (uint => PackedStruct) mappingPackedStruct; |
||||
mapping (address => mapping (uint => PackedStruct)) deepMappingPackedStruct; |
||||
mapping (address => mapping (uint => bool)) deepMappingElementaryTypes; |
||||
mapping (address => PackedStruct[]) mappingDynamicArrayOfStructs; |
||||
|
||||
address _address; |
||||
string _string = "slither-read-storage"; |
||||
uint8 packedUint8 = 8; |
||||
bytes8 packedBytes = "aaaaaaaa"; |
||||
|
||||
enum Enum { |
||||
a, |
||||
b, |
||||
c |
||||
} |
||||
Enum _enumA = Enum.a; |
||||
Enum _enumB = Enum.b; |
||||
Enum _enumC = Enum.c; |
||||
|
||||
uint256[3] fixedArray; |
||||
uint256[3][] dynamicArrayOfFixedArrays; |
||||
uint[][3] fixedArrayofDynamicArrays; |
||||
uint[][] multidimensionalArray; |
||||
PackedStruct[] dynamicArrayOfStructs; |
||||
PackedStruct[3] fixedArrayOfStructs; |
||||
|
||||
function store() external { |
||||
require(_address == address(0)); |
||||
_address = msg.sender; |
||||
|
||||
mappingPackedStruct[packedUint] = _packedStruct; |
||||
|
||||
deepMappingPackedStruct[_address][packedUint] = _packedStruct; |
||||
|
||||
deepMappingElementaryTypes[_address][1] = true; |
||||
deepMappingElementaryTypes[_address][2] = true; |
||||
|
||||
fixedArray = [1, 2, 3]; |
||||
|
||||
dynamicArrayOfFixedArrays.push(fixedArray); |
||||
dynamicArrayOfFixedArrays.push([4, 5, 6]); |
||||
|
||||
fixedArrayofDynamicArrays[0].push(7); |
||||
fixedArrayofDynamicArrays[1].push(8); |
||||
fixedArrayofDynamicArrays[1].push(9); |
||||
fixedArrayofDynamicArrays[2].push(10); |
||||
fixedArrayofDynamicArrays[2].push(11); |
||||
fixedArrayofDynamicArrays[2].push(12); |
||||
|
||||
multidimensionalArray.push([13]); |
||||
multidimensionalArray.push([14, 15]); |
||||
multidimensionalArray.push([16, 17, 18]); |
||||
|
||||
dynamicArrayOfStructs.push(_packedStruct); |
||||
dynamicArrayOfStructs.push(PackedStruct(false, 10)); |
||||
fixedArrayOfStructs[0] = _packedStruct; |
||||
fixedArrayOfStructs[1] = PackedStruct(false, 10); |
||||
|
||||
mappingDynamicArrayOfStructs[_address].push(dynamicArrayOfStructs[0]); |
||||
mappingDynamicArrayOfStructs[_address].push(dynamicArrayOfStructs[1]); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
contract Test{ |
||||
|
||||
mapping(uint => mapping(uint => address)) authorized_destination; |
||||
|
||||
address destination; |
||||
|
||||
function init(){ |
||||
authorized_destination[0][0] = msg.sender; |
||||
} |
||||
|
||||
function setup(uint idx){ |
||||
destination = authorized_destination[0][0]; |
||||
} |
||||
|
||||
function withdraw(){ |
||||
destination.transfer(this.balance); |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
using {a} for Data; |
||||
|
||||
struct Data { mapping(uint => bool) flags; } |
||||
|
||||
function a(Data storage self, uint value, uint value2) returns(bool){ |
||||
return false; |
||||
} |
||||
|
||||
library Lib { |
||||
function a(Data storage self, uint value) public |
||||
view |
||||
returns (bool) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C { |
||||
using Lib for Data; |
||||
Data knownValues; |
||||
|
||||
function libCall(uint value) public { |
||||
require(knownValues.a(value)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,25 @@ |
||||
using {f} for St; |
||||
struct St { uint field; } |
||||
|
||||
|
||||
function f(St storage self, uint8 v) view returns(uint){ |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
library Lib { |
||||
function f(St storage self, uint256 v) public view returns (uint) { |
||||
return 1; |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C { |
||||
using Lib for St; |
||||
St st; |
||||
|
||||
function libCall(uint16 v) public view returns(uint){ |
||||
return st.f(v); // return 1 |
||||
} |
||||
|
||||
} |
@ -0,0 +1,14 @@ |
||||
import "./using-for-alias-dep1.sol"; |
||||
|
||||
contract C { |
||||
using {T3.a, T3.Lib.b} for uint256; |
||||
|
||||
function topLevel(uint256 value) public { |
||||
value.a(); |
||||
} |
||||
|
||||
function libCall(uint256 value) public { |
||||
value.b(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,11 @@ |
||||
import "./using-for-alias-dep2.sol" as T3; |
||||
|
||||
function b(uint256 value) returns(bool) { |
||||
return true; |
||||
} |
||||
|
||||
library Lib { |
||||
function a(uint256 value) public returns(bool) { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
function a(uint256 value) returns(bool) { |
||||
return true; |
||||
} |
||||
|
||||
library Lib { |
||||
function b(uint256 value) public returns(bool) { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
import "./using-for-alias-dep1.sol"; |
||||
|
||||
using {T3.a, T3.Lib.b} for uint256; |
||||
|
||||
contract C { |
||||
|
||||
function topLevel(uint256 value) public { |
||||
value.a(); |
||||
} |
||||
|
||||
function libCall(uint256 value) public { |
||||
value.b(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,14 @@ |
||||
|
||||
library A { |
||||
using B for uint256; |
||||
|
||||
function a(uint256 v) public view returns (uint) { |
||||
return v.b(); |
||||
} |
||||
} |
||||
|
||||
library B { |
||||
function b(uint256 v) public view returns (uint) { |
||||
return 1; |
||||
} |
||||
} |
@ -0,0 +1,2 @@ |
||||
import "./MyTypeA/Type.sol"; |
||||
import "./MyTypeA/Math.sol"; |
@ -0,0 +1,4 @@ |
||||
import "./Type.sol"; |
||||
function unwrap(MyTypeA a) pure returns (int256) { |
||||
return MyTypeA.unwrap(a); |
||||
} |
@ -0,0 +1,5 @@ |
||||
import "./Type.sol"; |
||||
|
||||
function mul(MyTypeA a, MyTypeA b) pure returns (MyTypeA) { |
||||
return MyTypeA.wrap(MyTypeA.unwrap(a) * MyTypeA.unwrap(b)); |
||||
} |
@ -0,0 +1,6 @@ |
||||
import "./Casting.sol" as C; |
||||
import "./Math.sol" as M; |
||||
|
||||
type MyTypeA is int256; |
||||
|
||||
using {M.mul, C.unwrap} for MyTypeA global; |
@ -0,0 +1,2 @@ |
||||
import "./MyTypeB/Type.sol"; |
||||
import "./MyTypeB/Math.sol"; |
@ -0,0 +1,4 @@ |
||||
import "./Type.sol"; |
||||
function unwrap(MyTypeB a) pure returns (uint256) { |
||||
return MyTypeB.unwrap(a); |
||||
} |
@ -0,0 +1,6 @@ |
||||
import "./Type.sol"; |
||||
|
||||
function mul(MyTypeB a, MyTypeB b) pure returns (MyTypeB) { |
||||
return MyTypeB.wrap(MyTypeB.unwrap(a) * MyTypeB.unwrap(b)); |
||||
} |
||||
|
@ -0,0 +1,6 @@ |
||||
import "./Casting.sol" as C; |
||||
import "./Math.sol" as M; |
||||
|
||||
type MyTypeB is uint256; |
||||
|
||||
using {M.mul, C.unwrap} for MyTypeB global; |
@ -0,0 +1,7 @@ |
||||
import "./MyTypeB.sol"; |
||||
|
||||
contract UsingForGlobalTopLevelCollision { |
||||
function mulAndUnwrap(MyTypeB x, MyTypeB y) external pure returns (uint256 z) { |
||||
z = x.mul(y).unwrap(); |
||||
} |
||||
} |
@ -0,0 +1,305 @@ |
||||
""" |
||||
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 pathlib import Path |
||||
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 |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
FUNC_DELC_TEST_ROOT = Path(TEST_DATA_DIR, "function_declaration") |
||||
|
||||
|
||||
def test_functions(): |
||||
# pylint: disable=too-many-statements |
||||
solc_select.switch_global_version("0.6.12", always_install=True) |
||||
file = Path(FUNC_DELC_TEST_ROOT, "test_function.sol").as_posix() |
||||
slither = Slither(file) |
||||
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) |
||||
file = Path(FUNC_DELC_TEST_ROOT, "test_function.sol").as_posix() |
||||
slither = Slither(file) |
||||
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) |
||||
file = Path(FUNC_DELC_TEST_ROOT, "test_function_reentrant.sol").as_posix() |
||||
slither = Slither(file) |
||||
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) |
||||
file = Path(FUNC_DELC_TEST_ROOT, "test_function.sol").as_posix() |
||||
slither = Slither(file) |
||||
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") |
@ -0,0 +1,127 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
|
||||
from slither import Slither |
||||
from slither.core.declarations import Function |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
SRC_MAPPING_TEST_ROOT = Path(TEST_DATA_DIR, "src_mapping") |
||||
|
||||
|
||||
def test_source_mapping(): |
||||
solc_select.switch_global_version("0.6.12", always_install=True) |
||||
file = Path(SRC_MAPPING_TEST_ROOT, "inheritance.sol").as_posix() |
||||
slither = Slither(file) |
||||
|
||||
# Check if A.f() is at the offset 27 |
||||
functions = slither.offset_to_objects(file, 27) |
||||
print(functions) |
||||
assert len(functions) == 1 |
||||
function = functions.pop() |
||||
assert isinstance(function, Function) |
||||
assert function.canonical_name == "A.f()" |
||||
|
||||
# Only one definition for A.f() |
||||
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 27)} == {(26, 28)} |
||||
# Only one reference for A.f(), in A.test() |
||||
assert {(x.start, x.end) for x in slither.offset_to_references(file, 27)} == {(92, 93)} |
||||
# Only one implementation for A.f(), in A.test() |
||||
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 27)} == {(17, 53)} |
||||
|
||||
# Check if C.f() is at the offset 203 |
||||
functions = slither.offset_to_objects(file, 203) |
||||
assert len(functions) == 1 |
||||
function = functions.pop() |
||||
assert isinstance(function, Function) |
||||
assert function.canonical_name == "C.f()" |
||||
|
||||
# Only one definition for C.f() |
||||
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 203)} == {(202, 204)} |
||||
# Two references for C.f(), in A.test() and C.test2() |
||||
assert {(x.start, x.end) for x in slither.offset_to_references(file, 203)} == { |
||||
(270, 271), |
||||
(92, 93), |
||||
} |
||||
# Only one implementation for A.f(), in A.test() |
||||
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 203)} == {(193, 230)} |
||||
|
||||
# Offset 93 is the call to f() in A.test() |
||||
# This can lead to three differents functions, depending on the current contract's context |
||||
functions = slither.offset_to_objects(file, 93) |
||||
print(functions) |
||||
assert len(functions) == 3 |
||||
for function in functions: |
||||
assert isinstance(function, Function) |
||||
assert function.canonical_name in ["A.f()", "B.f()", "C.f()"] |
||||
|
||||
# There are three definitions possible (in A, B or C) |
||||
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 93)} == { |
||||
(26, 28), |
||||
(202, 204), |
||||
(138, 140), |
||||
} |
||||
|
||||
# There are two references possible (in A.test() or C.test2() ) |
||||
assert {(x.start, x.end) for x in slither.offset_to_references(file, 93)} == { |
||||
(92, 93), |
||||
(270, 271), |
||||
} |
||||
|
||||
# There are three implementations possible (in A, B or C) |
||||
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 93)} == { |
||||
(17, 53), |
||||
(193, 230), |
||||
(129, 166), |
||||
} |
||||
|
||||
|
||||
def _sort_references_lines(refs: list) -> list: |
||||
return sorted([ref.lines[0] for ref in refs]) |
||||
|
||||
|
||||
def _test_references_user_defined_aliases(): |
||||
""" |
||||
Tests if references are filled correctly for user defined aliases (declared using "type [...] is [...]" statement). |
||||
""" |
||||
solc_select.switch_global_version("0.8.16", always_install=True) |
||||
file = Path(SRC_MAPPING_TEST_ROOT, "ReferencesUserDefinedAliases.sol").as_posix() |
||||
slither = Slither(file) |
||||
|
||||
alias_top_level = slither.compilation_units[0].user_defined_value_types["aliasTopLevel"] |
||||
assert len(alias_top_level.references) == 2 |
||||
lines = _sort_references_lines(alias_top_level.references) |
||||
assert lines == [12, 16] |
||||
|
||||
alias_contract_level = ( |
||||
slither.compilation_units[0] |
||||
.contracts[0] |
||||
.file_scope.user_defined_types["C.aliasContractLevel"] |
||||
) |
||||
assert len(alias_contract_level.references) == 2 |
||||
lines = _sort_references_lines(alias_contract_level.references) |
||||
assert lines == [13, 16] |
||||
|
||||
|
||||
def _test_references_user_defined_types_when_casting(): |
||||
""" |
||||
Tests if references are filled correctly for user defined types in case of casting. |
||||
""" |
||||
solc_select.switch_global_version("0.8.16", always_install=True) |
||||
file = Path(SRC_MAPPING_TEST_ROOT, "ReferencesUserDefinedTypesCasting.sol").as_posix() |
||||
slither = Slither(file) |
||||
|
||||
contracts = slither.compilation_units[0].contracts |
||||
a = contracts[0] if contracts[0].is_interface else contracts[1] |
||||
assert len(a.references) == 2 |
||||
lines = _sort_references_lines(a.references) |
||||
assert lines == [12, 18] |
||||
|
||||
|
||||
def test_references(): |
||||
""" |
||||
Tests if references list is filled correctly in the following cases: |
||||
- user defined aliases (declared using "type [...] is [...]" statement) |
||||
- user defined types in case of casting (TypeConversion expressions) |
||||
""" |
||||
_test_references_user_defined_aliases() |
||||
_test_references_user_defined_types_when_casting() |
@ -0,0 +1,36 @@ |
||||
import json |
||||
from pathlib import Path |
||||
from subprocess import PIPE, Popen |
||||
from solc_select import solc_select |
||||
from slither import Slither |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
STORAGE_TEST_ROOT = Path(TEST_DATA_DIR, "storage_layout") |
||||
|
||||
|
||||
def test_storage_layout(): |
||||
# the storage layout has not yet changed between solidity versions so we will test with one version of the compiler |
||||
solc_select.switch_global_version("0.8.10", always_install=True) |
||||
test_item = Path(STORAGE_TEST_ROOT, "storage_layout-0.8.10.sol").as_posix() |
||||
|
||||
sl = Slither(test_item, solc_force_legacy_json=False, disallow_partial=True) |
||||
|
||||
with Popen(["solc", test_item, "--storage-layout"], stdout=PIPE) as process: |
||||
for line in process.stdout: # parse solc output |
||||
if '{"storage":[{' in line.decode("utf-8"): # find the storage layout |
||||
layout = iter(json.loads(line)["storage"]) |
||||
while True: |
||||
try: |
||||
for contract in sl.contracts: |
||||
curr_var = next(layout) |
||||
var_name = curr_var["label"] |
||||
sl_name = contract.variables_as_dict[var_name] |
||||
slot, offset = contract.compilation_unit.storage_layout_of( |
||||
contract, sl_name |
||||
) |
||||
assert slot == int(curr_var["slot"]) |
||||
assert offset == int(curr_var["offset"]) |
||||
except StopIteration: |
||||
break |
||||
except KeyError as e: |
||||
print(f"not found {e} ") |
@ -0,0 +1,95 @@ |
||||
from pathlib import Path |
||||
from crytic_compile import CryticCompile |
||||
from crytic_compile.platform.solc_standard_json import SolcStandardJson |
||||
from solc_select import solc_select |
||||
|
||||
from slither import Slither |
||||
from slither.slithir.operations import InternalCall, LibraryCall |
||||
|
||||
from tests.utils import _run_all_detectors |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
USING_FOR_TEST_DATA_DIR = Path(TEST_DATA_DIR, "using_for") |
||||
|
||||
|
||||
def test_using_for_global_collision() -> None: |
||||
solc_select.switch_global_version("0.8.18", always_install=True) |
||||
standard_json = SolcStandardJson() |
||||
for source_file in Path(USING_FOR_TEST_DATA_DIR, "using_for_global_collision").rglob("*.sol"): |
||||
standard_json.add_source_file(Path(source_file).as_posix()) |
||||
compilation = CryticCompile(standard_json) |
||||
sl = Slither(compilation) |
||||
_run_all_detectors(sl) |
||||
|
||||
|
||||
def test_using_for_top_level_same_name() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(USING_FOR_TEST_DATA_DIR, "using-for-3-0.8.0.sol").as_posix()) |
||||
contract_c = slither.get_contract_from_name("C")[0] |
||||
libCall = contract_c.get_function_from_full_name("libCall(uint256)") |
||||
for ir in libCall.all_slithir_operations(): |
||||
if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "a": |
||||
return |
||||
assert False |
||||
|
||||
|
||||
def test_using_for_top_level_implicit_conversion() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(USING_FOR_TEST_DATA_DIR, "using-for-4-0.8.0.sol").as_posix()) |
||||
contract_c = slither.get_contract_from_name("C")[0] |
||||
libCall = contract_c.get_function_from_full_name("libCall(uint16)") |
||||
for ir in libCall.all_slithir_operations(): |
||||
if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "f": |
||||
return |
||||
assert False |
||||
|
||||
|
||||
def test_using_for_alias_top_level() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither( |
||||
Path(USING_FOR_TEST_DATA_DIR, "using-for-alias-top-level-0.8.0.sol").as_posix() |
||||
) |
||||
contract_c = slither.get_contract_from_name("C")[0] |
||||
libCall = contract_c.get_function_from_full_name("libCall(uint256)") |
||||
ok = False |
||||
for ir in libCall.all_slithir_operations(): |
||||
if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "b": |
||||
ok = True |
||||
if not ok: |
||||
assert False |
||||
topLevelCall = contract_c.get_function_from_full_name("topLevel(uint256)") |
||||
for ir in topLevelCall.all_slithir_operations(): |
||||
if isinstance(ir, InternalCall) and ir.function_name == "a": |
||||
return |
||||
assert False |
||||
|
||||
|
||||
def test_using_for_alias_contract() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither( |
||||
Path(USING_FOR_TEST_DATA_DIR, "using-for-alias-contract-0.8.0.sol").as_posix() |
||||
) |
||||
contract_c = slither.get_contract_from_name("C")[0] |
||||
libCall = contract_c.get_function_from_full_name("libCall(uint256)") |
||||
ok = False |
||||
for ir in libCall.all_slithir_operations(): |
||||
if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "b": |
||||
ok = True |
||||
if not ok: |
||||
assert False |
||||
topLevelCall = contract_c.get_function_from_full_name("topLevel(uint256)") |
||||
for ir in topLevelCall.all_slithir_operations(): |
||||
if isinstance(ir, InternalCall) and ir.function_name == "a": |
||||
return |
||||
assert False |
||||
|
||||
|
||||
def test_using_for_in_library() -> None: |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(USING_FOR_TEST_DATA_DIR, "using-for-in-library-0.8.0.sol").as_posix()) |
||||
contract_c = slither.get_contract_from_name("A")[0] |
||||
libCall = contract_c.get_function_from_full_name("a(uint256)") |
||||
for ir in libCall.all_slithir_operations(): |
||||
if isinstance(ir, LibraryCall) and ir.destination == "B" and ir.function_name == "b": |
||||
return |
||||
assert False |
@ -0,0 +1,17 @@ |
||||
|
||||
contract Placeholder { |
||||
constructor() payable {} |
||||
} |
||||
|
||||
contract NewContract { |
||||
bytes32 internal constant state_variable_read = bytes32(0); |
||||
|
||||
function readAllStateVariables() external { |
||||
new Placeholder{salt: state_variable_read} (); |
||||
} |
||||
|
||||
function readAllLocalVariables() external { |
||||
bytes32 local_variable_read = bytes32(0); |
||||
new Placeholder{salt: local_variable_read} (); |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
interface Test { |
||||
function test() external payable returns (uint); |
||||
function testTuple() external payable returns (uint, uint); |
||||
} |
||||
contract C { |
||||
// TODO |
||||
// 1) support variable declarations |
||||
//uint min = 1 > 0 ? 1 : 2; |
||||
// 2) suppory ternary index range access |
||||
// function e(bool cond, bytes calldata x) external { |
||||
// bytes memory a = x[cond ? 1 : 2 :]; |
||||
// } |
||||
function a(uint a, uint b) external { |
||||
(uint min, uint max) = a < b ? (a, b) : (b, a); |
||||
} |
||||
function b( address a, address b) external { |
||||
(address tokenA, address tokenB) = a < b ? (a, b) : (b, a); |
||||
} |
||||
|
||||
bytes char; |
||||
function c(bytes memory strAddress, uint i, uint padding, uint length) external { |
||||
char[0] = strAddress[i < padding + 2 ? i : 42 + i - length]; |
||||
} |
||||
|
||||
function d(bool cond, bytes calldata x) external { |
||||
bytes1 a = x[cond ? 1 : 2]; |
||||
} |
||||
|
||||
function e(address one, address two) public { |
||||
uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? 2 : gasleft()}(); |
||||
} |
||||
|
||||
// Parenthetical expression |
||||
function f(address one, address two) public { |
||||
uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? (1 == 1 ? 1 : 2) : gasleft()}(); |
||||
} |
||||
|
||||
// Unused tuple variable |
||||
function g(address one) public { |
||||
(, uint x) = Test(one).testTuple(); |
||||
} |
||||
|
||||
uint[] myIntegers; |
||||
function _h(uint c) internal returns(uint) { |
||||
return c; |
||||
} |
||||
function h(bool cond, uint a, uint b) public { |
||||
uint d = _h( |
||||
myIntegers[cond ? a : b] |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
from pathlib import Path |
||||
from collections import namedtuple |
||||
from slither import Slither |
||||
from slither.slithir.operations import Operation, NewContract |
||||
from solc_select import solc_select |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
|
||||
|
||||
def check_num_local_vars_read(function, slithir_op: Operation, num_reads_expected: int): |
||||
for node in function.nodes: |
||||
for operation in node.irs: |
||||
if isinstance(operation, slithir_op): |
||||
assert len(operation.read) == num_reads_expected |
||||
assert len(node.local_variables_read) == num_reads_expected |
||||
|
||||
|
||||
def check_num_states_vars_read(function, slithir_op: Operation, num_reads_expected: int): |
||||
for node in function.nodes: |
||||
for operation in node.irs: |
||||
if isinstance(operation, slithir_op): |
||||
assert len(operation.read) == num_reads_expected |
||||
assert len(node.state_variables_read) == num_reads_expected |
||||
|
||||
|
||||
OperationTest = namedtuple("OperationTest", "contract_name slithir_op") |
||||
|
||||
OPERATION_TEST = [OperationTest("NewContract", NewContract)] |
||||
|
||||
|
||||
def test_operation_reads() -> None: |
||||
""" |
||||
Every slithir operation has its own contract and reads all local and state variables in readAllLocalVariables and readAllStateVariables, respectively. |
||||
""" |
||||
solc_select.switch_global_version("0.8.15", always_install=True) |
||||
slither = Slither(Path(TEST_DATA_DIR, "operation_reads.sol").as_posix()) |
||||
|
||||
for op_test in OPERATION_TEST: |
||||
print(op_test) |
||||
available = slither.get_contract_from_name(op_test.contract_name) |
||||
assert len(available) == 1 |
||||
target = available[0] |
||||
|
||||
num_state_variables = len(target.state_variables_ordered) |
||||
state_function = target.get_function_from_signature("readAllStateVariables()") |
||||
check_num_states_vars_read(state_function, op_test.slithir_op, num_state_variables) |
||||
|
||||
local_function = target.get_function_from_signature("readAllLocalVariables()") |
||||
num_local_vars = len(local_function.local_variables) |
||||
check_num_local_vars_read(local_function, op_test.slithir_op, num_local_vars) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_operation_reads() |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
from slither import Slither |
||||
from slither.core.cfg.node import NodeType |
||||
from slither.slithir.operations import Assignment |
||||
from slither.core.expressions import AssignmentOperation, TupleExpression |
||||
|
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
# pylint: disable=too-many-nested-blocks |
||||
def test_ternary_conversions() -> None: |
||||
"""This tests that true and false sons define the same number of variables that the father node declares""" |
||||
solc_select.switch_global_version("0.8.0", always_install=True) |
||||
slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix()) |
||||
for contract in slither.contracts: |
||||
for function in contract.functions: |
||||
vars_declared = 0 |
||||
vars_assigned = 0 |
||||
for node in function.nodes: |
||||
if node.type in [NodeType.IF, NodeType.IFLOOP]: |
||||
|
||||
# Iterate over true and false son |
||||
for inner_node in node.sons: |
||||
# Count all variables declared |
||||
expression = inner_node.expression |
||||
if isinstance(expression, AssignmentOperation): |
||||
var_expr = expression.expression_left |
||||
# Only tuples declare more than one var |
||||
if isinstance(var_expr, TupleExpression): |
||||
vars_declared += len(var_expr.expressions) |
||||
else: |
||||
vars_declared += 1 |
||||
|
||||
for ir in inner_node.irs: |
||||
# Count all variables defined |
||||
if isinstance(ir, Assignment): |
||||
vars_assigned += 1 |
||||
|
||||
assert vars_declared == vars_assigned |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_ternary_conversions() |
@ -0,0 +1,64 @@ |
||||
pragma experimental ABIEncoderV2; |
||||
|
||||
contract Contract{} |
||||
|
||||
contract C{ |
||||
|
||||
mapping(uint => address)[] public arrayOfMappings; |
||||
|
||||
mapping(uint => address[]) public normalMappingArrayField; |
||||
|
||||
enum State{a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64,a65,a66,a67,a68,a69,a70,a71,a72,a73,a74,a75,a76,a77,a78,a79,a80,a81,a82,a83,a84,a85,a86,a87,a88,a89,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,a100,a101,a102,a103,a104,a105,a106,a107,a108,a109,a110,a111,a112,a113,a114,a115,a116,a117,a118,a119,a120,a121,a122,a123,a124,a125,a126,a127,a128,a129,a130,a131,a132,a133,a134,a135,a136,a137,a138,a139,a140,a141,a142,a143,a144,a145,a146,a147,a148,a149,a150,a151,a152,a153,a154,a155,a156,a157,a158,a159,a160,a161,a162,a163,a164,a165,a166,a167,a168,a169,a170,a171,a172,a173,a174,a175,a176,a177,a178,a179,a180,a181,a182,a183,a184,a185,a186,a187,a188,a189,a190,a191,a192,a193,a194,a195,a196,a197,a198,a199,a200,a201,a202,a203,a204,a205,a206,a207,a208,a209,a210,a211,a212,a213,a214,a215,a216,a217,a218,a219,a220,a221,a222,a223,a224,a225,a226,a227,a228,a229,a230,a231,a232,a233,a234,a235,a236,a237,a238,a239,a240,a241,a242,a243,a244,a245,a246,a247,a248,a249,a250,a251,a252,a253,a254,a255,a256} |
||||
mapping(State => uint) public stateMap; |
||||
|
||||
mapping(Contract => uint) public contractMap; |
||||
|
||||
uint[][] public multiDimensionalArray; |
||||
|
||||
struct Simple { |
||||
uint a; |
||||
uint b; |
||||
mapping(uint => uint) c; |
||||
uint[] d; |
||||
function(uint) external returns (uint) e; |
||||
} |
||||
|
||||
Simple public simple; |
||||
|
||||
struct Inner { |
||||
uint a; |
||||
uint b; |
||||
} |
||||
|
||||
struct Outer { |
||||
Inner inner; |
||||
uint c; |
||||
} |
||||
|
||||
Outer public outer; |
||||
|
||||
|
||||
struct A { |
||||
Inner inner; |
||||
uint a; |
||||
} |
||||
struct B { |
||||
uint a; |
||||
Inner inner; |
||||
} |
||||
|
||||
A public a; |
||||
A[] public a_array; |
||||
mapping(address => B[]) public b_mapping_of_array; |
||||
|
||||
function function_with_struct(A memory a) public{} |
||||
|
||||
function function_with_array(A[] memory array, B memory b) public {} |
||||
|
||||
struct AnotherStruct{ |
||||
B b; |
||||
A[] a; |
||||
} |
||||
mapping(address => AnotherStruct[][]) public mapping_of_double_array_of_struct; |
||||
} |
||||
|
@ -0,0 +1,12 @@ |
||||
contract A{ |
||||
|
||||
struct St{ |
||||
St[] a; |
||||
uint b; |
||||
} |
||||
|
||||
function f(St memory s) internal{ |
||||
f(s); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,64 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
from slither import Slither |
||||
|
||||
# % solc functions_ids.sol --hashes |
||||
# ======= functions_ids.sol:C ======= |
||||
# Function signatures: |
||||
# 0dbe671f: a() |
||||
# 4a1f689d: a_array(uint256) |
||||
# 98fc2aa5: arrayOfMappings(uint256,uint256) |
||||
# 4ea7a557: b_mapping_of_array(address,uint256) |
||||
# 3c0af344: contractMap(address) |
||||
# 20969954: function_with_array(((uint256,uint256),uint256)[],(uint256,(uint256,uint256))) |
||||
# 1c039831: function_with_struct(((uint256,uint256),uint256)) |
||||
# 37e66bae: mapping_of_double_array_of_struct(address,uint256,uint256) |
||||
# f29872a8: multiDimensionalArray(uint256,uint256) |
||||
# 9539e3c8: normalMappingArrayField(uint256,uint256) |
||||
# 87c3dbb6: outer() |
||||
# df201a46: simple() |
||||
# 5a20851f: stateMap(uint16) |
||||
|
||||
# {"contracts":{"functions_ids.sol:C":{"hashes":{"a()":"0dbe671f","a_array(uint256)":"4a1f689d","arrayOfMappings(uint256,uint256)":"98fc2aa5","b_mapping_of_array(address,uint256)":"4ea7a557","contractMap(address)":"3c0af344","function_with_array(((uint256,uint256),uint256)[],(uint256,(uint256,uint256)))":"20969954","function_with_struct(((uint256,uint256),uint256))":"1c039831","mapping_of_double_array_of_struct(address,uint256,uint256)":"37e66bae","multiDimensionalArray(uint256,uint256)":"f29872a8","normalMappingArrayField(uint256,uint256)":"9539e3c8","outer()":"87c3dbb6","simple()":"df201a46","stateMap(uint16)":"5a20851f"}},"functions_ids.sol:Contract":{"hashes":{}}},"version":"0.7.0+commit.9e61f92b.Darwin.appleclang"} |
||||
from slither.utils.function import get_function_id |
||||
|
||||
signatures = { |
||||
"a()": "0dbe671f", |
||||
"a_array(uint256)": "4a1f689d", |
||||
"arrayOfMappings(uint256,uint256)": "98fc2aa5", |
||||
"b_mapping_of_array(address,uint256)": "4ea7a557", |
||||
"contractMap(address)": "3c0af344", |
||||
"function_with_array(((uint256,uint256),uint256)[],(uint256,(uint256,uint256)))": "20969954", |
||||
"function_with_struct(((uint256,uint256),uint256))": "1c039831", |
||||
"mapping_of_double_array_of_struct(address,uint256,uint256)": "37e66bae", |
||||
"multiDimensionalArray(uint256,uint256)": "f29872a8", |
||||
"normalMappingArrayField(uint256,uint256)": "9539e3c8", |
||||
"outer()": "87c3dbb6", |
||||
"simple()": "df201a46", |
||||
"stateMap(uint16)": "5a20851f", |
||||
} |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
|
||||
|
||||
def test_functions_ids() -> None: |
||||
solc_select.switch_global_version("0.7.0", always_install=True) |
||||
file = Path(TEST_DATA_DIR, "functions_ids.sol").as_posix() |
||||
sl = Slither(file) |
||||
contracts_c = sl.get_contract_from_name("C") |
||||
assert len(contracts_c) == 1 |
||||
contract_c = contracts_c[0] |
||||
|
||||
for sig, hashes in signatures.items(): |
||||
func = contract_c.get_function_from_signature(sig) |
||||
if not func: |
||||
var_name = sig[: sig.find("(")] |
||||
var = contract_c.get_state_variable_from_name(var_name) |
||||
assert var |
||||
assert get_function_id(var.solidity_signature) == int(hashes, 16) |
||||
else: |
||||
assert get_function_id(func.solidity_signature) == int(hashes, 16) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_functions_ids() |
@ -0,0 +1,13 @@ |
||||
from pathlib import Path |
||||
from solc_select import solc_select |
||||
from slither import Slither |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
|
||||
|
||||
def test_function_id_rec_structure() -> None: |
||||
solc_select.switch_global_version("0.8.0", always_install=True) |
||||
slither = Slither(Path(TEST_DATA_DIR, "type_helpers.sol").as_posix()) |
||||
for compilation_unit in slither.compilation_units: |
||||
for function in compilation_unit.functions: |
||||
assert function.solidity_signature |
Loading…
Reference in new issue