Covalent contest - gpersoon's results

One unified API. One billion possibilities.

General Information

Platform: Code4rena

Start Date: 19/10/2021

Pot Size: $30,000 ETH

Total HM: 5

Participants: 13

Period: 3 days

Judge: GalloDaSballo

Total Solo HM: 4

Id: 43

League: ETH

Covalent

Findings Distribution

Researcher Performance

Rank: 7/13

Findings: 2

Award: $695.14

🌟 Selected for report: 2

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: gpersoon

Also found by: hickuphh3, jonah1005, xYrYuYx

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

0.1639 ETH - $586.30

External Links

Handle

gpersoon

Vulnerability details

Impact

The function depositRewardTokens divides the "amount" of tokens by allocatedTokensPerEpoch to calculate the endEpoch. When "amount" isn't a multiple of allocatedTokensPerEpoch the result of the division will be rounded down, effectively losing a number of tokens for the rewards.

For example if allocatedTokensPerEpoch is set to 3e18 and "amount" is 100e18 then endEpoch will be increased with 33e18 and the last 1e18 tokens are lost.

A similar problem occurs here:

  • in setAllocatedTokensPerEpoch(), with the recalculation of endEpoch
  • in takeOutRewardTokens(), with the retrieval of tokens
  • in _stake(), when initializing endEpoch (e.g. when endEpoch==0)

Proof of Concept

https://github.com/code-423n4/2021-10-covalent/blob/ded3aeb2476da553e8bb1fe43358b73334434737/contracts/DelegatedStaking.sol#L90-L98

https://github.com/code-423n4/2021-10-covalent/blob/ded3aeb2476da553e8bb1fe43358b73334434737/contracts/DelegatedStaking.sol#L368-L383

Tools Used

In depositRewardTokens() add, in the beginning of function, before the if statement: require(amount % allocatedTokensPerEpoch == 0,"Not multiple");

In takeOutRewardTokens() add: require(amount % allocatedTokensPerEpoch == 0,"Not multiple");

Update setAllocatedTokensPerEpoch() to something like:

if (endEpoch != 0) { ... uint128 futureRewards = ... require(futureRewards % amount ==0,"Not multiple"); ...
} else { // to prevent issues with _stake() require(rewardsLocked % allocatedTokensPerEpoch==0,"Not multiple"); }

#0 - kitti-katy

2021-10-21T18:44:11Z

Agreed, the original assumption was that the owner would always make sure the take out and deposit amount is multiple of emission rate. But yes, this is good to add the check. Also it is not that risky since the emission rate wouldn't be that high per epoch and the loss will always be less than the emission rate.

#1 - GalloDaSballo

2021-11-02T01:25:47Z

Agree with the finding, since it's a rounding error the max loss in rewards can at most be 1 less than the denominator

That said, this is a Medium Severity Finding as per the doc: 2 — Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements.

Where in this case the rounding is a way to leak value (loss of yield)

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter