add tool slither-interface

pull/1898/head
0xGusMcCrae 2 years ago
parent 507795baaa
commit 92c06c4f4a
  1. 93
      scripts/ci_test_interface.sh
  2. 1
      setup.py
  3. 0
      slither/tools/interface/__init__.py
  4. 105
      slither/tools/interface/__main__.py
  5. 33
      tests/tools/interface/ContractMock.sol
  6. 20
      tests/tools/interface/test_1.sol
  7. 19
      tests/tools/interface/test_2.sol
  8. 19
      tests/tools/interface/test_3.sol
  9. 15
      tests/tools/interface/test_4.sol
  10. 16
      tests/tools/interface/test_5.sol
  11. 18
      tests/tools/interface/test_6.sol
  12. 16
      tests/tools/interface/test_7.sol

@ -0,0 +1,93 @@
#!/usr/bin/env bash
### Test slither-interface
DIR_TESTS="tests/tools/interface"
#Test 1 - Etherscan target
slither-interface WETH9 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
DIFF=$(diff crytic-export/interfaces/IWETH9.sol "$DIR_TESTS/test_1.sol")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 1 failed"
cat test_1.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 2 failed"
cat test_2.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 3 failed"
cat test_3.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 4 failed"
cat test_4.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 5 failed"
cat test_5.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 6 failed"
cat test_6.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")
if [ "$DIFF" != "" ]
then
echo "slither-interface test 7 failed"
cat test_7.sol
echo ""
cat "$DIR_TESTS/test_7.sol"
exit 255
fi
rm -r crytic-export

@ -61,6 +61,7 @@ setup(
"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",
]
},
)

@ -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()

@ -0,0 +1,33 @@
pragma solidity ^0.8.0;
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);
}
}

@ -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);
}

@ -0,0 +1,19 @@
pragma solidity ^0.8.0;
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);
}

@ -0,0 +1,19 @@
pragma solidity ^0.8.0;
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);
}

@ -0,0 +1,15 @@
pragma solidity ^0.8.0;
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);
}

@ -0,0 +1,16 @@
pragma solidity ^0.8.0;
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);
}

@ -0,0 +1,18 @@
pragma solidity ^0.8.0;
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);
}

@ -0,0 +1,16 @@
pragma solidity ^0.8.0;
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);
}
Loading…
Cancel
Save