mirror of https://github.com/crytic/slither
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
3.2 KiB
92 lines
3.2 KiB
import re
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from deepdiff import DeepDiff
|
|
from web3.contract import Contract
|
|
|
|
from slither import Slither
|
|
from slither.tools.read_storage import SlitherReadStorage, RpcInfo
|
|
|
|
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data"
|
|
|
|
|
|
def get_source_file(file_path) -> str:
|
|
with open(file_path, "r", encoding="utf8") as f:
|
|
source = f.read()
|
|
|
|
return source
|
|
|
|
|
|
def deploy_contract(w3, ganache, contract_bin, contract_abi) -> Contract:
|
|
"""Deploy contract to the local ganache network"""
|
|
signed_txn = w3.eth.account.sign_transaction(
|
|
dict(
|
|
nonce=w3.eth.get_transaction_count(ganache.eth_address),
|
|
maxFeePerGas=20000000000,
|
|
maxPriorityFeePerGas=1,
|
|
gas=15000000,
|
|
to=b"",
|
|
data="0x" + contract_bin,
|
|
chainId=1,
|
|
),
|
|
ganache.eth_privkey,
|
|
)
|
|
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
|
address = w3.eth.get_transaction_receipt(tx_hash)["contractAddress"]
|
|
contract = w3.eth.contract(address, abi=contract_abi)
|
|
return contract
|
|
|
|
|
|
# pylint: disable=too-many-locals
|
|
@pytest.mark.parametrize(
|
|
"test_contract, storage_file",
|
|
[("StorageLayout", "storage_layout"), ("UnstructuredStorageLayout", "unstructured_storage")],
|
|
)
|
|
@pytest.mark.usefixtures("web3", "ganache")
|
|
def test_read_storage(test_contract, storage_file, web3, ganache, solc_binary_path) -> None:
|
|
solc_path = solc_binary_path(version="0.8.10")
|
|
|
|
assert web3.is_connected()
|
|
bin_path = Path(TEST_DATA_DIR, f"{test_contract}.bin").as_posix()
|
|
abi_path = Path(TEST_DATA_DIR, f"{test_contract}.abi").as_posix()
|
|
bytecode = get_source_file(bin_path)
|
|
abi = get_source_file(abi_path)
|
|
contract = deploy_contract(web3, ganache, bytecode, abi)
|
|
contract.functions.store().transact({"from": ganache.eth_address})
|
|
address = contract.address
|
|
|
|
sl = Slither(Path(TEST_DATA_DIR, f"{test_contract}.sol").as_posix(), solc=solc_path)
|
|
contracts = sl.contracts
|
|
|
|
rpc_info: RpcInfo = RpcInfo(ganache.provider)
|
|
srs = SlitherReadStorage(contracts, 100, rpc_info)
|
|
srs.unstructured = True
|
|
srs.storage_address = address
|
|
srs.get_all_storage_variables()
|
|
srs.get_storage_layout()
|
|
srs.walk_slot_info(srs.get_slot_values)
|
|
actual_file = Path(TEST_DATA_DIR, "storage_layout.json").as_posix()
|
|
with open(actual_file, "w", encoding="utf-8") as file:
|
|
slot_infos_json = srs.to_json()
|
|
json.dump(slot_infos_json, file, indent=4)
|
|
|
|
expected_file = Path(TEST_DATA_DIR, f"TEST_{storage_file}.json").as_posix()
|
|
|
|
with open(expected_file, "r", encoding="utf8") as f:
|
|
expected = json.load(f)
|
|
with open(actual_file, "r", encoding="utf8") as f:
|
|
actual = json.load(f)
|
|
|
|
diff = DeepDiff(expected, actual, ignore_order=True, verbose_level=2, view="tree")
|
|
if diff:
|
|
for change in diff.get("values_changed", []):
|
|
path_list = re.findall(r"\['(.*?)'\]", change.path())
|
|
path = "_".join(path_list)
|
|
with open(f"{path}_expected.txt", "w", encoding="utf8") as f:
|
|
f.write(str(change.t1))
|
|
with open(f"{path}_actual.txt", "w", encoding="utf8") as f:
|
|
f.write(str(change.t2))
|
|
|
|
assert not diff
|
|
|