The Rewarder

Description

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?

TL;DR

distributeRewards() computes reward based on ERC20Snapshot. We can borrow large amount of flashloan and deposit into the contract to trigger the snapshot, then get a huge amount of reward tokens, a lot more than we deserve.

Code Audit

This chall is about ERC20 snapshot. Read this article to learn background knowledge:

Obviously we can manipulate something using flashloan and ERC20Snapshot plays a role in this chall. There are 3 tokens in the system:

  • dvt - liquidity token -> the token of flashloan pool

  • accounting token -> the token for governance

  • reward token -> the token when calling TheRewarderPool.distributeRewards()

In the test file:

The theRewarderPool.distributeRewards() call will trigger _recordSnapshot():

The lastRecordedSnapshotTimestamp variable influences the isNewRewardsRound() check:

So we have to vm.warp() 5 days forward before calling deposit():

You can see that if we deposit a lot of dvt (borrowed via flashloan), we get many accounting tokens with 1:1 ratio. Then distributeRewards() is called:

Since our accounting token balance is high, we get a lot of reward tokens here. After that we can just withdraw everything and pay back the flashloan.

Building PoC

Last updated