# Mint count and id collision unchecked

Mint paths that trust a hook's count or let admin ids collide with auto-generated ids

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2023-12-01. Updated 2026-10-31._

## How it works
Mint paths assume two things that are not enforced: that a mint call actually delivers the number of tokens paid for, and that any externally supplied token id cannot equal an id the contract will generate later. When either assumption breaks, the contract's internal accounting (supply, counters, balances) diverges from reality. A mint hook controlled by another party can under-deliver, or an admin mint-by-id can occupy a slot the auto-increment logic will later hand out, so the next legitimate mint reverts.

## Where it shows up
- Marketplace or sale contract calling a creator-supplied `mintCountTo`/mint hook and trusting its return value [E3](https://bugbountylibrary.com/r/c4%3A2022-08-foundation%3AM-06.md)
- No `balanceOf` before/after check around an external mint call [E3](https://bugbountylibrary.com/r/c4%3A2022-08-foundation%3AM-06.md)
- Admin mint functions taking a raw `tokenId` while normal mints use a packed counter encoding [E2](https://bugbountylibrary.com/r/c4%3A2022-12-forgotten-runiverse%3AM-02.md)
- Token ids built from packed fields (plotSize, local/global counters) with no decode-and-validate step [E2](https://bugbountylibrary.com/r/c4%3A2022-12-forgotten-runiverse%3AM-02.md)
- `transfer`/`_transfer` with special-case branches when `to == address(this)` or a fixed contract address [E1](https://bugbountylibrary.com/r/dhl%3A20240529-metadragon.md)
- Any branch that mints or credits balances inside transfer logic [E1](https://bugbountylibrary.com/r/dhl%3A20240529-metadragon.md)

## How to review
For every mint entry point, identify who controls the callee and whether delivered count is measured, not reported. The invariant: after a paid mint, `balanceOf(recipient)` increases by exactly the paid `count`, verified by the caller. For id assignment, the invariant: no externally supplied id may fall in the range the auto-generator can produce; admin mint-by-id must decode packed fields and check them against current counters [E2](https://bugbountylibrary.com/r/c4%3A2022-12-forgotten-runiverse%3AM-02.md). For transfer functions, confirm no path mints or credits without a corresponding debit; special-case `to` branches must not bypass balance checks [E1](https://bugbountylibrary.com/r/dhl%3A20240529-metadragon.md).

## Variants seen
- Under-delivery: malicious creator hook mints fewer NFTs than paid [E3](https://bugbountylibrary.com/r/c4%3A2022-08-foundation%3AM-06.md)
- Id collision: owner mints arbitrary packed id equal to a future auto-generated id, bricking mints/buys [E2](https://bugbountylibrary.com/r/c4%3A2022-12-forgotten-runiverse%3AM-02.md)
- Unrestricted mint via transfer-to-self special case draining liquidity [E1](https://bugbountylibrary.com/r/dhl%3A20240529-metadragon.md)

## Impact and severity
E1 led to ~$180k drained on BSC; E2 permanently bricked all subsequent mints and buys (denial of service); E3 caused direct collector fund loss. Severity rises when the flaw is permanent (E2) or reachable by any caller (E1) rather than admin-only.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20240529-metadragon.md
- E2: https://bugbountylibrary.com/r/c4%3A2022-12-forgotten-runiverse%3AM-02.md
- E3: https://bugbountylibrary.com/r/c4%3A2022-08-foundation%3AM-06.md
