You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
Root cause : start, cliff, end values are not encoded when computing getVestedFraction and it will revert when it tries to decode the zero bytes data into start, cliff, end
Vulnerability Detail
Issue flow :
To claim the vested tokens , beneficiary should call PerAddressContinuousVestingMerkle.claim() with start, cliff, end to verify with merkle root. Look at line 68, it is sending new bytes(0) instead of abi.encode(start, cliff, end)
2024-05-tokensoft-distributor-contracts-update\contracts\packages\hardhat\contracts\claim\PerAddressContinuousVestingMerkle.sol
53: function claim(
54: uint256index, // the beneficiary's index in the merkle root55: addressbeneficiary, // the address that will receive tokens56: uint256totalAmount, // the total claimable by this beneficiary57: uint256start, // the start of the vesting period58: uint256cliff, // cliff time59: uint256end, // the end of the vesting period60: bytes32[] calldatamerkleProof61: )
62: external63: validMerkleProof(keccak256(abi.encodePacked(index, beneficiary, totalAmount, start, cliff, end)), merkleProof)
64: nonReentrant
... SNIP ...
68: >>>uint256 claimedAmount =_executeClaim(beneficiary, totalAmount, newbytes(0));
69: // interactions70: _settleClaim(beneficiary, claimedAmount);
... SNIP ...
_executeClaim on line 68 above calls L110 below and data = new bytes(0) is passed in L115 below.
L115 above calls L66 below with data = new bytes(0) and it will call getClaimableAmount internall. in L124 below it is again calling getVestedFraction internally to compute how much is vested based on current delayed time between start, cliff, end
function claim(
uint256 index, // the beneficiary's index in the merkle root
address beneficiary, // the address that will receive tokens
uint256 totalAmount, // the total claimable by this beneficiary
uint256 start, // the start of the vesting period
uint256 cliff, // cliff time
uint256 end, // the end of the vesting period
bytes32[] calldata merkleProof
)
external
validMerkleProof(keccak256(abi.encodePacked(index, beneficiary, totalAmount, start, cliff, end)), merkleProof)
nonReentrant
{
// effects
- uint256 claimedAmount = _executeClaim(beneficiary, totalAmount, new bytes(0));+ uint256 claimedAmount = _executeClaim(beneficiary, totalAmount, abi.encode(start, cliff, end));
// interactions
_settleClaim(beneficiary, claimedAmount);
}
sherlock-admin4
changed the title
Atomic Opaque Quail - PerAddressContinuousVestingMerkle.claim will always revert
Ironsidesec - PerAddressContinuousVestingMerkle.claim will always revert
Jun 7, 2024
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelMediumA valid Medium severity issueRewardA payout will be made for this issue
Ironsidesec
high
PerAddressContinuousVestingMerkle.claim will always revert
Summary
Impact : beneficiary can never claim the tokens from
PerAddressContinuousVestingMerkle
contractLikelihood : always, and issue also exists on PerAddressContinuousVestingMerkleDistributor.claim(), PerAddressTrancheVestingMerkleDistributor.claim(). But doesn't exist on PerAddressTrancheVesting.claim() because it is encoding the data properly
Root cause :
start, cliff, end
values are not encoded when computinggetVestedFraction
and it will revert when it tries to decode the zero bytes data intostart, cliff, end
Vulnerability Detail
Issue flow :
PerAddressContinuousVestingMerkle.claim()
withstart, cliff, end
to verify with merkle root. Look at line 68, it is sendingnew bytes(0)
instead ofabi.encode(start, cliff, end)
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/PerAddressContinuousVestingMerkle.sol#L67
_executeClaim
on line 68 above calls L110 below and data =new bytes(0)
is passed in L115 below.https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/AdvancedDistributor.sol#L102-L109
new bytes(0)
and it will callgetClaimableAmount
internall. in L124 below it is again callinggetVestedFraction
internally to compute how much is vested based on current delayed time betweenstart, cliff, end
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/Distributor.sol#L79
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/Distributor.sol#L123
start, cliff, end
, since we sent data =new bytes(0)
from starting, this will trigger the revert.https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/PerAddressContinuousVesting.sol#L25
Impact
Impact : beneficiary can never claim the tokens from
PerAddressContinuousVestingMerkle
contractLikelihood : always, and issue also exists on PerAddressContinuousVestingMerkleDistributor.claim(), PerAddressTrancheVestingMerkleDistributor.claim(). But doesn't exist on PerAddressTrancheVesting.claim() because it is encoding the data properly
Code Snippet
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/PerAddressContinuousVestingMerkle.sol#L67
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/AdvancedDistributor.sol#L102-L109
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/Distributor.sol#L79
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/Distributor.sol#L123
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/abstract/PerAddressContinuousVesting.sol#L25
Tool used
Manual Review
Recommendation
https://github.com/sherlock-audit/2024-05-tokensoft-distributor-contracts-update/blob/67edd899612619b0acefdcb0783ef7a8a75caeac/contracts/packages/hardhat/contracts/claim/PerAddressContinuousVestingMerkle.sol#L67
Duplicate of #11
The text was updated successfully, but these errors were encountered: