ContinuousVesting beneficiaries will have zero voting power initiallly
Summary
Impact : ContinuousVesting beneficiaries will have zero voting power, due to wrong initialization.
Likelihood : always, till anyone reports the issue.
The team wants to give 1x voting power to ContinuousVesting initially, but it will be zero.
Even though voting factor can be changed by owner, still team is unaware of this issue and will change voting factor only after any users report saying no voting power due to wrong voting factor initialization.
Vulnerability Detail
To have 1x voting power in Tranche vesting, the voting factor is set == fractionDenominator == 10000, so that tokensToVotes will always return tokensToVotes = tokenAmount sent ( 1 token = 1 vote token)
But issue is in ContinuousVesting where to have 1x voting power, the voteFactor has to be equal to fractionDenominator. And it should be voteFactor == fractionDenominator == 10 ** 18. Instead here voteFactor = 10000 used, and most tokens with < 18 decimals USDT and USDC will make tokensToVotes return 0. So even if you have 1 million USDC to vest, the voting power will be 0 due to rounding down in tokensToVotes function. Just make voteFactor to be 10 ** 18 instead of 10k.
0 voting power for ContinuousVesting beneficiaries. And the USDC, USDT tokens being most used makes the likelihood always. So, it is high likelihood and medium impact.
Ironsidesec
medium
ContinuousVesting
beneficiaries will have zero voting power initialllySummary
Impact :
ContinuousVesting
beneficiaries will have zero voting power, due to wrong initialization.Likelihood : always, till anyone reports the issue. The team wants to give 1x voting power to
ContinuousVesting
initially, but it will be zero. Even though voting factor can be changed by owner, still team is unaware of this issue and will change voting factor only after any users report saying no voting power due to wrong voting factor initialization.Vulnerability Detail
To have 1x voting power in Tranche vesting, the voting factor is set == fractionDenominator == 10000, so that
tokensToVotes
will always return tokensToVotes = tokenAmount sent ( 1 token = 1 vote token)https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/AdvancedDistributorInitializable.sol#L80
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/PerAddressTrancheVestingInitializable.sol#L23-L24
But issue is in
ContinuousVesting
where to have 1x voting power, thevoteFactor
has to be equal tofractionDenominator
. And it should bevoteFactor == fractionDenominator == 10 ** 18
. Instead here voteFactor = 10000 used, and most tokens with < 18 decimals USDT and USDC will maketokensToVotes
return 0. So even if you have 1 million USDC to vest, the voting power will be 0 due to rounding down intokensToVotes
function. Just makevoteFactor
to be 10 ** 18 instead of 10k.https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/PerAddressContinuousVestingInitializable.sol#L22-L23
Impact
0 voting power for
ContinuousVesting
beneficiaries. And the USDC, USDT tokens being most used makes the likelihood always. So, it is high likelihood and medium impact.Code Snippet
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/AdvancedDistributorInitializable.sol#L80
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/PerAddressContinuousVestingInitializable.sol#L22-L23
Tool used
Manual Review
Recommendation