Super DCA Liquidity Network
Dollar-cost averaging via a Uniswap V4 hook — dynamic fees plus a Curve-style gauge that streams DCA-token rewards to liquidity providers.
setMintRate can retroactively change accrued staker rewards
Summary
SuperDCAStaking.setMintRate changes the mint rate without first settling the global reward index. Unaccrued rewards that were earned under the old rate get recalculated at the new rate, so an admin can retroactively inflate or deflate past rewards.
Root cause
In SuperDCAStaking.sol, setMintRate updates mintRate but never calls _updateRewardIndex() first. Any rewards accrued since lastMinted are then valued at the new rate.
Pre-conditions
- ›Admin calls
setMintRate. - ›Time has passed since
lastMinted, so there are unaccrued rewards.
Impact
Stakers receive more or less than they earned for past periods, depending on the direction of the rate change. The reward accounting is inconsistent with what was actually emitted.
Proof of concept
function test_UserRewardsBeforeAndAfterMintRateChange() public {
uint256 stakeAmount = 100e18;
_stake(user, tokenA, stakeAmount);
uint256 start = staking.lastMinted();
vm.warp(start + 1 days);
uint256 pendingBefore = staking.previewPending(tokenA);
uint256 newRate = staking.mintRate() * 2;
vm.prank(admin);
staking.setMintRate(newRate);
// no time advanced
uint256 pendingAfter = staking.previewPending(tokenA);
assertGt(pendingAfter, pendingBefore);
}
Recommendation
Call _updateRewardIndex() at the start of setMintRate, before mintRate is updated.