# Slither
![](https://i.imgur.com/SbzE5Sx.png)
Slither is a Solidity static analysis framework written in Python 3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses.
## How to install
*Slither requires Python 3.6+ and solc, the Solidity compiler.*
https://github.com/crytic/slither/wiki/Developer-installation
### Using Pip
`pip3 install slither-analyzer`
`sudo npm install -g solc`
then install `solc-select`
```
python3 -m pip install solc-select
solc-select versions
solc-select use 0.8.10
```
## Detector
Detector is severity detector which will warning or alarm you when it has detect some vulnerability.
ref: https://github.com/crytic/slither/wiki/Detector-Documentation
### Q1:
```
contract BaseContract{
address owner;
modifier isOwner(){
require(owner == msg.sender);
_;
}
}
contract DerivedContract is BaseContract{
address owner;
constructor(){
owner = msg.sender;
}
function withdraw() isOwner() external{
msg.sender.transfer(this.balance);
}
}
```
### State variable shadowing
```
contract BaseContract{
address owner;
modifier isOwner(){
require(owner == msg.sender);
_;
}
}
contract DerivedContract is BaseContract{
address owner;
constructor(){
owner = msg.sender;
}
function withdraw() isOwner() external{
msg.sender.transfer(this.balance);
}
}
```
`owner` of BaseContract is never assigned and the modifier `isOwner` does not work.
### Q2:
```
contract Memory {
uint[1] public x; // storage
function f() public {
f1(x);
f2(x);
}
function f1(uint[1] storage arr) internal {
arr[0] = 1;
}
function f2(uint[1] arr) internal {
arr[0] = 2;
}
}
```
### Modifying storage array by value
#### Description
Detect arrays passed to a function that expects reference to a storage array
#### Exploit Scenario:
```
contract Memory {
uint[1] public x; // storage
function f() public {
f1(x); // update x
f2(x); // do not update x
}
function f1(uint[1] storage arr) internal { // by reference
arr[0] = 1;
}
function f2(uint[1] arr) internal { // by value
arr[0] = 2;
}
}
```
Bob calls f(). Bob assumes that at the end of the call x[0] is 2, but it is 1. As a result, Bob's usage of the contract is incorrect.
#### Recommendation
Ensure the correct usage of memory and storage in the function parameters. Make all the locations explicit.
### Q3:
```
contract Uninitialized{
address owner = msg.sender;
struct St{
uint a;
}
function func() {
St st;
st.a = 0x0;
}
}
```
### Uninitialized storage variables
#### Description
An uninitialized storage variable will act as a reference to the first state variable, and can override a critical variable.
#### Exploit Scenario:
```
contract Uninitialized{
address owner = msg.sender;
struct St{
uint a;
}
function func() {
St st;
st.a = 0x0;
}
}
```
Bob calls `func`. As a result, owner is overridden to `0`.
#### Recommendation
Initialize all storage variables.
### Q4:
```
contract Token {
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}
contract MyBank{
mapping(address => uint) balances;
Token token;
function deposit(uint amount) public{
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
}
}
```
### Unchecked transfer
#### Description
The return value of an external transfer/transferFrom call is not checked
#### Exploit Scenario:
```
contract Token {
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}
contract MyBank{
mapping(address => uint) balances;
Token token;
function deposit(uint amount) public{
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount;
}
}
```
Several tokens do not revert in case of failure and return false. If one of these tokens is used in MyBank, deposit will not revert if the transfer fails, and an attacker can call deposit for free..
#### Recommendation
Use SafeERC20, or ensure that the transfer/transferFrom return value is checked.
## Printers
Printer will print contract information follow by printer format
List of all printers from: https://github.com/crytic/slither/wiki/Printer-documentation
### Install dependencies
`brew install graphviz`
`brew install xdot`
### Print call graph
- Generate `.dot` file
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print call-graph
```
![](https://i.imgur.com/PPxtAYo.png)
- Generate `.dot` file to `.png` file
```
dot contracts/AlphaStaking.sol.all_contracts.call-graph.dot -Tpng -o contracts/AlphaStaking.sol.png
```
![](https://i.imgur.com/cw4YjI3.png)
#### Print contract summary
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print contract-summary
```
![](https://i.imgur.com/hC88MDe.png)
#### Print human summary
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print human-summary
```
![](https://i.imgur.com/RSk01YA.png)
#### Print inheritance-graph
* Use below command to generate graph
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print inheritance-graph
```
* Use `xdot` to view graph
```
xdot contracts/AlphaStaking.sol.inheritance-graph.dot
```
![](https://i.imgur.com/FqzlZCC.png)
#### Print data dependency
Print the data dependencies of the variables
Run below command
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print function-id
```
Result
```
Function extract(uint256)
+---------------------------------+--------------------------------------+
| Variable | Dependencies |
+---------------------------------+--------------------------------------+
| amount | [] |
| Initializable._initialized | [] |
| Initializable._initializing | [] |
| ReentrancyGuard._NOT_ENTERED | [] |
| ReentrancyGuard._ENTERED | [] |
| ReentrancyGuard._status | [] |
| AlphaStaking.STATUS_READY | [] |
| AlphaStaking.STATUS_UNBONDING | [] |
| AlphaStaking.UNBONDING_DURATION | [] |
| AlphaStaking.WITHDRAW_DURATION | [] |
| AlphaStaking.alpha | ['alpha'] |
| AlphaStaking.governor | [] |
| AlphaStaking.pendingGovernor | [] |
| AlphaStaking.worker | [] |
| AlphaStaking.totalAlpha | ['totalAlpha', 'amount', 'SafeMath'] |
| AlphaStaking.totalShare | [] |
| AlphaStaking.users | [] |
+---------------------------------+--------------------------------------+
```
#### Print function id
Run below command
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --print function-id
```
Result
```
AlphaStaking:
+-----------------------------+------------+
| Name | ID |
+-----------------------------+------------+
| initialize(address,address) | 0x485cc955 |
| setWorker(address) | 0xc26f6d44 |
| setPendingGovernor(address) | 0xf235757f |
| acceptGovernor() | 0xe58bb639 |
| getStakeValue(address) | 0x96802374 |
| stake(uint256) | 0xa694fc3a |
| unbond(uint256) | 0x27de9e32 |
| withdraw() | 0x3ccfd60b |
| reward(uint256) | 0xa9fb763c |
| skim(uint256) | 0x6939aaf5 |
| extract(uint256) | 0x85b39782 |
| STATUS_READY() | 0x20e5a06b |
| STATUS_UNBONDING() | 0x146191f6 |
| UNBONDING_DURATION() | 0xe59357a7 |
| WITHDRAW_DURATION() | 0x77913322 |
| alpha() | 0xdb1d0fd5 |
| governor() | 0x0c340a24 |
| pendingGovernor() | 0xe3056a34 |
| worker() | 0x4d547ada |
| totalAlpha() | 0xcd2d5e44 |
| totalShare() | 0x026c4207 |
| users(address) | 0xa87430ba |
+-----------------------------+------------+
```
## ERC20 Conformance
`slither-check-erc` will check that:
* All the functions are present
* All the events are present
* Functions return the correct type
* Functions that must be view are view
* Events' parameters are correctly indexed
* The functions emit the events
* Derived contracts do not break the conformance
```
slither-check-erc contracts/Alpha.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin Alpha
```
then you will get the result
```
## Check functions
[✓] totalSupply() is present
[✓] totalSupply() -> () (correct return value)
[✓] totalSupply() is view
[✓] balanceOf(address) is present
[✓] balanceOf(address) -> () (correct return value)
[✓] balanceOf(address) is view
[✓] transfer(address,uint256) is present
[✓] transfer(address,uint256) -> () (correct return value)
[✓] Transfer(address,address,uint256) is emitted
...
```
## Upgradeability Checks
https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-v2
```
slither-check-upgradeability contracts/AlphaStakingV2.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin AlphaStakingV2 --new-contract-filename contracts/AlphaStakingV3.sol --new-contract-name AlphaStakingV3
```
Result
```
Different variables between AlphaStakingV2 (contracts/AlphaStakingV2.sol#9-144) and AlphaStakingV3 (contracts/AlphaStakingV3.sol#9-152)
AlphaStakingV2.alpha (contracts/AlphaStakingV2.sol#33)
AlphaStakingV3.alpha (contracts/AlphaStakingV3.sol#34)
Different variables between AlphaStakingV2 (contracts/AlphaStakingV2.sol#9-144) and AlphaStakingV3 (contracts/AlphaStakingV3.sol#9-152)
AlphaStakingV2.users (contracts/AlphaStakingV2.sol#39)
AlphaStakingV3.users (contracts/AlphaStakingV3.sol#40)
Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-v2
```
*Still found some false detected*
## Code Similarity
https://github.com/crytic/slither/wiki/Code-Similarity-detector
## Slither with brownie 🐕🦺
### Running Slither with Brownie hack
* Due to the interfaces compilation issue, create symbolic link from `interfaces` folder to `contracts` folder
```
ln -s /staking-tier-contracts/interfaces /staking-tier-contracts/contracts
```
* Run `slither .` to analyze all contracts
* Slither analyze vulnerability then show the result
![](https://i.imgur.com/GL7tspQ.png)
## Triage mode
* Use Triage mode to select which log you want to show
`slither . --triage`
* Sliter will show a list of type of detector
![](https://i.imgur.com/uK0gfUo.png)
* Select the type you want to hide e.g.`0, 2` to continue
Type `All` if you want to hide all type of detectors
* Slither will create `slither.db.json` for detector that is hided.
* Delete element on `slither.db.json` to bring back detector
## Detector Selection
* Use `slither --list-detectors` to show all detectors
* Use `--detect <detector>` to show only the result of given detector
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --detect <detector-name>
```
e.g.
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --detect arbitrary-send,pragma
```
result
![](https://i.imgur.com/Bv6sFTl.png)
* Use `--exclude` to exclude some detectors
e.g. to exclude pragma
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --exclude pragma
```
e.g. to exclude low severity
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --exclude-low
```
## Configuration file
If you don't want to config all options on CLI command. You can create config file call `slither.config.json` then config your interested detector or printer as this format
```
{
"detectors_to_run": "unused-state,costly-loop,external-function,naming-convention,pragma",
"printers_to_run": "contract-summary,human-summary",
"detectors_to_exclude": "",
"exclude_informational": false,
"exclude_low": false,
"exclude_medium": false,
"exclude_high": false,
"json": "",
"disable_color": false,
"filter_paths": "file1.sol,file2.sol",
"legacy_ast": false
}
```
then run with below command. the result will print to result.json
```
slither contracts/AlphaStaking.sol --solc-remaps OpenZeppelin=/Users/$(whoami)/.brownie/packages/OpenZeppelin --json result.json
```
### Running Slither with brownie is still have the problem as each issue isn't resolve:
![](https://i.imgur.com/nZQu9Ux.png)
- Add Support for Brownie
https://github.com/crytic/slither/issues/638
- Fix brownie issue
https://github.com/crytic/crytic-compile/issues/165
- Brownie does not generate proper compilation artifacts for interfaces
https://github.com/eth-brownie/brownie/issues/941
https://github.com/yearn/yearn-vaults/pull/473
## Slither with Truffle 🍄
Slither can run with truffle project without to change anything
Run `slither .` inside truffle project
![](https://i.imgur.com/D563nQq.png)
![](https://i.imgur.com/wEhSNkz.png)
https://www.youtube.com/watch?v=Dxex3b-eMq0
ref: https://ethereum.org/en/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/
--------------------------------------------------
https://medium.com/coinmonks/static-analysis-of-smart-contracts-with-slither-github-actions-1e67e54ed8a7