sherlock-audit / 2023-06-tokensoft-judging

4 stars 4 forks source link

dany.armstrong90 - PriceTierVestingSale_2_0 doesn't take into account for extra purchase of the beneficiary. #210

Closed sherlock-admin2 closed 1 year ago

sherlock-admin2 commented 1 year ago

dany.armstrong90

high

PriceTierVestingSale_2_0 doesn't take into account for extra purchase of the beneficiary.

Summary

PriceTierVestingSale_2_0 doesn't take into account for extra purchase of the beneficiary.

Vulnerability Detail

PriceTierVestingSale_2_0.getClaimableAmount() function calculates current claimable token amount. And this amount MUST be calculated with current purchased amount of the beneficiary. The code is as follows:

File: PriceTierVestingSale_2_0.sol
122:   // get the number of tokens currently claimable by a specific user
123:   function getClaimableAmount(address beneficiary) public view override returns (uint256) {
124:     if (records[beneficiary].initialized) return super.getClaimableAmount(beneficiary);
125: 
126:     // we can get the claimable amount prior to initialization
127:     return
128:       (getPurchasedAmount(beneficiary) * getVestedFraction(beneficiary, block.timestamp)) /
129:       fractionDenominator;
130:   }

This function will return correct claimable amount if records[beneficiary].initialized == false. But once this records[beneficiary].initialized is set to true, then this function's return value is not changed even if beneficiary made extra purchase into _sale.

As a result, beneficiary will get less token than he purchased.

Impact

If any beneficiary made extra purchasement into sale after he have made first claim, this beneficiary can not claim extra token about his extra purchasement.

Code Snippet

https://github.com/sherlock-audit/2023-06-tokensoft/blob/main/contracts/contracts/claim/abstract/PriceTierVestingSale_2_0.sol#L124

Tool used

Manual Review

Recommendation

File: PriceTierVestingSale_2_0.sol
122:   // get the number of tokens currently claimable by a specific user
123:   function getClaimableAmount(address beneficiary) public view override returns (uint256) {
124: -    if (records[beneficiary].initialized) return super.getClaimableAmount(beneficiary);
124: +    // if (records[beneficiary].initialized) return super.getClaimableAmount(beneficiary);
125: 
126:     // we can get the claimable amount prior to initialization
127:     return
128:       (getPurchasedAmount(beneficiary) * getVestedFraction(beneficiary, block.timestamp)) /
129:       fractionDenominator;
130:   }
File: PriceTierVestingSale_2_0.sol
110:   function getDistributionRecord(
111:     address beneficiary
112:   ) external view virtual override returns (DistributionRecord memory) {
113:     DistributionRecord memory record = records[beneficiary];
114: 
115:     // workaround prior to initialization
116: -    if (!record.initialized) {
116: +   // if (!record.initialized) {
117:       record.total = uint120(getPurchasedAmount(beneficiary));
118: -    }
118: +   // }
119:     return record;
120:   }