sherlock-audit / 2024-05-tokensoft-distributor-contracts-update-judging

3 stars 2 forks source link

Ironsidesec - `ContinuousVesting` beneficiaries will have zero voting power initiallly #36

Closed sherlock-admin4 closed 3 months ago

sherlock-admin4 commented 3 months ago

Ironsidesec

medium

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)

https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/AdvancedDistributorInitializable.sol#L80

2024-05-tokensoft-distributor-contracts-update\contracts\packages\hardhat\contracts\claim\factory\AdvancedDistributorInitializable.sol

80:     function tokensToVotes(uint256 tokenAmount) private view returns (uint256) {
81:         return (tokenAmount * voteFactor) / fractionDenominator;
82:     }

https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/PerAddressTrancheVestingInitializable.sol#L23-L24

2024-05-tokensoft-distributor-contracts-update\contracts\packages\hardhat\contracts\claim\factory\PerAddressTrancheVestingInitializable.sol

11:     function __PerAddressTrancheVesting_init(
... SNIP ...
18:     ) internal onlyInitializing {
19:         __AdvancedDistributor_init(
20:             _token,
21:             _total,
22:             _uri,
23:   >>>>      10000, // 1x voting power
24:   >>>>      10000, // vested fraction
25:             _maxDelayTime,
... SNIP ...
28:         );
29:     }

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.

https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/factory/PerAddressContinuousVestingInitializable.sol#L22-L23

File: 2024-05-tokensoft-distributor-contracts-update\contracts\packages\hardhat\contracts\claim\factory\PerAddressContinuousVestingInitializable.sol

10:     function __ContinuousVesting_init(
... SNIP ...
17:     ) internal onlyInitializing {
18:         __AdvancedDistributor_init(
19:             _token,
20:             _total,
21:             _uri,
22:  >>>>       10000, // 1x voting power 
23:  >>>>       10 ** 18, // provides the highest resolution possible for continuous vesting
24:             _maxDelayTime,
... SNIP ...
27:         );
28:     }

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

 function __ContinuousVesting_init(
... SNIP ...
 ) internal onlyInitializing {
 __AdvancedDistributor_init(
 _token,
 _total,
 _uri,
-           10000, // 1x voting power 
+           10 ** 18, // 1x voting power 
 10 ** 18, // provides the highest resolution possible for continuous vesting
 _maxDelayTime,
 _salt,
 _owner
 );
 }