Exercise 6
Table of contents:
Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum
Setup
- Clone the repo:
git clone https://github.com/crytic/damn-vulnerable-defi-echidna - install the dependencies via
yarn install.
Context
The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/1.html, we assume that the reader is familiar with it.
Goals
- Setup the testing environment with the right contracts and necessary balances.
- Analyze the before function in test/unstoppable/unstoppable.challenge.js to identify what initial setup needs to be done.
- Add a property to check whether
UnstoppableLendercan always provide flash loans. - Create a
config.yamlwith the necessary configuration option(s). - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna.
Only the following contracts are relevant:
contracts/DamnValuableToken.solcontracts/unstoppable/UnstoppableLender.solcontracts/unstoppable/ReceiverUnstoppable.sol
Hints
We recommend to first try without reading the following hints. The hints are in the hints branch.
- The invariant that we are looking for is "Flash loan can always be made"
- Read what is the multi abi option
- The
receiveTokenscallback function must be implemented - A template is provided in contracts/unstoppable/UnstoppableEchidna.sol
- A config file is provided in unstoppable.yaml
Solution
This solution can be found in the solutions branch.
Solution Explained (spoilers ahead)
Note: Please make sure that you have placed solution.sol (or UnstoppableEchidna.sol) in contracts/unstoppable.
The goal of the unstoppable challenge is to realize that UnstoppableLender has two modes of tracking its balance: poolBalance and damnValuableToken.balanceOf(address(this)).
poolBalance is added to when someone calls depositTokens().
However, a user can call damnValuableToken.transfer() directly and increase the balanceOf(address(this)) without increasing poolBalance.
Now, the two balance trackers are out-of-sync.
When Echidna calls pool.flashLoan(10), the assertion assert(poolBalance == balanceBefore) in UnstoppableLender will break and the pool can no longer provide flash loans.
See example output below from Echidna:
$ echidna-test . --contract UnstoppableEchidna --config unstoppable.yaml
...
echidna_testFlashLoan: failed!💥
Call sequence:
transfer(0x62d69f6867a0a084c6d313943dc22023bc263691,1296000)
...