Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tool slither-interface #1898

Merged
merged 5 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
"etherscan",
"find_paths",
"flat",
"interface",
"kspec",
"printers",
# "prop"
Expand Down
95 changes: 95 additions & 0 deletions scripts/ci_test_interface.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash

### Test slither-interface

DIR_TESTS="tests/tools/interface"

solc-select use 0.8.19 --always-install

#Test 1 - Etherscan target
slither-interface WETH9 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
DIFF=$(diff crytic-export/interfaces/IWETH9.sol "$DIR_TESTS/test_1.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 1 failed"
cat "crytic-export/interfaces/IWETH9.sol"
echo ""
cat "$DIR_TESTS/test_1.sol"
exit 255
fi


#Test 2 - Local file target
slither-interface Mock tests/tools/interface/ContractMock.sol
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_2.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 2 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_2.sol"
exit 255
fi


#Test 3 - unroll structs
slither-interface Mock tests/tools/interface/ContractMock.sol --unroll-structs
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_3.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 3 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_3.sol"
exit 255
fi

#Test 4 - exclude structs
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-structs
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_4.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 4 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_4.sol"
exit 255
fi

#Test 5 - exclude errors
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-errors
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_5.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 5 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_5.sol"
exit 255
fi

#Test 6 - exclude enums
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-enums
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_6.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 6 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_6.sol"
exit 255
fi

#Test 7 - exclude events
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-events
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_7.sol" --strip-trailing-cr)
if [ "$DIFF" != "" ]
then
echo "slither-interface test 7 failed"
cat "crytic-export/interfaces/IMock.sol"
echo ""
cat "$DIR_TESTS/test_7.sol"
exit 255
fi

rm -r crytic-export
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"slither-read-storage = slither.tools.read_storage.__main__:main",
"slither-doctor = slither.tools.doctor.__main__:main",
"slither-documentation = slither.tools.documentation.__main__:main",
"slither-interface = slither.tools.interface.__main__:main",
]
},
)
Empty file.
105 changes: 105 additions & 0 deletions slither/tools/interface/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import argparse
import logging
from pathlib import Path

from crytic_compile import cryticparser

from slither import Slither
from slither.utils.code_generation import generate_interface

logging.basicConfig()
logger = logging.getLogger("Slither-Interface")
logger.setLevel(logging.INFO)


def parse_args() -> argparse.Namespace:
"""
Parse the underlying arguments for the program.
:return: Returns the arguments for the program.
"""
parser = argparse.ArgumentParser(
description="Generates code for a Solidity interface from contract",
usage=("slither-interface <ContractName> <source file or deployment address>"),
)

parser.add_argument(
"contract_source",
help="The name of the contract (case sensitive) followed by the deployed contract address if verified on etherscan or project directory/filename for local contracts.",
nargs="+",
)

parser.add_argument(
"--unroll-structs",
help="Whether to use structures' underlying types instead of the user-defined type",
default=False,
action="store_true",
)

parser.add_argument(
"--exclude-events",
help="Excludes event signatures in the interface",
default=False,
action="store_true",
)

parser.add_argument(
"--exclude-errors",
help="Excludes custom error signatures in the interface",
default=False,
action="store_true",
)

parser.add_argument(
"--exclude-enums",
help="Excludes enum definitions in the interface",
default=False,
action="store_true",
)

parser.add_argument(
"--exclude-structs",
help="Exclude struct definitions in the interface",
default=False,
action="store_true",
)

cryticparser.init(parser)

return parser.parse_args()


def main() -> None:
args = parse_args()

contract_name, target = args.contract_source
slither = Slither(target, **vars(args))

_contract = slither.get_contract_from_name(contract_name)[0]

interface = generate_interface(
contract=_contract,
unroll_structs=args.unroll_structs,
include_events=not args.exclude_events,
include_errors=not args.exclude_errors,
include_enums=not args.exclude_enums,
include_structs=not args.exclude_structs,
)

# add version pragma
interface = (
f"pragma solidity {_contract.compilation_unit.pragma_directives[0].version};\n\n"
+ interface
)

# write interface to file
export = Path("crytic-export", "interfaces")
export.mkdir(parents=True, exist_ok=True)
filename = f"I{contract_name}.sol"
path = Path(export, filename)
logger.info(f" Interface exported to {path}")
with open(path, "w", encoding="utf8") as f:
f.write(interface)


if __name__ == "__main__":
main()
33 changes: 33 additions & 0 deletions tests/tools/interface/ContractMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pragma solidity ^0.8.19;

contract Mock {

error Error1();
error Error2();
error Error3();

event Event1();
event Event2(address param);
event Event3(uint256 num1, uint72 num2);

struct Foo {
uint256 bar;
address baz;
}

enum Status {
Active,
Pending,
Canceled
}

Foo public foo;

Status public status;

function function1() public pure returns (address){
return address(0);
}


}
20 changes: 20 additions & 0 deletions tests/tools/interface/test_1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pragma solidity ^0.4.18;

interface IWETH9 {
event Approval(address, address, uint256);
event Transfer(address, address, uint256);
event Deposit(address, uint256);
event Withdrawal(address, uint256);
function name() external returns (string memory);
function symbol() external returns (string memory);
function decimals() external returns (uint8);
function balanceOf(address) external returns (uint256);
function allowance(address,address) external returns (uint256);
function deposit() external payable;
function withdraw(uint256) external;
function totalSupply() external view returns (uint256);
function approve(address,uint256) external returns (bool);
function transfer(address,uint256) external returns (bool);
function transferFrom(address,address,uint256) external returns (bool);
}

19 changes: 19 additions & 0 deletions tests/tools/interface/test_2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pragma solidity ^0.8.19;

interface IMock {
event Event1();
event Event2(address);
event Event3(uint256, uint72);
error Error1();
error Error2();
error Error3();
enum Status { Active, Pending, Canceled }
struct Foo {
uint256 bar;
address baz;
}
function foo() external returns (Foo memory);
function status() external returns (Status);
function function1() external pure returns (address);
}

19 changes: 19 additions & 0 deletions tests/tools/interface/test_3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pragma solidity ^0.8.19;

interface IMock {
event Event1();
event Event2(address);
event Event3(uint256, uint72);
error Error1();
error Error2();
error Error3();
enum Status { Active, Pending, Canceled }
struct Foo {
uint256 bar;
address baz;
}
function foo() external returns (uint256, address);
function status() external returns (uint8);
function function1() external pure returns (address);
}

15 changes: 15 additions & 0 deletions tests/tools/interface/test_4.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pragma solidity ^0.8.19;

interface IMock {
event Event1();
event Event2(address);
event Event3(uint256, uint72);
error Error1();
error Error2();
error Error3();
enum Status { Active, Pending, Canceled }
function foo() external returns (Foo memory);
function status() external returns (Status);
function function1() external pure returns (address);
}

16 changes: 16 additions & 0 deletions tests/tools/interface/test_5.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.8.19;

interface IMock {
event Event1();
event Event2(address);
event Event3(uint256, uint72);
enum Status { Active, Pending, Canceled }
struct Foo {
uint256 bar;
address baz;
}
function foo() external returns (Foo memory);
function status() external returns (Status);
function function1() external pure returns (address);
}

18 changes: 18 additions & 0 deletions tests/tools/interface/test_6.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pragma solidity ^0.8.19;

interface IMock {
event Event1();
event Event2(address);
event Event3(uint256, uint72);
error Error1();
error Error2();
error Error3();
struct Foo {
uint256 bar;
address baz;
}
function foo() external returns (Foo memory);
function status() external returns (Status);
function function1() external pure returns (address);
}

16 changes: 16 additions & 0 deletions tests/tools/interface/test_7.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.8.19;

interface IMock {
error Error1();
error Error2();
error Error3();
enum Status { Active, Pending, Canceled }
struct Foo {
uint256 bar;
address baz;
}
function foo() external returns (Foo memory);
function status() external returns (Status);
function function1() external pure returns (address);
}