Table of Contents:
Join the team on Slack at: https://slack.empirehacking.nyc/ #ethereum
- Clone the repository:
git clone https://github.com/crytic/damn-vulnerable-defi-echidna
- Install the dependencies with
The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/1.html. We assume that the reader is familiar with it.
- Set up the testing environment with the appropriate contracts and necessary balances.
- Analyze the "before" function in
test/unstoppable/unstoppable.challenge.jsto identify the initial setup required.
- Add a property to check whether
UnstoppableLendercan always provide flash loans.
- Create a
config.yamlfile with the required configuration option(s).
- Once Echidna finds the bug, fix the issue, and retry your property with Echidna.
Only the following contracts are relevant:
We recommend trying without reading the following hints first. The hints are in the
- The invariant we are looking for is "Flash loans can always be made".
- Read what the allContracts option is.
receiveTokenscallback function must be implemented.
- A template is provided in contracts/unstoppable/UnstoppableEchidna.sol.
- A configuration file is provided in unstoppable.yaml.
This solution can be found in the
Solution Explained (spoilers ahead)
Note: Please ensure that you have placed
The goal of the unstoppable challenge is to recognize that
UnstoppableLender has two modes of tracking its balance:
poolBalance is increased when someone calls
However, a user can call
damnValuableToken.transfer() directly and increase the
balanceOf(address(this)) without increasing
Now, the two balance trackers are out of sync.
When Echidna calls
pool.flashLoan(10), the assertion
assert(poolBalance == balanceBefore) in
UnstoppableLender will fail, and the pool can no longer provide flash loans.
See the example output below from Echidna:
echidna . --contract UnstoppableEchidna --config unstoppable.yaml ... echidna_testFlashLoan: failed!💥 Call sequence: transfer(0x62d69f6867a0a084c6d313943dc22023bc263691,1296000) ...