SECURITY AUDIT REGISTRY

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.

SherlockSherlock
RANK 49thpayout $1
[M-01]mediumofficial

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

solidity
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.

STATUS: AVAILABLE FOR ENGAGEMENTS

Open to audits, contract work, and security writing.