Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: high
Valid

Market.sol does not scale the WETH rewards by the vault's credit share, leading to incorrect reward distribution.

Summary

Inside the getVaultAccumulatedValues function, wethRewardChangeX18 is not scaled by the vaultCreditShareX18 leading to incorrect rewards distribution in case market has several connected vaults.

Vulnerability Details

The function getVaultAccumulatedValues calculates changes in debt, USDC credit, and WETH rewards for a vault. However, it does not correctly scale the WETH rewards by the vault's share of the total credit. This means that the vaults receive incorrect amounts of WETH rewards, which are not proportional to their credit share. This leads to an unfair distribution of rewards and may result in a scenario where there are not enough funds to back users' claims.

Consider the following scenario:

  • Total delegated credit: 1000 USD

  • Vault A's delegated credit: 200 USD (20% of total)

  • WETH rewards to be distributed: 10 WETH

The current implementation gives 10 weth to all vaults including Vault A. Ideally, Vault A should receive 2 WETH due to the ratio of it's delagated credit.

UD60x18 vaultCreditShareX18 = vaultDelegatedCreditUsdX18.div(getTotalDelegatedCreditUsd(self));
// calculate the vault's value changes since its last accumulation
// note: if the last distributed value is zero, we assume it's the first time the vault is accumulating
// values, thus, it needs to return zero changes
realizedDebtChangeUsdX18 = !lastVaultDistributedRealizedDebtUsdPerShareX18.isZero()
? sd59x18(self.realizedDebtUsdPerVaultShare).sub(lastVaultDistributedRealizedDebtUsdPerShareX18).mul(
vaultCreditShareX18.intoSD59x18()
)
: SD59x18_ZERO;
unrealizedDebtChangeUsdX18 = !lastVaultDistributedUnrealizedDebtUsdPerShareX18.isZero()
? sd59x18(self.unrealizedDebtUsdPerVaultShare).sub(lastVaultDistributedUnrealizedDebtUsdPerShareX18).mul(
vaultCreditShareX18.intoSD59x18()
)
: SD59x18_ZERO;
usdcCreditChangeX18 = !lastVaultDistributedUsdcCreditPerShareX18.isZero()
? ud60x18(self.usdcCreditPerVaultShare).sub(lastVaultDistributedUsdcCreditPerShareX18).mul(
vaultCreditShareX18
)
: UD60x18_ZERO;
// TODO: fix the vaultCreditShareX18 flow to multiply by `wethRewardChangeX18`
wethRewardChangeX18 = ud60x18(self.wethRewardPerVaultShare).sub(lastVaultDistributedWethRewardPerShareX18);
}

Impact

Unfair rewards distribution to vaults. The latest changes in rewards are entitled to all the vaults not taking into the account their share in a particular market.

Tools Used

Manual review

Recommendations

Protocol seems to be aware of the issue as the code mentions it with a TODO. Need to scale the wethRewardChangeX18 with vaultCreditShareX18.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`wethRewardPerVaultShare` is incremented by `receivedVaultWethReward` amount which is not divided by number of shares.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.