“We have fixed WETH10 and now have introduced its new version i.e. WETH11.”
How to Submit a Solution:
Use the below submission form to submit the solution: https://quillaudits.typeform.com/QuillCTF
Objective of CTF: We have fixed WETH10 and now have introduced its new version WETH11. But along the way, bob made a mistake and transferred its tokens to the wrong address. Can you help bob recover his 10 ether?
For more information, refer to the Foundry setUp file:
Note: You can create POCs using Foundry/Hardhat. Without proper POC, your submissions will not be accepted.
Contract Code:
pragma solidity ^0.8.0;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
// The Angel Di Maria Wrapped Ether
contract WETH11 is ERC20("Angel Di Maria Wrapped Ether", "WETH11"), ReentrancyGuard {
receive() external payable {
deposit();
}
function _burnAll() internal {
_burn(msg.sender, balanceOf(msg.sender));
}
function deposit() public payable nonReentrant {
_mint(msg.sender, msg.value);
}
function withdraw(uint256 wad) external nonReentrant {
_burn(msg.sender, wad);
Address.sendValue(payable(msg.sender), wad);
}
function withdrawAll() external nonReentrant {
uint256 balance = balanceOf(msg.sender);
_burnAll();
Address.sendValue(payable(msg.sender), balance);
}
/// @notice Request a flash loan in ETH
function execute(address receiver, uint256 amount, bytes calldata data) external nonReentrant {
uint256 prevBalance = address(this).balance;
Address.functionCallWithValue(receiver, data, amount);
require(address(this).balance >= prevBalance, "flash loan not returned");
}
}
Foundry setUp:
(You can also use other frameworks like Hardhat or Brownie)
// SPDX-License-Identifier: Manija
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "../src/WETH11.sol";
contract Weth11Test is Test {
WETH11 public weth;
address owner;
address bob;
function setUp() public {
weth = new WETH11();
bob = makeAddr("bob");
vm.deal(address(bob), 10 ether);
vm.startPrank(bob);
weth.deposit{value: 10 ether}();
weth.transfer(address(weth), 10 ether);
vm.stopPrank();
}
function testHack() public {
assertEq(
weth.balanceOf(address(weth)),
10 ether,
"weth contract should have 10 ether"
);
vm.startPrank(bob);
// hack time!
vm.stopPrank();
assertEq(address(weth).balance, 0, "empty weth contract");
assertEq(
weth.balanceOf(address(weth)),
0,
"empty weth on weth contract"
);
assertEq(
bob.balance,
10 ether,
"player should recover initial 10 ethers"
);
}
}