Our goal is to decrease SideEntranceLenderPool’s balance to zero ETH and attacker gets ‘attackerInitialEthBalance’ ETH. So it is transfer the pool’s balance to attacker’s account.
1 2 3 4 5 6 7 8 9 10 11 12 13
after(asyncfunction () { /** SUCCESS CONDITIONS */ expect( await ethers.provider.getBalance(this.pool.address) ).to.be.equal('0'); // Not checking exactly how much is the final balance of the attacker, // because it'll depend on how much gas the attacker spends in the attack // If there were no gas costs, it would be balance before attack + ETHER_IN_POOL expect( await ethers.provider.getBalance(attacker.address) ).to.be.gt(this.attackerInitialEthBalance); });
SideEntranceLenderPool has a mapping balances, it allows anyone to deposit and withdraw their liquidity.
There is a logical error in the following code: When calling flashloan(), SideEntranceLenderPool will only check whether its balance decrease or not. But if we flashLoan a lot of money, and then use it to deposit, the address(this).balances will not change! We can pass it. And because we have recorded mapping balances(by deposit()), we can withdraw it!
1 2 3
balances[msg.sender] += msg.value;
require(address(this).balance >= balanceBefore, "Flash loan hasn't been paid back");
I think it is a logical error. Balance check should not be the contract’s balance while deposit() will change it. In order to correct it, maybe it could change contract balance check to the mapping balances check.