-
Notifications
You must be signed in to change notification settings - Fork 982
Upgradeability Checks
slither-check-upgradability
is meant to help to review contracts using the delegatecall proxy pattern.
The tool checks that:
slither-check-upgradability proxy.sol ProxyName implem.sol ContractName
If a second version of the contract is to be checked, use:
slither-check-upgradeability proxy.sol ProxyName implem.sol ContractName implem_v2.sol ContractNameV2
proxy.sol
/implem.sol
can be a Truffle directory, for example:
slither-check-upgradability . ProxyName . ContractName
If you use zos, you will have the proxy and the contract in different directory and Solidity version.
To allow slither-check-upgradability
to work, you can compile manually the proxy contract to its AST form (solc file.sol --ast-compact-json > file.json
), and provides the generated file to slither-check-upgradability
. Use solc-select
to switch between Solidity version.
For example:
cd my_contracts
cd node_modules/zos-lib
npm install openzeppelin-solidity
cp node_modules/openzeppelin-solidity/ . -r
solc contracts/upgradeability/AdminUpgradeabilityProxy.sol --allow-paths . --ast-compact-json > AdminUpgradeabilityProxy.json
cd ..
slither-check-upgradability node_modules/openzeppelin-solidity/contracts/upgradeability/AdminUpgradeabilityProxy/json AdminUpgradeabilityProxy . MyImplementation
slither-check-upgradeability
checks that:
- There is no function id collision between the proxy and the implementation
- The proxy does not shadow any functions from the implementation
slither-check-upgradeability
checks that:
- The variables are declared in the same order between the proxy and the implementation
- The variables are declared in the implementation first and second version
slither-check-upgradeability
will warn if the proxy has state variables. Consider using the Unstructured storage pattern for those variables.
Contracts based on delegatecallproxy
cannot be initialized through constructors. As a result, init functions must be used. These functions do not benefitfrom:
- The Solidity C3 linearization. As a result, an init function can be called multiple times, or never.
- The init functions must be calleable only once.
- Race conditions can occur during deployement.
If the contract uses the zos library (and the Initializable
contract), the util checks that:
- All the
initalize
functions call theinitializer
modifier - All the inherits
initalize
functions are called -
initialize
functions are never called twice
Additionally, slither-check-upgradeability
prints the functions that must be called during initialization.
If the contract uses another schema, no check is performed. In that case, the tool warns:
Initializable contract not found, the contract does not follow a standard initalization schema.