API Basics
Slither has an API that allows you to explore basic attributes of contracts and their functions.
On a high level there are 6 layers:
Slither
- main slither objectSlitherCompilationUnit
- group of files used by one call to solcContract
- contract levelFunction
- function levelNode
- control flow graphSlithrIR
- intermediate representation
Watch our API walkthrough for more details
Slither object
To load a codebase:
from slither import Slither
slither = Slither('/path/to/project')
To load a contract deployed:
from slither import Slither
slither = Slither('0x..') # assuming the code is verified on etherscan
Use etherscan_api_key
to provide an Etherscan API KEY
slither = Slither('0x..', etherscan_api_key='..')
You can retrieve the list of compilation units with:
sl.compilation_units # array of SlitherCompilationUnit
SlitherCompilationUnit object
- ~ group of files used by one call to solc
- Most targets have 1 compilation, but not always true
- Partial compilation for optimization
- Multiple solc version used
- Etc..
- Why compilation unit matters?
- Some APIs might be not intuitive
- Ex: looking for a contract based on the name?
- Can have multiple contracts
- For hacking you can (probably) use the first compilation unit
compilation_unit = sl.compilation_units[0]
A SlitherCompilationUnit
has:
contracts (list(Contract))
: A list of contractscontracts_derived (list(Contract))
: A list of contracts that are not inherited by another contract (a subset of contracts)get_contract_from_name (str)
: Returns a list of contracts matching the name[structures | enums | events | variables | functions]_top_level
: Top level object
Example
from slither import Slither
sl = Slither("0xdac17f958d2ee523a2206206994597c13d831ec7")
compilation_unit = sl.compilation_units[0]
# Print all the contracts from the USDT address
print([str(c) for c in compilation_unit.contracts])
# Print the most derived contracts from the USDT address
print([str(c) for c in compilation_unit.contracts_derived])
% python test.py
['SafeMath', 'Ownable', 'ERC20Basic', 'ERC20', 'BasicToken', 'StandardToken', 'Pausable', 'BlackList', 'UpgradedStandardToken', 'TetherToken']
['SafeMath', 'UpgradedStandardToken', 'TetherToken']
Contract Object
A Contract
object has:
name: str
: The name of the contractfunctions: list[Function]
: A list of functionsmodifiers: list[Modifier]
: A list of modifiersall_functions_called: list[Function/Modifier]
: A list of all internal functions reachable by the contractinheritance: list[Contract]
: A list of inherited contracts (c3 linearization order)derived_contracts: list[Contract]
: contracts derived from itget_function_from_signature(str): Function
: Returns a Function from its signatureget_modifier_from_signature(str): Modifier
: Returns a Modifier from its signatureget_state_variable_from_name(str): StateVariable
: Returns a StateVariable from its namestate_variables: List[StateVariable]
: list of accessible variablesstate_variables_ordered: List[StateVariable]
: all variable ordered by declaration
Example
from slither import Slither
sl = Slither("0xdac17f958d2ee523a2206206994597c13d831ec7")
compilation_unit = sl.compilation_units[0]
# Print all the state variables of the USDT token
contract = compilation_unit.get_contract_from_name("TetherToken")[0]
print([str(v) for v in contract.state_variables])
% python test.py
['owner', 'paused', '_totalSupply', 'balances', 'basisPointsRate', 'maximumFee', 'allowed', 'MAX_UINT', 'isBlackListed', 'name', 'symbol', 'decimals', 'upgradedAddress', 'deprecated']
Function object
A Function
or a Modifier
object has:
name: str
: The name of the functioncontract: Contract
: The contract where the function is declarednodes: list[Node]
: A list of nodes composing the CFG of the function/modifierentry_point: Node
: The entry point of the CFG[state |local]_variable_[read |write]: list[StateVariable]
: A list of local/state variables read/write- All can be prefixed by “all_” for recursive lookup
- Ex:
all_state_variable_read
: return all the state variables read in internal calls
slithir_operations: List[Operation]
: list of IR operations
from slither import Slither
sl = Slither("0xdac17f958d2ee523a2206206994597c13d831ec7")
compilation_unit = sl.compilation_units[0]
contract = compilation_unit.get_contract_from_name("TetherToken")[0]
transfer = contract.get_function_from_signature("transfer(address,uint256)")
# Print all the state variables read by the transfer function
print([str(v) for v in transfer.state_variables_read])
# Print all the state variables read by the transfer function and its internal calls
print([str(v) for v in transfer.all_state_variables_read])
% python test.py
['deprecated', 'isBlackListed', 'upgradedAddress']
['owner', 'basisPointsRate', 'deprecated', 'paused', 'isBlackListed', 'maximumFee', 'upgradedAddress', 'balances']
Node object
To explore the nodes:
- If order does not matter
for node in function.nodes
- If order matters, walk through the nodes
def visit_node(node: Node, visited: List[Node]):
if node in visited:
return
visited += [node]
# custom action
for son in node.sons:
visit_node(son, visited)
- If need to iterate more than once (advanced usages)
- Bound the iteration X times
- Create a fix-point - abstract interpretation style analysis
SlithIR
- slither/slithir
- Every IR operation has its own methods
- Check if an operation is of a type:
isinstance(ir, TYPE)
- Ex:
isinstance(ir, Call)
- Check if the operation is an addition
isinstance(ir, Binary) & ir.type == BinaryType.ADDITION
- Check if the operation is a call to MyContract
isinstance(ir, HighLevelCall) & ir.destination == MyContract
from slither import Slither
sl = Slither("0xdac17f958d2ee523a2206206994597c13d831ec7")
compilation_unit = sl.compilation_units[0]
contract = compilation_unit.get_contract_from_name("TetherToken")[0]
totalSupply = contract.get_function_from_signature("totalSupply()")
# Print the external call made in the totalSupply function
for ir in totalSupply.slithir_operations:
if isinstance(ir, HighLevelCall):
print(f"External call found {ir} ({ir.node.source_mapping})")
% python test.py
External call found HIGH_LEVEL_CALL, […] (...TetherToken.sol#339)
Example: Print Basic Information
print_basic_information.py demonstrates how to print basic information about a project.