When calculateNewEmissionRate() is called, it only adjusts the emission rate if the utilizationRate is strictly greater than (>) or strictly less than (<) the utilizationTarget. If the utilizationRate equals (==) the target, no change is applied and the function returns the existing emissionRate unchanged.
An attacker can exploit this by manipulating deposits through a flash loan and depositing/withdrawing so that the utilization ratio lines up exactly with the target at the moment of calculation. This effectively freezes the emission rate, preventing normal increases or decreases.
Note that the same root cause can also lead to this same flash loan exploit leading to a) always raising the emissions rate or b) always ensuring the emissions rate is lower. In this bug report, I show the example of the emissions rate always being frozen.
Step1: Create a test file named EmissionsRateManipulation.test.js in the test directory
Step 2: Paste the contents below into it and run with npx hardhat test test/EmissionsRateManipulation.test.js
Locked Emissions: The attacker can prevent adjustments, causing emissions to remain higher or lower than intended.
Incentive Disruption: The protocol’s dynamic emission model relies on adjusting rates. If these updates are blocked, the mechanism becomes ineffective.
Repeatable Exploit: As shown in the PoC, the attacker can repeatedly force the protocol into the equality scenario, keeping emissions locked indefinitely.
Manual review, Hardhat
Implement Flash Loan Protections: Guard against flash loans manipulating the emissions rate calculation. For example, using time‐weighted averages or cooldown periods can prevent a temporary flash loan-induced imbalance from being used to trigger an emission rate change. Additionally, imposing maximum change limits and monitoring for anomalous, flash-loan-like activity can ensure that only sustained changes affect the emission rate.
Handle Equality: Modify the logic in calculateNewEmissionRate() to ensure no scenario exists where the emission rate remains unchanged by design. For example, if utilizationRate == utilizationTarget, choose a minor adjustment (e.g., a rounding policy or “nudge” factor) to prevent indefinite stalling.
Margin Checks: Set a minimal threshold around the target value—e.g., if the difference is less than some epsilon, handle it as either greater or less for the purpose of adjustments.
Guard Rails: Periodically force a re-calculation of emissions that ensures an actual update if the utilization rate hovers around the target for too long.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.