Merge branch 'master' into dev-json-additionalfields

pull/226/head
David Pokora 6 years ago
commit c449d99f22
No known key found for this signature in database
GPG Key ID: 3CED48D1BB21BDD7
  1. 1
      README.md
  2. 1
      scripts/tests_generate_expected_json_4.sh
  3. 32
      scripts/tests_generate_expected_json_5.sh
  4. 1
      scripts/travis_test_4.sh
  5. 2
      scripts/travis_test_5.sh
  6. 48
      slither/core/declarations/contract.py
  7. 1
      slither/core/declarations/function.py
  8. 9
      slither/core/declarations/structure.py
  9. 7
      slither/core/expressions/literal.py
  10. 4
      slither/core/solidity_types/array_type.py
  11. 1
      slither/core/variables/state_variable.py
  12. 6
      slither/detectors/all_detectors.py
  13. 0
      slither/detectors/erc/__init__.py
  14. 27
      slither/detectors/erc/incorrect_erc20_interface.py
  15. 96
      slither/detectors/erc/incorrect_erc721_interface.py
  16. 0
      slither/detectors/erc/unindexed_event_parameters.py
  17. 80
      slither/detectors/statements/too_many_digits.py
  18. 74
      slither/slithir/convert.py
  19. 48
      slither/slithir/variables/constant.py
  20. 2
      slither/solc_parsing/declarations/structure.py
  21. 16
      slither/solc_parsing/expressions/expression_parsing.py
  22. 4
      slither/solc_parsing/solidity_types/type_parsing.py
  23. 31
      slither/utils/type.py
  24. 8
      slither/visitors/expression/constants_folding.py
  25. 3
      slither/visitors/slithir/expression_to_slithir.py
  26. 218
      tests/expected_json/incorrect_erc20_interface.erc20-interface.json
  27. 9
      tests/expected_json/incorrect_erc20_interface.erc20-interface.txt
  28. 442
      tests/expected_json/incorrect_erc721_interface.erc721-interface.json
  29. 14
      tests/expected_json/incorrect_erc721_interface.erc721-interface.txt
  30. 196
      tests/expected_json/too_many_digits.too-many-digits.json
  31. 19
      tests/expected_json/too_many_digits.too-many-digits.txt
  32. 7
      tests/incorrect_erc20_interface.sol
  33. 16
      tests/incorrect_erc721_interface.sol
  34. 35
      tests/too_many_digits.sol

@ -71,6 +71,7 @@ Num | Detector | What it Detects | Impact | Confidence
30 | `pragma` | [If different pragma directives are used](https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used) | Informational | High 30 | `pragma` | [If different pragma directives are used](https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used) | Informational | High
31 | `solc-version` | [Incorrect Solidity version (< 0.4.24 or complex pragma)](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity) | Informational | High 31 | `solc-version` | [Incorrect Solidity version (< 0.4.24 or complex pragma)](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity) | Informational | High
32 | `unused-state` | [Unused state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables) | Informational | High 32 | `unused-state` | [Unused state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables) | Informational | High
33 | `too-many-digits` | [Conformance to numeric notation best practices](https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits) | Informational | Medium
[Contact us](https://www.trailofbits.com/contact/) to get access to additional detectors. [Contact us](https://www.trailofbits.com/contact/) to get access to additional detectors.

@ -23,6 +23,7 @@ generate_expected_json(){
#generate_expected_json tests/deprecated_calls.sol "deprecated-standards" #generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
#generate_expected_json tests/erc20_indexed.sol "erc20-indexed" #generate_expected_json tests/erc20_indexed.sol "erc20-indexed"
#generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface" #generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
#generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"
#generate_expected_json tests/uninitialized.sol "uninitialized-state" #generate_expected_json tests/uninitialized.sol "uninitialized-state"
#generate_expected_json tests/backdoor.sol "backdoor" #generate_expected_json tests/backdoor.sol "backdoor"
#generate_expected_json tests/backdoor.sol "suicidal" #generate_expected_json tests/backdoor.sol "suicidal"

@ -19,18 +19,20 @@ generate_expected_json(){
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename" -i sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename" -i
} }
generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state" #generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state"
generate_expected_json tests/backdoor.sol "backdoor" #generate_expected_json tests/backdoor.sol "backdoor"
generate_expected_json tests/backdoor.sol "suicidal" #generate_expected_json tests/backdoor.sol "suicidal"
generate_expected_json tests/pragma.0.4.24.sol "pragma" #generate_expected_json tests/pragma.0.4.24.sol "pragma"
generate_expected_json tests/old_solc.sol.json "solc-version" #generate_expected_json tests/old_solc.sol.json "solc-version"
generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth" #generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy" #generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy"
generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage" #generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage"
generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin" #generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin"
generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether" #generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether"
generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send" #generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send"
generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly" #generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly"
generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly" #generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly"
generate_expected_json tests/constant-0.5.1.sol "constant-function" #generate_expected_json tests/constant-0.5.1.sol "constant-function"
generate_expected_json tests/incorrect_equality.sol "incorrect-equality" #generate_expected_json tests/incorrect_equality.sol "incorrect-equality"
#generate_expected_json tests/too_many_digits.sol "too-many-digits"

@ -72,6 +72,7 @@ test_slither(){
test_slither tests/deprecated_calls.sol "deprecated-standards" test_slither tests/deprecated_calls.sol "deprecated-standards"
test_slither tests/erc20_indexed.sol "erc20-indexed" test_slither tests/erc20_indexed.sol "erc20-indexed"
test_slither tests/incorrect_erc20_interface.sol "erc20-interface" test_slither tests/incorrect_erc20_interface.sol "erc20-interface"
test_slither tests/incorrect_erc721_interface.sol "erc721-interface"
test_slither tests/uninitialized.sol "uninitialized-state" test_slither tests/uninitialized.sol "uninitialized-state"
test_slither tests/backdoor.sol "backdoor" test_slither tests/backdoor.sol "backdoor"
test_slither tests/backdoor.sol "suicidal" test_slither tests/backdoor.sol "suicidal"

@ -91,6 +91,8 @@ test_slither tests/constant-0.5.1.sol "constant-function"
test_slither tests/unused_return.sol "unused-return" test_slither tests/unused_return.sol "unused-return"
test_slither tests/timestamp.sol "timestamp" test_slither tests/timestamp.sol "timestamp"
test_slither tests/incorrect_equality.sol "incorrect-equality" test_slither tests/incorrect_equality.sol "incorrect-equality"
test_slither tests/too_many_digits.sol "too-many-digits"
### Test scripts ### Test scripts

@ -527,6 +527,14 @@ class Contract(ChildSlither, SourceMapping):
""" """
return all((not f.is_implemented) for f in self.functions) return all((not f.is_implemented) for f in self.functions)
# endregion
###################################################################################
###################################################################################
# region ERC conformance
###################################################################################
###################################################################################
def is_erc20(self): def is_erc20(self):
""" """
Check if the contract is an erc20 token Check if the contract is an erc20 token
@ -535,11 +543,49 @@ class Contract(ChildSlither, SourceMapping):
Returns: Returns:
bool bool
""" """
full_names = [f.full_name for f in self.functions] full_names = set([f.full_name for f in self.functions])
return 'transfer(address,uint256)' in full_names and\ return 'transfer(address,uint256)' in full_names and\
'transferFrom(address,address,uint256)' in full_names and\ 'transferFrom(address,address,uint256)' in full_names and\
'approve(address,uint256)' in full_names 'approve(address,uint256)' in full_names
def is_erc721(self):
full_names = set([f.full_name for f in self.functions])
return self.is_erc20() and\
'ownerOf(uint256)' in full_names and\
'safeTransferFrom(address,address,uint256,bytes)' in full_names and\
'safeTransferFrom(address,address,uint256)' in full_names and\
'setApprovalForAll(address,bool)' in full_names and\
'getApproved(uint256)' in full_names and\
'isApprovedForAll(address,address)' in full_names
def has_an_erc20_function(self):
"""
Checks if the provided contract could be attempting to implement ERC20 standards.
:param contract: The contract to check for token compatibility.
:return: Returns a boolean indicating if the provided contract met the token standard.
"""
full_names = set([f.full_name for f in self.functions])
return 'transfer(address,uint256)' in full_names or \
'transferFrom(address,address,uint256)' in full_names or \
'approve(address,uint256)' in full_names
def has_an_erc721_function(self):
"""
Checks if the provided contract could be attempting to implement ERC721 standards.
:param contract: The contract to check for token compatibility.
:return: Returns a boolean indicating if the provided contract met the token standard.
"""
full_names = set([f.full_name for f in self.functions])
return self.has_an_erc20_function() and \
('ownerOf(uint256)' in full_names or
'safeTransferFrom(address,address,uint256,bytes)' in full_names or
'safeTransferFrom(address,address,uint256)' in full_names or
'setApprovalForAll(address,bool)' in full_names or
'getApproved(uint256)' in full_names or
'isApprovedForAll(address,address)' in full_names)
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -86,6 +86,7 @@ class Function(ChildContract, SourceMapping):
self._reachable_from_nodes = set() self._reachable_from_nodes = set()
self._reachable_from_functions = set() self._reachable_from_functions = set()
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region General properties # region General properties

@ -10,6 +10,8 @@ class Structure(ChildContract, SourceMapping):
self._name = None self._name = None
self._canonical_name = None self._canonical_name = None
self._elems = None self._elems = None
# Name of the elements in the order of declaration
self._elems_ordered = None
@property @property
def canonical_name(self): def canonical_name(self):
@ -23,5 +25,12 @@ class Structure(ChildContract, SourceMapping):
def elems(self): def elems(self):
return self._elems return self._elems
@property
def elems_ordered(self):
ret = []
for e in self._elems_ordered:
ret.append(self._elems[e])
return ret
def __str__(self): def __str__(self):
return self.name return self.name

@ -2,14 +2,19 @@ from slither.core.expressions.expression import Expression
class Literal(Expression): class Literal(Expression):
def __init__(self, value): def __init__(self, value, type):
super(Literal, self).__init__() super(Literal, self).__init__()
self._value = value self._value = value
self._type = type
@property @property
def value(self): def value(self):
return self._value return self._value
@property
def type(self):
return self._type
def __str__(self): def __str__(self):
# be sure to handle any character # be sure to handle any character
return str(self._value) return str(self._value)

@ -10,7 +10,7 @@ class ArrayType(Type):
assert isinstance(t, Type) assert isinstance(t, Type)
if length: if length:
if isinstance(length, int): if isinstance(length, int):
length = Literal(length) length = Literal(length, 'uint256')
assert isinstance(length, Expression) assert isinstance(length, Expression)
super(ArrayType, self).__init__() super(ArrayType, self).__init__()
self._type = t self._type = t
@ -18,7 +18,7 @@ class ArrayType(Type):
if length: if length:
if not isinstance(length, Literal): if not isinstance(length, Literal):
cf = ConstantFolding(length) cf = ConstantFolding(length, "uint256")
length = cf.result() length = cf.result()
self._length_value = length self._length_value = length
else: else:

@ -3,7 +3,6 @@ from slither.core.children.child_contract import ChildContract
class StateVariable(ChildContract, Variable): class StateVariable(ChildContract, Variable):
@property @property
def canonical_name(self): def canonical_name(self):
return '{}:{}'.format(self.contract.name, self.name) return '{}:{}'.format(self.contract.name, self.name)

@ -28,9 +28,11 @@ from .shadowing.builtin_symbols import BuiltinSymbolShadowing
from .operations.block_timestamp import Timestamp from .operations.block_timestamp import Timestamp
from .statements.calls_in_loop import MultipleCallsInLoop from .statements.calls_in_loop import MultipleCallsInLoop
from .statements.incorrect_strict_equality import IncorrectStrictEquality from .statements.incorrect_strict_equality import IncorrectStrictEquality
from .erc20.incorrect_interface import IncorrectERC20InterfaceDetection from .erc.incorrect_erc20_interface import IncorrectERC20InterfaceDetection
from .erc20.unindexed_event_parameters import UnindexedERC20EventParameters from .erc.incorrect_erc721_interface import IncorrectERC721InterfaceDetection
from .erc.unindexed_event_parameters import UnindexedERC20EventParameters
from .statements.deprecated_calls import DeprecatedStandards from .statements.deprecated_calls import DeprecatedStandards
from .source.rtlo import RightToLeftOverride from .source.rtlo import RightToLeftOverride
from .statements.too_many_digits import TooManyDigits
# #
# #

@ -18,7 +18,7 @@ class IncorrectERC20InterfaceDetection(AbstractDetector):
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface' WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface'
WIKI_TITLE = 'Incorrect erc20 interface' WIKI_TITLE = 'Incorrect erc20 interface'
WIKI_DESCRIPTION = 'Lack of return value for the ERC20 `approve`/`transfer`/`transferFrom` functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.' WIKI_DESCRIPTION = 'Incorrect return values for ERC20 functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.'
WIKI_EXPLOIT_SCENARIO = ''' WIKI_EXPLOIT_SCENARIO = '''
```solidity ```solidity
contract Token{ contract Token{
@ -28,7 +28,7 @@ contract Token{
``` ```
`Token.transfer` does not return a boolean. Bob deploys the token. Alice creates a contract that interacts with it but assumes a correct ERC20 interface implementation. Alice's contract is unable to interact with Bob's contract.''' `Token.transfer` does not return a boolean. Bob deploys the token. Alice creates a contract that interacts with it but assumes a correct ERC20 interface implementation. Alice's contract is unable to interact with Bob's contract.'''
WIKI_RECOMMENDATION = 'Return a boolean for the `approve`/`transfer`/`transferFrom` functions.' WIKI_RECOMMENDATION = 'Set the appropriate return values and value-types for the defined ERC20 functions.'
@staticmethod @staticmethod
def incorrect_erc20_interface(signature): def incorrect_erc20_interface(signature):
@ -43,6 +43,15 @@ contract Token{
if name == 'approve' and parameters == ['address', 'uint256'] and returnVars != ['bool']: if name == 'approve' and parameters == ['address', 'uint256'] and returnVars != ['bool']:
return True return True
if name == 'allowance' and parameters == ['address', 'address'] and returnVars != ['uint256']:
return True
if name == 'balanceOf' and parameters == ['address'] and returnVars != ['uint256']:
return True
if name == 'totalSupply' and parameters == [] and returnVars != ['uint256']:
return True
return False return False
@staticmethod @staticmethod
@ -52,15 +61,23 @@ contract Token{
Returns: Returns:
list(str) : list of incorrect function signatures list(str) : list of incorrect function signatures
""" """
functions = [f for f in contract.functions if f.contract == contract and \ # Verify this is an ERC20 contract.
IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)] if not contract.has_an_erc20_function():
return []
# If this contract implements a function from ERC721, we can assume it is an ERC721 token. These tokens
# offer functions which are similar to ERC20, but are not compatible.
if contract.has_an_erc721_function():
return []
functions = [f for f in contract.functions if IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)]
return functions return functions
def _detect(self): def _detect(self):
""" Detect incorrect erc20 interface """ Detect incorrect erc20 interface
Returns: Returns:
dict: [contrat name] = set(str) events dict: [contract name] = set(str) events
""" """
results = [] results = []
for c in self.contracts: for c in self.contracts:

@ -0,0 +1,96 @@
"""
Detect incorrect erc721 interface.
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
class IncorrectERC721InterfaceDetection(AbstractDetector):
"""
Incorrect ERC721 Interface
"""
ARGUMENT = 'erc721-interface'
HELP = 'Incorrect ERC721 interfaces'
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.HIGH
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface'
WIKI_TITLE = 'Incorrect erc721 interface'
WIKI_DESCRIPTION = 'Incorrect return values for ERC721 functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.'
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract Token{
function ownerOf(uint256 _tokenId) external view returns (bool);
//...
}
```
`Token.ownerOf` does not return an address as ERC721 expects. Bob deploys the token. Alice creates a contract that interacts with it but assumes a correct ERC721 interface implementation. Alice's contract is unable to interact with Bob's contract.'''
WIKI_RECOMMENDATION = 'Set the appropriate return values and value-types for the defined ERC721 functions.'
@staticmethod
def incorrect_erc721_interface(signature):
(name, parameters, returnVars) = signature
# ERC721
if name == 'balanceOf' and parameters == ['address'] and returnVars != ['uint256']:
return True
if name == 'ownerOf' and parameters == ['uint256'] and returnVars != ['address']:
return True
if name == 'safeTransferFrom' and parameters == ['address', 'address', 'uint256', 'bytes'] and returnVars != []:
return True
if name == 'safeTransferFrom' and parameters == ['address', 'address', 'uint256'] and returnVars != []:
return True
if name == 'transferFrom' and parameters == ['address', 'address', 'uint256'] and returnVars != []:
return True
if name == 'approve' and parameters == ['address', 'uint256'] and returnVars != []:
return True
if name == 'setApprovalForAll' and parameters == ['address', 'bool'] and returnVars != []:
return True
if name == 'getApproved' and parameters == ['uint256'] and returnVars != ['address']:
return True
if name == 'isApprovedForAll' and parameters == ['address', 'address'] and returnVars != ['bool']:
return True
# ERC165 (dependency)
if name == 'supportsInterface' and parameters == ['bytes4'] and returnVars != ['bool']:
return True
return False
@staticmethod
def detect_incorrect_erc721_interface(contract):
""" Detect incorrect ERC721 interface
Returns:
list(str) : list of incorrect function signatures
"""
# Verify this is an ERC721 contract.
if not contract.has_an_erc721_function() or not contract.has_an_erc20_function():
return []
functions = [f for f in contract.functions if IncorrectERC721InterfaceDetection.incorrect_erc721_interface(f.signature)]
return functions
def _detect(self):
""" Detect incorrect erc721 interface
Returns:
dict: [contract name] = set(str) events
"""
results = []
for c in self.contracts:
functions = IncorrectERC721InterfaceDetection.detect_incorrect_erc721_interface(c)
if functions:
info = "{} ({}) has incorrect ERC721 function interface(s):\n"
info = info.format(c.name,
c.source_mapping_str)
for function in functions:
info += "\t-{} ({})\n".format(function.name, function.source_mapping_str)
json = self.generate_json_result(info)
self.add_functions_to_json(functions, json)
results.append(json)
return results

@ -0,0 +1,80 @@
"""
Module detecting numbers with too many digits.
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.variables import Constant
class TooManyDigits(AbstractDetector):
"""
Detect numbers with too many digits
"""
ARGUMENT = 'too-many-digits'
HELP = 'Conformance to numeric notation best practices'
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits'
WIKI_TITLE = 'Too many digits'
WIKI_DESCRIPTION = '''
Literals with many digits are difficult to read and review.
'''
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract MyContract{
uint 1_ether = 10000000000000000000;
}
```
While `1_ether` looks like `1 ether`, it is `10 ether`. As a result, its usage is likely to be incorrect.
'''
WIKI_RECOMMENDATION = '''
Use:
- [Ether suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#ether-units)
- [Time suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#time-units), or
- [The scientific notation](https://solidity.readthedocs.io/en/latest/types.html#rational-and-integer-literals)
'''
@staticmethod
def _detect_too_many_digits(f):
ret = []
for node in f.nodes:
# each node contains a list of IR instruction
for ir in node.irs:
# iterate over all the variables read by the IR
for read in ir.read:
# if the variable is a constant
if isinstance(read, Constant):
# read.value can return an int or a str. Convert it to str
value_as_str = read.original_value
line_of_code = str(node.expression)
if '00000' in value_as_str:
# Info to be printed
ret.append(node)
return ret
def _detect(self):
results = []
# iterate over all contracts
for contract in self.slither.contracts_derived:
# iterate over all functions
for f in contract.functions:
# iterate over all the nodes
ret = self._detect_too_many_digits(f)
if ret:
info = '{}.{} ({}) uses literals with too many digits:'.format(f.contract.name,
f.name,
f.source_mapping_str)
for node in ret:
info += '\n\t- {}'.format(node.expression)
info += '\n\tUse the proper denomination (ether-unit, time-unit,'
info += 'or the scientific notation\n'
# Add the result in result
json = self.generate_json_result(info)
self.add_nodes_to_json(ret, json)
results.append(json)
return results

@ -7,7 +7,9 @@ from slither.core.expressions import Identifier, Literal
from slither.core.solidity_types import (ArrayType, ElementaryType, from slither.core.solidity_types import (ArrayType, ElementaryType,
FunctionType, MappingType, FunctionType, MappingType,
UserDefinedType) UserDefinedType)
from slither.core.solidity_types.elementary_type import Int as ElementaryTypeInt
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import (Assignment, Balance, Binary, from slither.slithir.operations import (Assignment, Balance, Binary,
BinaryType, Call, Condition, Delete, BinaryType, Call, Condition, Delete,
EventCall, HighLevelCall, Index, EventCall, HighLevelCall, Index,
@ -30,6 +32,7 @@ from slither.slithir.variables import (Constant, ReferenceVariable,
TemporaryVariable) TemporaryVariable)
from slither.visitors.slithir.expression_to_slithir import ExpressionToSlithIR from slither.visitors.slithir.expression_to_slithir import ExpressionToSlithIR
from slither.utils.function import get_function_id from slither.utils.function import get_function_id
from slither.utils.type import export_nested_types_from_variable
logger = logging.getLogger('ConvertToIR') logger = logging.getLogger('ConvertToIR')
@ -39,7 +42,8 @@ def convert_expression(expression, node):
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
if isinstance(expression, Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]: if isinstance(expression, Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]:
result = [Condition(Constant(expression.value))] cst = Constant(expression.value, expression.type)
result = [Condition(cst)]
return result return result
if isinstance(expression, Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]: if isinstance(expression, Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]:
result = [Condition(expression.value)] result = [Condition(expression.value)]
@ -599,7 +603,7 @@ def convert_to_push(ir, node):
ir = Push(ir.destination, val) ir = Push(ir.destination, val)
length = Literal(len(operation.init_values)) length = Literal(len(operation.init_values), 'uint256')
t = operation.init_values[0].type t = operation.init_values[0].type
ir.lvalue.set_type(ArrayType(t, length)) ir.lvalue.set_type(ArrayType(t, length))
@ -822,6 +826,71 @@ def remove_unused(result):
result = [i for i in result if not i in to_remove] result = [i for i in result if not i in to_remove]
return result return result
# endregion
###################################################################################
###################################################################################
# region Constant type conversioh
###################################################################################
###################################################################################
def convert_constant_types(irs):
"""
late conversion of uint -> type for constant (Literal)
:param irs:
:return:
"""
# TODO: implement instances lookup for events, NewContract
was_changed = True
while was_changed:
was_changed = False
for ir in irs:
if isinstance(ir, Assignment):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
if ir.rvalue.type.type != 'int256':
ir.rvalue.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, Binary):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
for r in ir.read:
if r.type.type != 'int256':
r.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, (HighLevelCall, InternalCall)):
func = ir.function
if isinstance(func, StateVariable):
types = export_nested_types_from_variable(func)
else:
types = [p.type for p in func.parameters]
for idx, arg in enumerate(ir.arguments):
t = types[idx]
if isinstance(t, ElementaryType):
if t.type in ElementaryTypeInt:
if arg.type.type != 'int256':
arg.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, NewStructure):
st = ir.structure
for idx, arg in enumerate(ir.arguments):
e = st.elems_ordered[idx]
if isinstance(e.type, ElementaryType):
if e.type.type in ElementaryTypeInt:
if arg.type.type != 'int256':
arg.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, InitArray):
if isinstance(ir.lvalue.type, ArrayType):
if isinstance(ir.lvalue.type.type, ElementaryType):
if ir.lvalue.type.type.type in ElementaryTypeInt:
for r in ir.read:
if r.type.type != 'int256':
r.set_type(ElementaryType('int256'))
was_changed = True
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -839,6 +908,7 @@ def apply_ir_heuristics(irs, node):
irs = propagate_type_and_convert_call(irs, node) irs = propagate_type_and_convert_call(irs, node)
irs = remove_unused(irs) irs = remove_unused(irs)
find_references_origin(irs) find_references_origin(irs)
convert_constant_types(irs)
return irs return irs

@ -1,17 +1,41 @@
from .variable import SlithIRVariable from .variable import SlithIRVariable
from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
class Constant(SlithIRVariable): class Constant(SlithIRVariable):
def __init__(self, val): def __init__(self, val, type=None):
super(Constant, self).__init__() super(Constant, self).__init__()
assert isinstance(val, str) assert isinstance(val, str)
if val.isdigit():
self._type = ElementaryType('uint256') self._original_value = val
self._val = int(val)
if type:
assert isinstance(type, ElementaryType)
self._type = type
if type.type in Int + Uint:
if val.startswith('0x'):
self._val = int(val, 16)
else:
if 'e' in val:
base, expo = val.split('e')
self._val = int(float(base)* (10 ** int(expo)))
elif 'E' in val:
base, expo = val.split('E')
self._val = int(float(base) * (10 ** int(expo)))
else:
self._val = int(val)
elif type.type == 'bool':
self._val = val == 'true'
else:
self._val = val
else: else:
self._type = ElementaryType('string') if val.isdigit():
self._val = val self._type = ElementaryType('uint256')
self._val = int(val)
else:
self._type = ElementaryType('string')
self._val = val
@property @property
def value(self): def value(self):
@ -20,10 +44,18 @@ class Constant(SlithIRVariable):
If the expression was an hexadecimal delcared as hex'...' If the expression was an hexadecimal delcared as hex'...'
return a str return a str
Returns: Returns:
(str, int) (str | int | bool)
''' '''
return self._val return self._val
@property
def original_value(self):
'''
Return the string representation of the value
:return: str
'''
return self._original_value
def __str__(self): def __str__(self):
return str(self.value) return str(self.value)

@ -16,6 +16,7 @@ class StructureSolc(Structure):
self._name = name self._name = name
self._canonical_name = canonicalName self._canonical_name = canonicalName
self._elems = {} self._elems = {}
self._elems_ordered = []
self._elemsNotParsed = elems self._elemsNotParsed = elems
@ -28,5 +29,6 @@ class StructureSolc(Structure):
elem.analyze(self.contract) elem.analyze(self.contract)
self._elems[elem.name] = elem self._elems[elem.name] = elem
self._elems_ordered.append(elem.name)
self._elemsNotParsed = [] self._elemsNotParsed = []

@ -479,6 +479,12 @@ def parse_expression(expression, caller_context):
value = str(convert_subdenomination(value, expression['subdenomination'])) value = str(convert_subdenomination(value, expression['subdenomination']))
elif not value and value != "": elif not value and value != "":
value = '0x'+expression['hexValue'] value = '0x'+expression['hexValue']
type = expression['typeDescriptions']['typeString']
# Length declaration for array was None until solc 0.5.5
if type is None:
if expression['kind'] == 'number':
type = 'int_const'
else: else:
value = expression['attributes']['value'] value = expression['attributes']['value']
if value: if value:
@ -489,7 +495,15 @@ def parse_expression(expression, caller_context):
# see https://solidity.readthedocs.io/en/v0.4.25/types.html?highlight=hex#hexadecimal-literals # see https://solidity.readthedocs.io/en/v0.4.25/types.html?highlight=hex#hexadecimal-literals
assert 'hexvalue' in expression['attributes'] assert 'hexvalue' in expression['attributes']
value = '0x'+expression['attributes']['hexvalue'] value = '0x'+expression['attributes']['hexvalue']
literal = Literal(value) type = expression['attributes']['type']
if type.startswith('int_const '):
type = ElementaryType('uint256')
elif type.startswith('bool'):
type = ElementaryType('bool')
else:
type = ElementaryType('string')
literal = Literal(value, type)
return literal return literal
elif name == 'Identifier': elif name == 'Identifier':

@ -32,7 +32,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
if name_elementary in ElementaryTypeName: if name_elementary in ElementaryTypeName:
depth = name.count('[') depth = name.count('[')
if depth: if depth:
return ArrayType(ElementaryType(name_elementary), Literal(depth)) return ArrayType(ElementaryType(name_elementary), Literal(depth, 'uint256'))
else: else:
return ElementaryType(name_elementary) return ElementaryType(name_elementary)
# We first look for contract # We first look for contract
@ -78,7 +78,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
depth+=1 depth+=1
var_type = next((st for st in all_structures if st.contract.name+"."+st.name == name_struct), None) var_type = next((st for st in all_structures if st.contract.name+"."+st.name == name_struct), None)
if var_type: if var_type:
return ArrayType(UserDefinedType(var_type), Literal(depth)) return ArrayType(UserDefinedType(var_type), Literal(depth, 'uint256'))
if not var_type: if not var_type:
var_type = next((f for f in contract.functions if f.name == name), None) var_type = next((f for f in contract.functions if f.name == name), None)

@ -0,0 +1,31 @@
from slither.core.solidity_types import (ArrayType, MappingType, ElementaryType)
def _add_mapping_parameter(t, l):
while isinstance(t, MappingType):
l.append(t.type_from)
t = t.type_to
_add_array_parameter(t, l)
def _add_array_parameter(t, l):
while isinstance(t, ArrayType):
l.append(ElementaryType('uint256'))
t = t.type
def export_nested_types_from_variable(variable):
"""
Export the list of nested types (mapping/array)
:param variable:
:return: list(Type)
"""
l = []
if isinstance(variable.type, MappingType):
t = variable.type
_add_mapping_parameter(t, l)
if isinstance(variable.type, ArrayType):
v = variable
_add_array_parameter(v.type, l)
return l

@ -20,8 +20,12 @@ def set_val(expression, val):
class ConstantFolding(ExpressionVisitor): class ConstantFolding(ExpressionVisitor):
def __init__(self, expression, type):
super(ConstantFolding, self).__init__(expression)
self._type = type
def result(self): def result(self):
return Literal(int(get_val(self._expression))) return Literal(int(get_val(self._expression)), self._type)
def _post_identifier(self, expression): def _post_identifier(self, expression):
if not expression.value.is_constant: if not expression.value.is_constant:
@ -29,7 +33,7 @@ class ConstantFolding(ExpressionVisitor):
expr = expression.value.expression expr = expression.value.expression
# assumption that we won't have infinite loop # assumption that we won't have infinite loop
if not isinstance(expr, Literal): if not isinstance(expr, Literal):
cf = ConstantFolding(expr) cf = ConstantFolding(expr, self._type)
expr = cf.result() expr = cf.result()
set_val(expression, int(expr.value)) set_val(expression, int(expr.value))

@ -173,7 +173,8 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, val) set_val(expression, val)
def _post_literal(self, expression): def _post_literal(self, expression):
set_val(expression, Constant(expression.value)) cst = Constant(expression.value, expression.type)
set_val(expression, cst)
def _post_member_access(self, expression): def _post_member_access(self, expression):
expr = get(expression.expression) expr = get(expression.expression)

@ -3,20 +3,184 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-7) has incorrect ERC20 function interface(s):\n\t-transfer (tests/incorrect_erc20_interface.sol#5)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface(s):\n\t-transfer (tests/incorrect_erc20_interface.sol#4)\n\t-approve (tests/incorrect_erc20_interface.sol#5)\n\t-transferFrom (tests/incorrect_erc20_interface.sol#6)\n\t-totalSupply (tests/incorrect_erc20_interface.sol#7)\n\t-balanceOf (tests/incorrect_erc20_interface.sol#8)\n\t-allowance (tests/incorrect_erc20_interface.sol#9)\n",
"elements": [ "elements": [
{
"type": "function",
"name": "allowance",
"source_mapping": {
"start": 319,
"length": 60,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
9
],
"starting_column": 5,
"ending_column": 65
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 26,
"length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
3,
4,
5,
6,
7,
8,
9,
10
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "approve",
"source_mapping": {
"start": 102,
"length": 55,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
5
],
"starting_column": 5,
"ending_column": 60
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 26,
"length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
3,
4,
5,
6,
7,
8,
9,
10
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "balanceOf",
"source_mapping": {
"start": 273,
"length": 41,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
8
],
"starting_column": 5,
"ending_column": 46
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 26,
"length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
3,
4,
5,
6,
7,
8,
9,
10
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "totalSupply",
"source_mapping": {
"start": 236,
"length": 32,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
7
],
"starting_column": 5,
"ending_column": 37
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 26,
"length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
3,
4,
5,
6,
7,
8,
9,
10
],
"starting_column": 1,
"ending_column": 2
}
}
},
{ {
"type": "function", "type": "function",
"name": "transfer", "name": "transfer",
"source_mapping": { "source_mapping": {
"start": 47, "start": 46,
"length": 51, "length": 51,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol", "filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol", "filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol", "filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol", "filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [ "lines": [
5 4
], ],
"starting_column": 5, "starting_column": 5,
"ending_column": 56 "ending_column": 56
@ -26,7 +190,48 @@
"name": "Token", "name": "Token",
"source_mapping": { "source_mapping": {
"start": 26, "start": 26,
"length": 75, "length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
3,
4,
5,
6,
7,
8,
9,
10
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "transferFrom",
"source_mapping": {
"start": 162,
"length": 69,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_short": "tests/incorrect_erc20_interface.sol",
"lines": [
6
],
"starting_column": 5,
"ending_column": 74
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 26,
"length": 355,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol", "filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
"filename_relative": "tests/incorrect_erc20_interface.sol", "filename_relative": "tests/incorrect_erc20_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol", "filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc20_interface.sol",
@ -36,7 +241,10 @@
4, 4,
5, 5,
6, 6,
7 7,
8,
9,
10
], ],
"starting_column": 1, "starting_column": 1,
"ending_column": 2 "ending_column": 2

@ -1,5 +1,10 @@
INFO:Detectors: INFO:Detectors:
Token (tests/incorrect_erc20_interface.sol#3-7) has incorrect ERC20 function interface(s): Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface(s):
-transfer (tests/incorrect_erc20_interface.sol#5) -transfer (tests/incorrect_erc20_interface.sol#4)
-approve (tests/incorrect_erc20_interface.sol#5)
-transferFrom (tests/incorrect_erc20_interface.sol#6)
-totalSupply (tests/incorrect_erc20_interface.sol#7)
-balanceOf (tests/incorrect_erc20_interface.sol#8)
-allowance (tests/incorrect_erc20_interface.sol#9)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface
INFO:Slither:tests/incorrect_erc20_interface.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/incorrect_erc20_interface.sol analyzed (1 contracts), 1 result(s) found

@ -0,0 +1,442 @@
[
{
"check": "erc721-interface",
"impact": "Medium",
"confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface(s):\n\t-supportsInterface (tests/incorrect_erc721_interface.sol#4)\n\t-balanceOf (tests/incorrect_erc721_interface.sol#7)\n\t-ownerOf (tests/incorrect_erc721_interface.sol#8)\n\t-safeTransferFrom (tests/incorrect_erc721_interface.sol#9)\n\t-safeTransferFrom (tests/incorrect_erc721_interface.sol#10)\n\t-transferFrom (tests/incorrect_erc721_interface.sol#11)\n\t-approve (tests/incorrect_erc721_interface.sol#12)\n\t-setApprovalForAll (tests/incorrect_erc721_interface.sol#13)\n\t-getApproved (tests/incorrect_erc721_interface.sol#14)\n\t-isApprovedForAll (tests/incorrect_erc721_interface.sol#15)\n",
"elements": [
{
"type": "function",
"name": "approve",
"source_mapping": {
"start": 549,
"length": 78,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
12
],
"starting_column": 5,
"ending_column": 83
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "balanceOf",
"source_mapping": {
"start": 140,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
7
],
"starting_column": 5,
"ending_column": 49
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "getApproved",
"source_mapping": {
"start": 723,
"length": 48,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
14
],
"starting_column": 5,
"ending_column": 53
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "isApprovedForAll",
"source_mapping": {
"start": 776,
"length": 70,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
15
],
"starting_column": 5,
"ending_column": 75
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "ownerOf",
"source_mapping": {
"start": 189,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
8
],
"starting_column": 5,
"ending_column": 49
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "safeTransferFrom",
"source_mapping": {
"start": 238,
"length": 108,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
9
],
"starting_column": 5,
"ending_column": 113
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "safeTransferFrom",
"source_mapping": {
"start": 351,
"length": 96,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
10
],
"starting_column": 5,
"ending_column": 101
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "setApprovalForAll",
"source_mapping": {
"start": 632,
"length": 86,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
13
],
"starting_column": 5,
"ending_column": 91
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "supportsInterface",
"source_mapping": {
"start": 50,
"length": 56,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
4
],
"starting_column": 5,
"ending_column": 61
},
"contract": {
"type": "contract",
"name": "IERC165",
"source_mapping": {
"start": 26,
"length": 82,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
3,
4,
5
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "function",
"name": "transferFrom",
"source_mapping": {
"start": 452,
"length": 92,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
11
],
"starting_column": 5,
"ending_column": 97
},
"contract": {
"type": "contract",
"name": "Token",
"source_mapping": {
"start": 109,
"length": 739,
"filename_used": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_relative": "tests/incorrect_erc721_interface.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/incorrect_erc721_interface.sol",
"filename_short": "tests/incorrect_erc721_interface.sol",
"lines": [
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"starting_column": 1,
"ending_column": 2
}
}
}
]
}
]

@ -0,0 +1,14 @@
INFO:Detectors:
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface(s):
-supportsInterface (tests/incorrect_erc721_interface.sol#4)
-balanceOf (tests/incorrect_erc721_interface.sol#7)
-ownerOf (tests/incorrect_erc721_interface.sol#8)
-safeTransferFrom (tests/incorrect_erc721_interface.sol#9)
-safeTransferFrom (tests/incorrect_erc721_interface.sol#10)
-transferFrom (tests/incorrect_erc721_interface.sol#11)
-approve (tests/incorrect_erc721_interface.sol#12)
-setApprovalForAll (tests/incorrect_erc721_interface.sol#13)
-getApproved (tests/incorrect_erc721_interface.sol#14)
-isApprovedForAll (tests/incorrect_erc721_interface.sol#15)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface
INFO:Slither:tests/incorrect_erc721_interface.sol analyzed (2 contracts), 1 result(s) found

@ -0,0 +1,196 @@
[
{
"check": "too-many-digits",
"impact": "Informational",
"confidence": "Medium",
"description": "C.f (tests/too_many_digits.sol#9-15) uses literals with too many digits:\n\t- x1 = 0x000001\n\t- x2 = 0x0000000000001\n\t- x3 = 1000000000000000000\n\t- x4 = 100000\n\tUse the proper denomination (ether-unit, time-unit,or the scientific notation\n",
"elements": [
{
"type": "expression",
"expression": "x1 = 0x000001",
"source_mapping": {
"start": 206,
"length": 18,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
10
],
"starting_column": 9,
"ending_column": 27
}
},
{
"type": "expression",
"expression": "x2 = 0x0000000000001",
"source_mapping": {
"start": 234,
"length": 25,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
11
],
"starting_column": 9,
"ending_column": 34
}
},
{
"type": "expression",
"expression": "x3 = 1000000000000000000",
"source_mapping": {
"start": 269,
"length": 29,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
12
],
"starting_column": 9,
"ending_column": 38
}
},
{
"type": "expression",
"expression": "x4 = 100000",
"source_mapping": {
"start": 308,
"length": 16,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
13
],
"starting_column": 9,
"ending_column": 25
}
}
]
},
{
"check": "too-many-digits",
"impact": "Informational",
"confidence": "Medium",
"description": "C.h (tests/too_many_digits.sol#20-24) uses literals with too many digits:\n\t- x2 = 100000\n\tUse the proper denomination (ether-unit, time-unit,or the scientific notation\n",
"elements": [
{
"type": "expression",
"expression": "x2 = 100000",
"source_mapping": {
"start": 509,
"length": 16,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
22
],
"starting_column": 9,
"ending_column": 25
}
}
]
},
{
"check": "too-many-digits",
"impact": "Informational",
"confidence": "Medium",
"description": "C.i (tests/too_many_digits.sol#29-33) uses literals with too many digits:\n\t- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000\n\t- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000\n\t- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000\n\t- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000\n\t- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000\n\tUse the proper denomination (ether-unit, time-unit,or the scientific notation\n",
"elements": [
{
"type": "expression",
"expression": "x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000",
"source_mapping": {
"start": 749,
"length": 67,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
31
],
"starting_column": 9,
"ending_column": 76
}
},
{
"type": "expression",
"expression": "x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000",
"source_mapping": {
"start": 749,
"length": 67,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
31
],
"starting_column": 9,
"ending_column": 76
}
},
{
"type": "expression",
"expression": "x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000",
"source_mapping": {
"start": 749,
"length": 67,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
31
],
"starting_column": 9,
"ending_column": 76
}
},
{
"type": "expression",
"expression": "x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000",
"source_mapping": {
"start": 749,
"length": 67,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
31
],
"starting_column": 9,
"ending_column": 76
}
},
{
"type": "expression",
"expression": "x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000",
"source_mapping": {
"start": 749,
"length": 67,
"filename_used": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_relative": "tests/too_many_digits.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/too_many_digits.sol",
"filename_short": "tests/too_many_digits.sol",
"lines": [
31
],
"starting_column": 9,
"ending_column": 76
}
}
]
}
]

@ -0,0 +1,19 @@
INFO:Detectors:
C.f (tests/too_many_digits.sol#9-15) uses literals with too many digits:
- x1 = 0x000001
- x2 = 0x0000000000001
- x3 = 1000000000000000000
- x4 = 100000
Use the proper denomination (ether-unit, time-unit,or the scientific notation
C.h (tests/too_many_digits.sol#20-24) uses literals with too many digits:
- x2 = 100000
Use the proper denomination (ether-unit, time-unit,or the scientific notation
C.i (tests/too_many_digits.sol#29-33) uses literals with too many digits:
- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000
- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000
- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000
- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000
- x2 = 1000000000000 + 10000000000000 + 100000000000000 + 1000000000000000 + 10000000000000000
Use the proper denomination (ether-unit, time-unit,or the scientific notation
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits
INFO:Slither:tests/too_many_digits.sol analyzed (1 contracts), 3 result(s) found

@ -1,7 +1,10 @@
pragma solidity ^0.4.24; pragma solidity ^0.4.24;
contract Token{ contract Token{
function transfer(address to, uint value) external; function transfer(address to, uint value) external;
function approve(address spender, uint value) external;
function transferFrom(address from, address to, uint value) external;
function totalSupply() external;
function balanceOf(address who) external;
function allowance(address owner, address spender) external;
} }

@ -0,0 +1,16 @@
pragma solidity ^0.4.24;
interface IERC165 {
function supportsInterface(bytes4 interfaceID) external;
}
contract Token is IERC165{
function balanceOf(address _owner) external;
function ownerOf(uint256 _tokenId) external;
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external returns (bool);
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) external returns (bool);
function approve(address _approved, uint256 _tokenId) external returns (bool);
function setApprovalForAll(address _operator, bool _approved) external returns (bool);
function getApproved(uint256 _tokenId) external;
function isApprovedForAll(address _owner, address _operator) external;
}

@ -0,0 +1,35 @@
pragma solidity ^0.5.1;
contract C {
uint balance;
/**
* @dev Variables are not Ok - using too many digits in place of the Ether denomination.
*/
function f() external {
uint x1 = 0x000001;
uint x2 = 0x0000000000001;
uint x3 = 1000000000000000000;
uint x4 = 100000;
balance += x1 + x2 + x3 + x4;
}
/**
* @dev Variables are Ok - not using too many digits.
*/
function h() external {
uint x1 = 1000;
uint x2 = 100000;
balance += x1 + x2 + 100;
}
/**
* @dev Variables are Ok - Using Ether denominations.
*/
function i() external {
uint x1 = 1 wei + 10 wei + 100 wei + 1000 wei + 10000 wei;
uint x2 = 1 szabo + 10 szabo + 100 szabo + 1000 szabo + 10000 szabo;
balance += x1 + x2;
}
}
Loading…
Cancel
Save