Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

`HorseStore.huff::mintHorse()` can't mint more than one horse

Summary

The mintHorse() implementation in HorseStore.huff prevents the minting of more than one horse. The issue arises from the failure to update the TOTAL_SUPPLY variable after each minting operation. Consequently, the same tokenId value is used in subsequent minting attempts, triggering a revert with the error message ALREADY_MINTED.

Vulnerability Details

Test Case

To reproduce the test, paste the function inside HorseStoreHuff.t.sol::HorseStoreHuff, then run forge test --mt testFail_HuffCantMintMultipleHorses -vvvv in the terminal

function testFail_HuffCantMintMultipleHorses() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
vm.prank(user);
horseStore.mintHorse();
vm.prank(user2);
horseStore.mintHorse();
vm.prank(user3);
horseStore.mintHorse();
}

Logs

Running 1 test for test/HorseStoreHuff.t.sol:HorseStoreHuff
[PASS] testFail_HuffCantMintMultipleHorses() (gas: 65832)
Traces:
[65832] HorseStoreHuff::testFail_HuffCantMintMultipleHorses()
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802]
├─ [0] VM::label(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], "user2")
│ └─ ← ()
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]
├─ [0] VM::label(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], "user3")
│ └─ ← ()
├─ [0] VM::prank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← ()
├─ [50931] 0x6d2eed85750d316088343D6d5e91ca59eb052768::mintHorse()
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], tokenId: 0)
│ └─ ← ()
├─ [0] VM::prank(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802])
│ └─ ← ()
├─ [501] 0x6d2eed85750d316088343D6d5e91ca59eb052768::mintHorse()
│ └─ ← revert: ALREADY_MINTED
└─ ← revert: ALREADY_MINTED

Impact

The protocol becomes unusable after a user mints a horse, as subsequent minting attempts fail, leading to the inability to mint new horses.

Tools Used

Manual review

Recommendations

  1. Load TOTAL_SUPPLY value from storage in MINT_HORSE()

#define macro MINT_HORSE() = takes (0) returns (0) {
[TOTAL_SUPPLY] // [TOTAL_SUPPLY]
+ sload // [totalSupply]
caller // [msg.sender, TOTAL_SUPPLY]
_MINT() // []
stop // []
}
  1. Implement a macro to update TOTAL_SUPPLY

+#define macro _UPDATE_TOTAL_SUPPLY() = takes (0) returns (0) {
+ [TOTAL_SUPPLY] // [TOTAL_SUPPLY]
+ sload // [totalSupply]
+ 0x01 add // [totalSupply+1]
+ [TOTAL_SUPPLY] // [TOTAL_SUPPLY]
+ sstore // []
+}
  1. Update total supply in _MINT()

#define macro _MINT() = takes (2) returns (0) {
// Input stack: // [to, tokenId]
// Output stack: // []
// Check that the recipient is valid
dup1 iszero invalid_recipient jumpi // [to, tokenId]
// Create the minting params
0x00 dup3 // [tokenId, from (0x00), to, tokenId]
// Check token ownership
[OWNER_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [owner, from (0x00), to, tokenId]
unauthorized jumpi
// Give tokens to the recipient.
TRANSFER_GIVE_TO() // [from (0x00), to, tokenId]
// Emit the transfer event.
__EVENT_HASH(Transfer) // [sig, from (0x00), to, tokenId]
0x00 0x00 log4 // []
+ // Update the total supply
+ _UPDATE_TOTAL_SUPPLY() // []
// Continue Executing
cont jump
invalid_recipient:
INVALID_RECIPIENT(0x00)
unauthorized:
ALREADY_MINTED(0x00)
cont:
}
Updates

Lead Judging Commences

inallhonesty Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

Failure to increment total supply on mint

Failure to properly load the totalSupply in Huff

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!