Challenge 1: Unstoppable, Damn vulnerable defi V4 lazy solutions series

Siddharth Patel
3 min readAug 9, 2024

--

Why Lazy?

I’ll strongly assume that you’ve gone through challenge once or more time and you’ve some understandings of the challenge contracts flows. So, I’ll potentially will go towards solution directly.

V4 Intro

Read more comments and details about the changes in the full release announcement:

Problem statement

Our aim is to halt the vault. If we do think little bit then it can be possible if we somehow manage to make smart contract transaction fail every time, It could be lets say finding out and making that one condition fail every time👀.

There are 2 smart contracts mainly,
UnstoppableVault.sol and UnstoppableMonitor.sol

Let’s focus on main functionality, flashLoan of UnstoppableVault

There are 4 require conditions,

  1. flashloan amount should not be equal to zero.
  2. asked token should be always token for which vault is built for.
  3. receiver.onFlashLoan should always return keccak256("IERC3156FlashBorrower.onFlashLoan")
  4. Also in between one weird condition is,

convertToShares(totalSupply) != balanceBefore()

Let’s focus on this,

uint256 balanceBefore = totalAssets();
if (convertToShares(totalSupply) != balanceBefore) revert InvalidBalance(); // enforce ERC4626 requirement

Look at convertToShares and totalAssets function for reference,

function convertToShares(uint256 assets) public view virtual returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
}
function totalAssets() public view override nonReadReentrant returns (uint256) {
return asset.balanceOf(address(this));
}

what’s this?

This code is meant to enforce the ERC4626 requirement, which is a standard proposed for tokenized vaults in DeFi. The aim of ERC4626 is to create a standardized approach for handling user deposits and shares within a vault, ultimately determining the rewards for staked tokens.

Understanding ERC4626 and the Accounting System

In the context of this challenge, there are two fundamental terms to comprehend: assets and shares.

  • The assets represent the underlying token, in this case, DVT that users deposit and withdraw from the vault.
  • Shares, on the other hand, symbolize the vault tokens, denoted as tDVT minted or burned for users based on the proportion of their deposited assets.

The challenge leverages the convertToShares() function as per ERC4626. This function calculates the number of shares the vault should mint, taking the user’s deposited assets into account.

Enforcing Equal TotalSupply and TotalAssets

The line (convertToShares(totalSupply) != balanceBefore) enforces a condition that requires the totalSupply of vault tokens to always match the totalAssets of underlying tokens before any flash loan execution. This condition acts as a safeguard to ensure that the flashLoan function remains inactive if the vault deviates assets to other contracts.

Tracking Assets and the TotalAssets Function

The totalAssets function has been overridden to return the vault contract's asset balance (asset.balanceOf(address(this))). This introduces an alternative accounting system that relies on monitoring the supply of vault tokens.

Attack

The attack strategy revolves around creating a conflict between the two distinct accounting systems. This is achieved by manually transferring DVT tokens directly to the vault.

This manipulation disrupts the balance and leads to a scenario where the condition (convertToShares(totalSupply) != balanceBefore) fails.

Consequently, the flashLoan function is deactivated due to the divergence in accounting systems, since the transaction will always be reverted without dependance on the “user” input.

Solution code:

Unstoppable.t.sol

function test_unstoppable() public checkSolvedByPlayer {
require(token.transfer(address(vault), 1));
}

Test it,

forge test --mp test/unstoppable/Unstoppable.t.sol

Succeed!🔥💸

Incase if you need all solutions,

https://github.com/siddharth9903/damn-vulnerable-defi-v4-solutions

--

--