changed 3 years ago
Published Linked with GitHub

Smart Contract Upgradeability in DeFi protocols

Daniel Perez and Paul Pritz

Imperial College London


Immutability vs Flexibility

  • Ethereum is immutable by default
  • Protocols use specific design patterns to work around this to be maintainable in practice
  • This leads to several risks as functionality can be changed
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Proxy Pattern

  • The EIP 1822 proxy pattern is commonly used to allow upgradeability
  • This works by delegate calling functions in another contract that can be exchanged
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Contract Setting Pattern

  • This works by splitting functionality in an entry point and a logic contract
  • The address of the logic contract can be set and changed
  • This offers more control as not everything is exchangeable but also limits flexibility
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Governance and Upgradeability

  • Upgrades are executed by some governance mechanims
  • Typically two patterns exist: On-chain voting or a multisig with optional off-chain voting
  • Timelocks are used to allow users to react to changes - trade-off between being able to react to problems and risk for users not being able to react to changes
  • Trade-off between gate-keeper function of multisig and trust requirement

Taxonomy

  • If large parts of a protocol are upgradeable, the barrier to executing upgrades should be high
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Automating Upgradeability Detection

The tool scans contracts for upgradeability using the EIP 1822 pattern:

  • By convention, EIP 1822 stores the address of the logic contract in a specific storage slot
  • The tool analyses the bytecode to detect whether this solt has been set
  • The contract setting pattern and patterns deviating from EIP 1822 are harder to detect as these differ across protocols
  • The tool also checks for common proxy pattern functions such as implementation()

Proxy Pattern Upgradeable Contracts

Protocol Scanned Upgradeable Percentage
Aave 50 39 78.00%
MakerDAO 278 10 3.60%
Curve 111 1 0.90%
Convex 33 0 0.00%
Compound 72 36 50.00%

Case Study #1: Compound

  • Everything upgradeable (proxy pattern), everything goes through on-chain governance
  • Time locks are enforced (currently 2 days)
  • Reliance on voters to review and understand proposals
  • Timelocks meant that they couldn't immediately react: $90m funds lost
if (supplierIndex == 0 && supplyIndex > compInitialIndex) {
    supplierIndex = compInitialIndex;
}
Double memory deltaIndex = Double({
    mantissa: sub_(supplyIndex, supplierIndex)});
uint supplierTokens = CToken(cToken).balanceOf(supplier);
uint supplierDelta = mul_(supplierTokens, deltaIndex);

Case Study #2: MakerDAO

  • Everything upgradeable (contract setting pattern), everything goes through on-chain governance
  • Time locks employed (24h)
  • Poor voting design (no lock period) led to flash loan attack on voting mechanism
  • No monetary consequences as attacker only whitelisted a coin - but could have led to loss of all funds [1]
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
[1] Gudgeon, Lewis, et al. "The decentralized financial crisis." 2020 Crypto Valley Conference on Blockchain Technology (CVCBT). IEEE, 2020.

Case Study #3: Convex

  • Almost nothing upgradeable, except for StakingProxy (which holds almost all vote locked CVX) through contract setting pattern
function setStakingContract(address _staking) external onlyOwner {
        require(stakingProxy == address(0) || (minimumStake == 0 && maximumStake == 0), "!assign");

        stakingProxy = _staking;
    }
  • Upgrade executable by multisig without time delay, all 1.5B USD worth of CVX could have been stolen in single transaction
  • This has now been fixed in a V2 version of the ConvexLocker
ConvexLocker cvxLocker;
CvxStakingProxy stakingProxy;
cvxLocker.setStakeLimits(0, 0, {"from": multisig});
cvxLocker.setStakingContract(stakingProxy, {"from": multisig});
cvxLocker.setStakeLimits(1, 1, {"from": multisig});

Conclusion

  • Our tool shows that many protocols are not actually fully immutable
  • Upgradeability is a necessary evil to allow protocols to be maintained
  • Protocols with extensive upgradeability should put barriers to upgrade execution in place (efficient frontier)
Select a repo