
Standalone
Flash Loan Counter-Exploit

Bank Loan Theft
Download quests in Questplay
View the contracts and any other additional content from your IDE.
By cergyk.eth
The banking house runs a simple loan system. Customers can deposit gold as collateral to withdraw coin. Specifically, a customer has to deposit 1000 $GLD tokens to draw a $COIN loan. The deposited $GLD should only be withdrawable if the customer repays the loan.
A thief has cleverly bypassed the bank's loan system, robbing the bank's $COIN balance. Can you figure out how to recover the stolen funds?
Your Task
Find out how the coins in BankingHouse
have been stolen and recover it back from the thief. To pass this quest:
The thief should have a $COIN balance of 0.
The
BankingHouse
contract should have its original $COIN balance back.
Contract Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
contract BankingHouse {
bytes32 constant PASSWORD_HASH = 0x3a1cf401d67c55af5baa816bfb6f886bdb7ff802e35c98333ce62b2843dfdbb2;
uint256 constant REQUIRED_COLLATERAL = 1000 ether;
IERC20 public immutable gold;
IERC20 public immutable coin;
bool public paused;
mapping(address => uint256) public deposits;
mapping(address => int256) public loans;
constructor(IERC20 _gold, IERC20 _coin) {
gold = _gold;
coin = _coin;
}
function deposit(uint256 amount) external {
if (paused) { return; }
gold.transferFrom(msg.sender, address(this), amount);
deposits[msg.sender] += amount;
}
function transactCoin(int256 amount) external {
if (amount > 0) {
require(
deposits[msg.sender] >= REQUIRED_COLLATERAL,
"Borrower has insufficient gold collateral"
);
loans[msg.sender] += amount;
coin.transfer(msg.sender, uint256(amount));
} else {
loans[msg.sender] += amount;
coin.transferFrom(
msg.sender,
address(this),
uint256(-amount)
);
}
}
function withdraw(uint256 amount) external {
if (paused || loans[msg.sender] > 0) { return; }
deposits[msg.sender] -= amount;
gold.transfer(msg.sender, amount);
}
function resetLoan(
address borrower,
string calldata password
) external {
require(keccak256(bytes(password)) == PASSWORD_HASH);
loans[borrower] = 0;
}
function setPaused(
bool _paused,
string calldata password
) external {
require(keccak256(bytes(password)) == PASSWORD_HASH);
paused = _paused;
}
}

You settle in, pouring over the bank’s security system. Where did all the coin go?