mirror of https://github.com/crytic/slither
commit
d962ddeb5b
@ -0,0 +1,7 @@ |
||||
""" |
||||
This module import all slither exceptions |
||||
""" |
||||
from slither.slithir.exceptions import SlithIRError |
||||
from slither.solc_parsing.exceptions import ParsingError, ParsingContractNotFound, ParsingNameReuse |
||||
from slither.core.exceptions import SlitherCoreError |
||||
from slither.exceptions import SlitherException |
@ -0,0 +1,3 @@ |
||||
from slither.exceptions import SlitherException |
||||
|
||||
class SlitherCoreError(SlitherException): pass |
@ -1,8 +1,53 @@ |
||||
from .variable import Variable |
||||
from slither.core.children.child_contract import ChildContract |
||||
from slither.utils.type import export_nested_types_from_variable |
||||
|
||||
class StateVariable(ChildContract, Variable): |
||||
|
||||
################################################################################### |
||||
################################################################################### |
||||
# region Signature |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
@property |
||||
def signature(self): |
||||
""" |
||||
Return the signature of the state variable as a function signature |
||||
:return: (str, list(str), list(str)), as (name, list parameters type, list return values type) |
||||
""" |
||||
return self.name, [str(x) for x in export_nested_types_from_variable(self)], self.type |
||||
|
||||
@property |
||||
def signature_str(self): |
||||
""" |
||||
Return the signature of the state variable as a function signature |
||||
:return: str: func_name(type1,type2) returns(type3) |
||||
""" |
||||
name, parameters, returnVars = self.signature |
||||
return name+'('+','.join(parameters)+') returns('+','.join(returnVars)+')' |
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region Name |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
@property |
||||
def canonical_name(self): |
||||
return '{}:{}'.format(self.contract.name, self.name) |
||||
|
||||
@property |
||||
def full_name(self): |
||||
""" |
||||
Return the name of the state variable as a function signaure |
||||
str: func_name(type1,type2) |
||||
:return: the function signature without the return values |
||||
""" |
||||
name, parameters, _ = self.signature |
||||
return name+'('+','.join(parameters)+')' |
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
|
@ -0,0 +1,43 @@ |
||||
""" |
||||
Module detecting unused return values from low level |
||||
""" |
||||
from slither.detectors.abstract_detector import DetectorClassification |
||||
from .unused_return_values import UnusedReturnValues |
||||
from slither.slithir.operations import LowLevelCall |
||||
|
||||
class UncheckedLowLevel(UnusedReturnValues): |
||||
""" |
||||
If the return value of a send is not checked, it might lead to losing ether |
||||
""" |
||||
|
||||
ARGUMENT = 'unchecked-lowlevel' |
||||
HELP = 'Unchecked low-level calls' |
||||
IMPACT = DetectorClassification.MEDIUM |
||||
CONFIDENCE = DetectorClassification.MEDIUM |
||||
|
||||
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-low-level' |
||||
|
||||
WIKI_TITLE = 'Unchecked low-level calls' |
||||
WIKI_DESCRIPTION = 'The return value of a low-level call is not checked.' |
||||
WIKI_EXPLOIT_SCENARIO = ''' |
||||
```solidity |
||||
contract MyConc{ |
||||
function my_func(address payable dst) public payable{ |
||||
dst.call.value(msg.value)(""); |
||||
} |
||||
} |
||||
``` |
||||
The return value of the low-level call is not checked. As a result if the callfailed, the ether will be locked in the contract. |
||||
If the low level is used to prevent blocking operations, consider logging failed calls. |
||||
''' |
||||
|
||||
WIKI_RECOMMENDATION = 'Ensure that the return value of low-level call is checked or logged.' |
||||
|
||||
_txt_description = "low-level calls" |
||||
|
||||
def _is_instance(self, ir): |
||||
return isinstance(ir, LowLevelCall) |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,40 @@ |
||||
""" |
||||
Module detecting unused return values from send |
||||
""" |
||||
|
||||
from slither.detectors.abstract_detector import DetectorClassification |
||||
from .unused_return_values import UnusedReturnValues |
||||
from slither.slithir.operations import Send |
||||
|
||||
class UncheckedSend(UnusedReturnValues): |
||||
""" |
||||
If the return value of a send is not checked, it might lead to losing ether |
||||
""" |
||||
|
||||
ARGUMENT = 'unchecked-send' |
||||
HELP = 'Unchecked send' |
||||
IMPACT = DetectorClassification.MEDIUM |
||||
CONFIDENCE = DetectorClassification.MEDIUM |
||||
|
||||
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send' |
||||
|
||||
WIKI_TITLE = 'Unchecked Send' |
||||
WIKI_DESCRIPTION = 'The return value of a send is not checked.' |
||||
WIKI_EXPLOIT_SCENARIO = ''' |
||||
```solidity |
||||
contract MyConc{ |
||||
function my_func(address payable dst) public payable{ |
||||
dst.send(msg.value); |
||||
} |
||||
} |
||||
``` |
||||
The return value of `send` is not checked. As a result if the send failed, the ether will be locked in the contract. |
||||
If `send` is used to prevent blocking operations, consider logging the failed sent. |
||||
''' |
||||
|
||||
WIKI_RECOMMENDATION = 'Ensure that the return value of send is checked or logged.' |
||||
|
||||
_txt_description = "send calls" |
||||
|
||||
def _is_instance(self, ir): |
||||
return isinstance(ir, Send) |
@ -0,0 +1,3 @@ |
||||
class SlitherException(Exception): pass |
||||
|
||||
class SlitherError(SlitherException): pass |
@ -0,0 +1,3 @@ |
||||
from slither.exceptions import SlitherException |
||||
|
||||
class SlithIRError(SlitherException): pass |
@ -0,0 +1,7 @@ |
||||
from slither.exceptions import SlitherException |
||||
|
||||
class ParsingError(SlitherException): pass |
||||
|
||||
class ParsingNameReuse(SlitherException): pass |
||||
|
||||
class ParsingContractNotFound(SlitherException): pass |
@ -0,0 +1,69 @@ |
||||
|
||||
def erc_to_signatures(erc): |
||||
return [f'{e[0]}({",".join(e[1])})' for e in erc] |
||||
|
||||
|
||||
# Final |
||||
# https://eips.ethereum.org/EIPS/eip-20 |
||||
# name, symbolc, decimals are optionals |
||||
ERC20 = [('totalSupply', [], 'uint256'), |
||||
('balanceOf', ['address'], 'uint256'), |
||||
('transfer', ['address', 'uint256'], 'bool'), |
||||
('transferFrom', ['address', 'address', 'uint256'], 'bool'), |
||||
('approve', ['address', 'uint256'], 'bool'), |
||||
('allowance', ['address', 'address'], 'uint256')] |
||||
ERC20_signatures = erc_to_signatures(ERC20) |
||||
|
||||
# Draft |
||||
# https://github.com/ethereum/eips/issues/223 |
||||
ERC223 = [('name', [], 'string'), |
||||
('symbol', [], 'string'), |
||||
('decimals', [], 'uint8'), |
||||
('totalSupply', [], 'uint256'), |
||||
('balanceOf', ['address'], 'uint256'), |
||||
('transfer', ['address', 'uint256'], 'bool'), |
||||
('transfer', ['address', 'uint256', 'bytes'], 'bool'), |
||||
('transfer', ['address', 'uint256', 'bytes', 'string'], 'bool')] |
||||
ERC223_signatures = erc_to_signatures(ERC223) |
||||
|
||||
# Final |
||||
# https://eips.ethereum.org/EIPS/eip-165 |
||||
ERC165 = [('supportsInterface', ['bytes4'], 'bool')] |
||||
ERC165_signatures = erc_to_signatures(ERC165) |
||||
|
||||
# Final |
||||
# https://eips.ethereum.org/EIPS/eip-721 |
||||
# Must have ERC165 |
||||
# name, symbol, tokenURI are optionals |
||||
ERC721 = [('balanceOf', ['address'], 'uint256'), |
||||
('ownerOf', ['uint256'], 'address'), |
||||
('safeTransferFrom', ['address', 'address', 'uint256', 'bytes'], ''), |
||||
('safeTransferFrom', ['address', 'address', 'uint256'], ''), |
||||
('transferFrom', ['address', 'address', 'uint256'], ''), |
||||
('approve', ['address', 'uint256'], ''), |
||||
('setApprovalForAll', ['address', 'bool'], ''), |
||||
('getApproved', ['uint256'], 'address'), |
||||
('isApprovedForAll', ['address', 'address'], 'bool')] + ERC165 |
||||
ERC721_signatures = erc_to_signatures(ERC721) |
||||
|
||||
# Final |
||||
# https://eips.ethereum.org/EIPS/eip-1820 |
||||
ERC1820 = [('canImplementInterfaceForAddress', ['bytes32', 'address'], 'bytes32')] |
||||
ERC1820_signatures = erc_to_signatures(ERC1820) |
||||
|
||||
# Last Call |
||||
# https://eips.ethereum.org/EIPS/eip-777 |
||||
ERC777 = [('name', [], 'string'), |
||||
('symbol', [], 'string'), |
||||
('totalSupply', [], 'uint256'), |
||||
('balanceOf', ['address'], 'uint256'), |
||||
('granularity', [], 'uint256'), |
||||
('defaultOperators', [], 'address[]'), |
||||
('isOperatorFor', ['address', 'address'], 'bool'), |
||||
('authorizeOperator', ['address'], ''), |
||||
('revokeOperator', ['address'], ''), |
||||
('send', ['address', 'uint256', 'bytes'], ''), |
||||
('operatorSend', ['address', 'address', 'uint256', 'bytes', 'bytes'], ''), |
||||
('burn', ['uint256', 'bytes'] , ''), |
||||
('operatorBurn', ['address', 'uint256', 'bytes', 'bytes'] , '')] |
||||
ERC777_signatures = erc_to_signatures(ERC777) |
@ -0,0 +1,193 @@ |
||||
from pathlib import Path |
||||
|
||||
|
||||
libraries = { |
||||
'Openzeppelin-SafeMath': lambda x: is_openzepellin_safemath(x), |
||||
'Openzeppelin-ECRecovery': lambda x: is_openzepellin_ecrecovery(x), |
||||
'Openzeppelin-Ownable': lambda x: is_openzepellin_ownable(x), |
||||
'Openzeppelin-ERC20': lambda x: is_openzepellin_erc20(x), |
||||
'Openzeppelin-ERC721': lambda x: is_openzepellin_erc721(x), |
||||
'Zos-Upgrade': lambda x: is_zos_initializable(x), |
||||
'Dapphub-DSAuth': lambda x: is_dapphub_ds_auth(x), |
||||
'Dapphub-DSMath': lambda x: is_dapphub_ds_math(x), |
||||
'Dapphub-DSToken': lambda x: is_dapphub_ds_token(x), |
||||
'Dapphub-DSProxy': lambda x: is_dapphub_ds_proxy(x), |
||||
'Dapphub-DSGroup': lambda x: is_dapphub_ds_group(x), |
||||
} |
||||
|
||||
def is_standard_library(contract): |
||||
for name, is_lib in libraries.items(): |
||||
if is_lib(contract): |
||||
return name |
||||
return None |
||||
|
||||
|
||||
################################################################################### |
||||
################################################################################### |
||||
# region General libraries |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_openzepellin(contract): |
||||
if not contract.is_from_dependency(): |
||||
return False |
||||
return 'openzeppelin-solidity' in Path(contract.source_mapping['filename_absolute']).parts |
||||
|
||||
|
||||
def is_zos(contract): |
||||
if not contract.is_from_dependency(): |
||||
return False |
||||
return 'zos-lib' in Path(contract.source_mapping['filename_absolute']).parts |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region SafeMath |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_safemath(contract): |
||||
return contract.name == "SafeMath" |
||||
|
||||
|
||||
def is_openzepellin_safemath(contract): |
||||
return is_safemath(contract) and is_openzepellin(contract) |
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region ECRecovery |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_ecrecovery(contract): |
||||
return contract.name == 'ECRecovery' |
||||
|
||||
|
||||
def is_openzepellin_ecrecovery(contract): |
||||
return is_ecrecovery(contract) and is_openzepellin(contract) |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region Ownable |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_ownable(contract): |
||||
return contract.name == 'Ownable' |
||||
|
||||
|
||||
def is_openzepellin_ownable(contract): |
||||
return is_ownable(contract) and is_openzepellin(contract) |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region ERC20 |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_erc20(contract): |
||||
return contract.name == 'ERC20' |
||||
|
||||
|
||||
def is_openzepellin_erc20(contract): |
||||
return is_erc20(contract) and is_openzepellin(contract) |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region ERC721 |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_erc721(contract): |
||||
return contract.name == 'ERC721' |
||||
|
||||
|
||||
def is_openzepellin_erc721(contract): |
||||
return is_erc721(contract) and is_openzepellin(contract) |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region Zos Initializable |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
|
||||
def is_initializable(contract): |
||||
return contract.name == 'Initializable' |
||||
|
||||
|
||||
def is_zos_initializable(contract): |
||||
return is_initializable(contract) and is_zos(contract) |
||||
|
||||
|
||||
# endregion |
||||
################################################################################### |
||||
################################################################################### |
||||
# region DappHub |
||||
################################################################################### |
||||
################################################################################### |
||||
|
||||
dapphubs = { |
||||
'DSAuth': 'ds-auth', |
||||
'DSMath': 'ds-math', |
||||
'DSToken': 'ds-token', |
||||
'DSProxy': 'ds-proxy', |
||||
'DSGroup': 'ds-group', |
||||
} |
||||
|
||||
|
||||
def _is_ds(contract, name): |
||||
return contract.name == name |
||||
|
||||
def _is_dappdhub_ds(contract, name): |
||||
if not contract.is_from_dependency(): |
||||
return False |
||||
if not dapphubs[name] in Path(contract.source_mapping['filename_absolute']).parts: |
||||
return False |
||||
return _is_ds(contract, name) |
||||
|
||||
def is_ds_auth(contract): |
||||
return _is_ds(contract, 'DSAuth') |
||||
|
||||
def is_dapphub_ds_auth(contract): |
||||
return _is_dappdhub_ds(contract, 'DSAuth') |
||||
|
||||
def is_ds_math(contract): |
||||
return _is_ds(contract, 'DSMath') |
||||
|
||||
def is_dapphub_ds_math(contract): |
||||
return _is_dappdhub_ds(contract, 'DSMath') |
||||
|
||||
def is_ds_token(contract): |
||||
return _is_ds(contract, 'DSToken') |
||||
|
||||
def is_dapphub_ds_token(contract): |
||||
return _is_dappdhub_ds(contract, 'DSToken') |
||||
|
||||
def is_ds_proxy(contract): |
||||
return _is_ds(contract, 'DSProxy') |
||||
|
||||
def is_dapphub_ds_proxy(contract): |
||||
return _is_dappdhub_ds(contract, 'DSProxy') |
||||
|
||||
def is_ds_group(contract): |
||||
return _is_ds(contract, 'DSGroup') |
||||
|
||||
def is_dapphub_ds_group(contract): |
||||
return _is_dappdhub_ds(contract, 'DSGroup') |
@ -1 +1,5 @@ |
||||
[] |
||||
{ |
||||
"success": true, |
||||
"error": null, |
||||
"results": [] |
||||
} |
@ -1,10 +0,0 @@ |
||||
Traceback (most recent call last): |
||||
File "/home/monty/Envs/slither/bin/slither", line 11, in <module> |
||||
load_entry_point('slither-analyzer', 'console_scripts', 'slither')() |
||||
File "/home/monty/Private/tob/tools/slither-public/slither/__main__.py", line 469, in main |
||||
main_impl(all_detector_classes=detectors, all_printer_classes=printers) |
||||
File "/home/monty/Private/tob/tools/slither-public/slither/__main__.py", line 483, in main_impl |
||||
detector_classes = choose_detectors(args, all_detector_classes) |
||||
File "/home/monty/Private/tob/tools/slither-public/slither/__main__.py", line 176, in choose_detectors |
||||
raise Exception('Error: {} is not a detector'.format(d)) |
||||
Exception: Error: reentrancy is not a detector |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue