TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: medium
Invalid

When vesting factor is updated distribute amounts may be calculated wrong

Summary

When vesting factor is updated distribute amounts may be calculated wrong, due to using the new updated vesting factor for the time since the last distribution. This can also happen

Vulnerability Details

The protocol issues Temple Gold Tokens which are not transferable between users. The tokens can be acquired through staking in TempleGoldStaking or through auction in the DaiGoldAuction.

TGLD is only transferred to these contract by the TempleGold contract itself. The amount to transfer is calculated based on
distribution params and vesting factor.
The distribution params are used to calculate the share percentages of TGLD to send to staking, escrow (dai/gold auction) and gnosis.
The vesting factor is used to calculate the amount of tokens to mint and distribute depending on the time passed as can be seen in the following code snippet:

mintAmount = TempleMath.mulDivRound((block.timestamp - _lastMintTimestamp) * (MAX_SUPPLY), vestingFactorCache.numerator, vestingFactorCache.denominator, false);

Both the vesting factor and the distribution params can be updated via setVestingFactor or setDistributionParams.

The problem with this is that if mint() has NOT been called in while and the vesting factor or distribution params are updated, the next call to mint() would mint and distribute tokens, from before the update, according to the newly updated values of the distribution params or vesting factor. This will cause more or less tokens tokes to be send to staking and escrow resulting in losses for the users or the protocol.

Impact

Users receive wrong amount of tokens for staking or in the DAI/TGLD auction - either less or more

Tools Used

Manual review

Recommendations

Call mint in order to distribute rewards according to the old vesting factor before setting the new one

function setVestingFactor(VestingFactor calldata _factor) external override onlyOwner {
if (_factor.numerator == 0 || _factor.denominator == 0) { revert CommonEventsAndErrors.ExpectedNonZero(); }
if (_factor.numerator > _factor.denominator) { revert CommonEventsAndErrors.InvalidParam(); }
+ mint()
vestingFactor = _factor;
if (lastMintTimestamp == 0) { lastMintTimestamp = uint32(block.timestamp); }
emit VestingFactorSet(_factor.numerator, _factor.denominator);
}

and also in the setDistributionParams:

function setDistributionParams(DistributionParams calldata _params) external override onlyOwner {
if (_params.staking + _params.gnosis + _params.escrow != DISTRIBUTION_DIVISOR) { revert ITempleGold.InvalidTotalShare(); }
+ mint();
distributionParams = _params;
emit DistributionParamsSet(_params.staking, _params.escrow, _params.gnosis);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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