Summary
TempleGold:setDistributionParams doesn't have an upper limit mint percentage for gnosisTeam address allowing to get all minted tokens when setting this percentage to 100%
Vulnerability Details
Setting the percentage for gnosisTeam address to 100% will left stacking and auction TLGD with no tokens when mint.
TempleGold:setDistributionParams doesnt implement a restriction to prevent gnosis receive 100% of new minted tokens as shown below.
It only check that assigned percentages will add 100%.
function setDistributionParams(DistributionParams calldata _params) external override onlyOwner {
if (_params.staking + _params.gnosis + _params.escrow != DISTRIBUTION_DIVISOR) { revert ITempleGold.InvalidTotalShare(); }
distributionParams = _params;
emit DistributionParamsSet(_params.staking, _params.escrow, _params.gnosis);
}
However this allows deployer to self assign 100% of TLGD emmision setting _params.gnosis to 100% and leaving _params.staking and _params.escrow to 0%.
The following PoC shows the previous described issue, showing that contract has no upper percentage restriction checks to prevent it.
To run first import console.sol library in TempleGold.t.sol
import "forge-std/console.sol";
Copy the following this as a new test case in test/forge/templegold/TempleGold.t.sol
function test_distribution_no_upper_check() public {
arbitrumOneForkId = fork("arbitrum_one");
ITempleGold.InitArgs memory initArgs = _getTempleGoldInitArgs();
templeGold = new TempleGold(initArgs);
templeToken = new FakeERC20("Temple Token", "TEMPLE", executor, 1000 ether);
staking = new TempleGoldStaking(rescuer, executor, address(templeToken), address(templeGold));
daiGoldAuction = new DaiGoldAuction(
address(templeGold),
daiToken,
treasury,
rescuer,
executor
);
vm.startPrank(executor);
templeGold.setEscrow(address(daiGoldAuction));
ITempleGold.DistributionParams memory params;
params.staking = 0 ether;
params.escrow = 0 ether;
params.gnosis = 100 ether;
templeGold.setDistributionParams(params);
ITempleGold.VestingFactor memory factor;
factor.numerator = 2 ether;
factor.denominator = 1000 ether;
templeGold.setVestingFactor(factor);
_setVestingFactorTime = uint32(block.timestamp);
templeGold.setStaking(address(staking));
templeGold.authorizeContract(address(daiGoldAuction), true);
templeGold.authorizeContract(address(staking), true);
templeGold.authorizeContract(teamGnosis, true);
console.log("[i] test_distribution_no_upper_check");
vm.startPrank(executor);
vm.warp(block.timestamp + 20 days);
templeGold.mint();
address teamGnosis = templeGold.teamGnosis();
vm.startPrank(teamGnosis);
uint256 balance = templeGold.balanceOf(teamGnosis);
console.log("TeamGnosis Balance => ",balance);
}
And run with verbose mode
forge test -vv --mt test_distribution_no_upper_check
Observe how all the TGLD were minted to gnosis address
Impact
High because if an EOA is used, will allow to get all minted TGLD.
However attack complexity is High.
Tools Used
Manual Review
Recommendations
Implement an upper percentage limit for gnosis team address as shown below or a guard to prevent params.gnosis asignation to 100% :
function setDistributionParams(DistributionParams calldata _params) external override onlyOwner {
if (_params.gnosis == DISTRIBUTION_DIVISOR) {revert ITempleGold.InvalidTotalShare();}
if (_params.staking + _params.gnosis + _params.escrow != DISTRIBUTION_DIVISOR) { revert ITempleGold.InvalidTotalShare(); }
distributionParams = _params;
emit DistributionParamsSet(_params.staking, _params.escrow, _params.gnosis);
}