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 over 1 year 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.