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
{{ message }}
This repository has been archived by the owner on Jun 2, 2024. It is now read-only.
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
Incorrect implementation of _getNextTokenId causing the loss of the founder's token
Summary
_getNextTokenId is used to find the next available baseTokenId in the range from 0 to 99 for a founder. However, if reservedUntilTokenId surpasses 99, getNextTokenId will initially return a number greater than 99. This leads to tokenRecipient being unable to store the recipient correctly, causing the founder to lose tokens.
Vulnerability Detail
The _addFounders function stores the newFounder for baseTokenId in the mapping tokenRecipient. The baseTokenId is determined by the _getNextTokenId function, and the initial value of baseTokenId passed into _getNextTokenId is reservedUntilTokenId.
// Used to store the base token id the founder will recieveuint256 baseTokenId = reservedUntilTokenId;
// For each token to vest:for (uint256 j; j < founderPct; ++j) {
// Get the available token id
baseTokenId =_getNextTokenId(baseTokenId);
// Store the founder as the recipient
tokenRecipient[baseTokenId] = newFounder;
emitMintScheduled(baseTokenId, founderId, newFounder);
// Update the base token id
baseTokenId = (baseTokenId + schedule) %100;
}
Typically, _getNextTokenId returns a _tokenId within the range of 0 to 99. However, if reservedUntilTokenId exceeds 99, the while loop won't run because tokenRecipient[reservedUntilTokenId].wallet is equal to zero. As a result, _getNextTokenId will directly return the value of reservedUntilTokenId, which is a number greater than 99.
function _getNextTokenId(uint256_tokenId) internalviewreturns (uint256) {
unchecked {
while (tokenRecipient[_tokenId].wallet !=address(0)) {
_tokenId = (++_tokenId) %100;
}
return _tokenId;
}
}
Consider the usage of tokenRecipient in the _isForFounder function. The baseTokenId is determined by _tokenId % 100, implying that tokenRecipient[reservedUntilTokenId] will never be utilized. Consequently, the associated founder won't receive their token.
function _isForFounder(uint256_tokenId) privatereturns (bool) {
// Get the base token iduint256 baseTokenId = _tokenId %100;
// If there is no scheduled recipient:if (tokenRecipient[baseTokenId].wallet ==address(0)) {
returnfalse;
// Else if the founder is still vesting:
} elseif (block.timestamp< tokenRecipient[baseTokenId].vestExpiry) {
// Mint the token to the founder_mint(tokenRecipient[baseTokenId].wallet, _tokenId);
returntrue;
// Else the founder has finished vesting:
} else {
// Remove them from future lookupsdelete tokenRecipient[baseTokenId];
returnfalse;
}
}
Impact
Founder cannot obtain the token that he was originally supposed to receive, facing economic loss.
sherlock-admin
changed the title
Low Boysenberry Reindeer - Incorrect implementation of _getNextTokenId causing the loss of the founder's token
Krace - Incorrect implementation of _getNextTokenId causing the loss of the founder's token
Dec 13, 2023
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
Krace
medium
Incorrect implementation of
_getNextTokenId
causing the loss of the founder's tokenSummary
_getNextTokenId
is used to find the next availablebaseTokenId
in the range from 0 to 99 for a founder. However, ifreservedUntilTokenId
surpasses 99,getNextTokenId
will initially return a number greater than 99. This leads totokenRecipient
being unable to store the recipient correctly, causing the founder to lose tokens.Vulnerability Detail
The
_addFounders
function stores thenewFounder
forbaseTokenId
in the mappingtokenRecipient
. ThebaseTokenId
is determined by the_getNextTokenId
function, and the initial value ofbaseTokenId
passed into_getNextTokenId
isreservedUntilTokenId
.Typically,
_getNextTokenId
returns a_tokenId
within the range of 0 to 99. However, ifreservedUntilTokenId
exceeds 99, the while loop won't run becausetokenRecipient[reservedUntilTokenId].wallet
is equal to zero. As a result,_getNextTokenId
will directly return the value ofreservedUntilTokenId
, which is a number greater than 99.Consider the usage of
tokenRecipient
in the_isForFounder
function. ThebaseTokenId
is determined by_tokenId % 100
, implying thattokenRecipient[reservedUntilTokenId]
will never be utilized. Consequently, the associated founder won't receive their token.Impact
Founder cannot obtain the token that he was originally supposed to receive, facing economic loss.
Code Snippet
https://github.com/sherlock-audit/2023-09-nounsbuilder/blob/db232c649b425c36f5a93607c95cfdf0e5962b2f/nouns-protocol/src/token/Token.sol#L166-L169
https://github.com/sherlock-audit/2023-09-nounsbuilder/blob/db232c649b425c36f5a93607c95cfdf0e5962b2f/nouns-protocol/src/token/Token.sol#L186-L194
https://github.com/sherlock-audit/2023-09-nounsbuilder/blob/db232c649b425c36f5a93607c95cfdf0e5962b2f/nouns-protocol/src/token/Token.sol#L263
Tool used
Manual Review
Recommendation
Maybe you can mod
_tokenId
by 100 before return.Duplicate of #42
The text was updated successfully, but these errors were encountered: