Because setPool does a transfer before configuring the pool it is possible for anyone to re-enter and drain the contract.
From the beetle we can see that Lenders make pool that borrowers borrow from, but all tokens are stored in one shared contract - Lender. Now if any of the lenders makes a pool with an ERC777 token (or any other token with a hook) other Users will be able to drain this pool and steal all of the tokens. This is all possible because setPool does this transfer before setting the storage of a given pool.
How to re-enter:
There are 2 pools A : B and C : D where one of the two tokens is re-enterable.
| Preconditions | values |
|---|---|
| Loan tokenA : tokenB Collateral | ERC777 : ERC20 |
| Pool size | 10 000 |
| TokenA token left in the pool(ERC777 remaining) | 5000 |
| Loan tokenC : tokenD Collateral | ERC20 : ERC777 |
| Pool size | 4000 |
| TokenD token left in the pool(ERC777 remaining) | 3000 |
| Total ERC777 in contract | 8000 |
Steal from A : B
Create a pool A : B with 1000 of tokenA
Call setPool on that pool, only changing the loan amount from 1000 to 500
This transfer will trigger and transfer 500 tokens to your contract from where you will re-enter 5000 / 500 = 10 times
Withdraw your initial 1000 loan tokens
Steal from C : D
Make a pool with D as loan token (the re-enter "hack" only steals loan tokens) with again 1000 tokenD
Call setPool on that pool, only changing the loan amount from 1000 to 500
This transfer will trigger and transfer 500 tokens to your contract from where you will re-enter 3000 / 500 = 6 times
Withdraw your initial 1000 loan tokens
Any user can drain every ERC777 token from the contract.
Manual review.
Either prohibit ERC777 tokens, by having whitelist on allowed tokens, or use ReentrancyGuard by OZ.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.