Platform: Code4rena
Start Date: 20/12/2022
Pot Size: $24,500 USDC
Total HM: 7
Participants: 4
Period: 2 days
Judge: GalloDaSballo
Total Solo HM: 4
Id: 198
League: ETH
Rank: 2/4
Findings: 2
Award: $0.00
🌟 Selected for report: 2
🚀 Solo Findings: 1
🌟 Selected for report: cccz
Also found by: hansfriese
Data not available
The first eight digits of the RuniverseLand TokenID indicate the corresponding plotSize of the NFT owner can call RuniverseLandMinter.ownerMintUsingTokenId directly to mint the NFT for a specific TokenID In RuniverseLandMinter._mintTokensUsingTokenId, there is no verification that the first eight bits of the tokenId match the plotSize parameter, which allows the owner to bypass the plotsAvailablePerSize limit.
function _mintTokensUsingTokenId( IRuniverseLand.PlotSize plotSize, uint256 tokenId, address recipient ) private { uint256 numPlots = 1; require( plotsMinted[uint256(plotSize)] < plotsAvailablePerSize[uint256(plotSize)], "All plots of that size minted" ); require( plotsMinted[uint256(plotSize)] + numPlots <= plotsAvailablePerSize[uint256(plotSize)], "Trying to mint too many plots" ); plotsMinted[uint256(plotSize)] += 1; runiverseLand.mintTokenId(recipient, tokenId, plotSize); }
For example, the plotSize parameter provided by the owner when calling ownerMintUsingTokenId is 8 * 8, while the plotSize contained in the tokenId is 128 * 128, thus bypassing the plotsAvailablePerSize limit
Also, once RuniverseLands with mismatched tokenId and plotSize are minted, the supply of RuniverseLands with different plotSize will no longer be correct because the plotsMinted variable is incorrectly calculated
None
Consider verifying in RuniverseLandMinter._mintTokensUsingTokenId that the first eight bits of the tokenId match the plotSize parameter
#0 - GalloDaSballo
2022-12-23T19:58:46Z
Additional possibly broken invariant due to Admin Privilege
#1 - msclecram
2023-01-04T02:15:36Z
Duplicated from #6 .
#2 - c4-sponsor
2023-01-04T02:15:40Z
msclecram marked the issue as sponsor confirmed
#3 - GalloDaSballo
2023-01-05T10:54:17Z
Similarly to #11 the Warden has shown a way to bypass specific checks which offer an invariant, in this case the invariant is the fact that plotSizes are capped, which can be broken by using ownerMintUsingTokenId
in an unintended way.
Because the lack of checks allows that, whereas the rest of the codebase offers checks to prevent that, I agree with Medium Severity
#4 - c4-judge
2023-01-06T12:30:55Z
GalloDaSballo marked the issue as primary issue
#5 - c4-judge
2023-01-06T14:27:53Z
GalloDaSballo marked the issue as selected for report
#6 - msclecram
2023-01-11T04:34:03Z
We updated the code with the next changes: -We removed _mintTokensUsingTokenId
https://github.com/bisonic-official/plot-contract/commit/ea8abd7faffde4218232e22ba5d8402e37d96878
🌟 Selected for report: cccz
Data not available
RuniverseLand allows primaryMinter and secondaryMinter to mint NFT.
function mintTokenId( address recipient, uint256 tokenId, PlotSize size ) public override nonReentrant { require(numMinted < MAX_SUPPLY, "All land has been minted"); require( _msgSender() == primaryMinter || _msgSender() == secondaryMinter, "Not a minter" ); numMinted += 1; emit LandMinted(recipient, tokenId, size); _mint(recipient, tokenId); }
RuniverseLandMinter, as one of them, will have a limit on the number of NFTs with different PlotSize
uint256[] public plotsAvailablePerSize = [ 52500, // 8x8 16828, // 16x16 560, // 32x32 105, // 64x64 7 // 128x128 ];
This will be checked in _mintTokens
function _mintTokens( IRuniverseLand.PlotSize plotSize, uint256 numPlots, address recipient ) private { require( plotsMinted[uint256(plotSize)] < plotsAvailablePerSize[uint256(plotSize)], "All plots of that size minted" ); require( plotsMinted[uint256(plotSize)] + numPlots <= plotsAvailablePerSize[uint256(plotSize)], "Trying to mint too many plots" ); for (uint256 i = 0; i < numPlots; i++) { uint256 tokenId = ownerGetNextTokenId(plotSize); plotsMinted[uint256(plotSize)] += 1;
But the other minter is not limited and can mint RuniverseLand with any tokenID, thus breaking the plotsAvailablePerSize limit
https://github.com/code-423n4/2022-12-forgotten-runiverse/blob/dcad1802bf258bf294900a08a03ca0d26d2304f4/contracts/RuniverseLand.sol#L88-L102 https://github.com/code-423n4/2022-12-forgotten-runiverse/blob/dcad1802bf258bf294900a08a03ca0d26d2304f4/contracts/RuniverseLandMinter.sol#L323-L341
None
Consider making RuniverseLandMinter the only minter for RuniverseLand
#0 - GalloDaSballo
2022-12-23T19:57:27Z
Risk of broken invariant, will flag, unsure about severity
#1 - c4-sponsor
2023-01-04T02:12:02Z
msclecram marked the issue as sponsor acknowledged
#2 - GalloDaSballo
2023-01-05T10:52:14Z
The warden has shown a way to bypass specific checks, while the function is privileged, the lack of checks is inconsistent with the checks applied in other parts of the codebase.
For this reason, I agree with Medium Severity
#3 - c4-judge
2023-01-06T14:28:05Z
GalloDaSballo marked the issue as selected for report
🌟 Selected for report: Lambda
Also found by: Dravee, cccz, hansfriese
Data not available
In RuniverseLand.mintTokenId, _mint takes in two parameters, recipient and tokenId
_mint(recipient, tokenId);
However, if the recipient is a contract address that does not support ERC721, the NFT can be frozen in the contract.
As per the documentation of EIP-721:
A wallet/broker/auction application MUST implement the wallet interface if it will accept safe transfers.
https://eips.ethereum.org/EIPS/eip-721
As per the documentation of ERC721.sol by OpenZeppelin:
None
use safeMint instead of mint to check received address support for ERC721 implementation
#0 - GalloDaSballo
2022-12-23T19:49:17Z
Not sold on Med, but is valid
#1 - c4-sponsor
2023-01-04T02:06:28Z
msclecram marked the issue as sponsor acknowledged
#2 - GalloDaSballo
2023-01-05T08:55:54Z
Downgrading to QA per this reasoning: https://github.com/code-423n4/2022-09-artgobblers-findings/issues/321#issuecomment-1275317394
Both mint and safeMint have downsides, these are worth flagging, but by themselves, in a fairly open-ended codebase, they are not sufficient to demonstrate a Med Severity
L
#3 - c4-judge
2023-01-05T08:56:00Z
GalloDaSballo changed the severity to QA (Quality Assurance)
#4 - GalloDaSballo
2023-01-06T14:27:22Z
2L 1R
A
#5 - c4-judge
2023-01-06T14:27:28Z
GalloDaSballo marked the issue as grade-b
#6 - c4-judge
2023-01-06T14:27:37Z
GalloDaSballo marked the issue as grade-a