Summary
In TempleGold
contract, setDistributionParams() can be executed with 0 value for a parameter eg. params.gnosis -
This is intentional to freely distribute minted TGLD to staking and dai gold auction only.
However, when params.gnosis
is set to 0, any leftover dust from rounding down the minting amount still goes to teamGnosis
.
Vulnerability Details
When params.gnosis
is set to 0 in setDistributionParams()
, the contract does not correctly handle leftover dust from the rounding down of minting amounts in the TempleGold._distribute()
.
* mintAmount = 990000000000000000102
* DISTRIBUTION_DIVISOR = 100e18 = 1e20
* params.staking = 40e18
* params.escrow = 60e18
* params.gnosis = 0
*/
function _distribute(DistributionParams storage params, uint256 mintAmount) private {
uint256 stakingAmount = TempleMath.mulDivRound(params.staking, mintAmount, DISTRIBUTION_DIVISOR, false);
if (stakingAmount > 0) {
_mint(address(staking), stakingAmount);
staking.notifyDistribution(stakingAmount);
}
uint256 escrowAmount = TempleMath.mulDivRound(params.escrow, mintAmount, DISTRIBUTION_DIVISOR, false);
if (escrowAmount > 0) {
_mint(address(escrow), escrowAmount);
escrow.notifyDistribution(escrowAmount);
}
uint256 gnosisAmount = mintAmount - stakingAmount - escrowAmount;
if (gnosisAmount > 0) {
_mint(teamGnosis, gnosisAmount);
}
_totalDistributed += mintAmount;
emit Distributed(stakingAmount, escrowAmount, gnosisAmount, block.timestamp);
}
Impact
This vulnerability allows extra TGLD tokens to accumulate with teamGnosis
, unintended by the contract's design.
It may lead to a loss of control over token supply and impact the intended fairness of token distribution.
Tools Used
Recommendations
Update the TempleGold._distribute()
to handle leftover dust from rounding down minting amounts correctly.
// TempleGold.sol
function _distribute(DistributionParams storage params, uint256 mintAmount) private {
uint256 stakingAmount = TempleMath.mulDivRound(params.staking, mintAmount, DISTRIBUTION_DIVISOR, false);
if (stakingAmount > 0) {
_mint(address(staking), stakingAmount);
staking.notifyDistribution(stakingAmount);
}
- uint256 escrowAmount = TempleMath.mulDivRound(params.escrow, mintAmount, DISTRIBUTION_DIVISOR, false);
+ uint256 escrowAmount = params.gnosis != 0 ? TempleMath.mulDivRound(params.escrow, mintAmount, DISTRIBUTION_DIVISOR, false): mintAmount - stakingAmount;
if (escrowAmount > 0) {
_mint(address(escrow), escrowAmount);
escrow.notifyDistribution(escrowAmount);
}
uint256 gnosisAmount = mintAmount - stakingAmount - escrowAmount;
if (gnosisAmount > 0) {
_mint(teamGnosis, gnosisAmount);
/// @notice no requirement to notify gnosis because no action has to be taken
}
_totalDistributed += mintAmount;
emit Distributed(stakingAmount, escrowAmount, gnosisAmount, block.timestamp);
}