The expected pattern in functions that interact with external contracts is to finalize internal state before making external calls, following the checks-effects-interactions pattern.
In both mintNft() and buy(), the contract performs an external ERC20 call before completing all related state updates. While the protocol is intended to work with USDC, and a standard USDC implementation is not expected to reenter, this ordering still weakens the contract's safety assumptions and creates unnecessary exposure if the configured token is non-standard, upgradeable, or behaves unexpectedly.
Likelihood:
The issue becomes relevant whenever the configured token does not behave like a simple, non-reentrant ERC20 implementation.
The risk increases if the token address is changed to an upgradeable, hook-enabled, or otherwise non-standard token in a future deployment.
Impact:
Unexpected control flow during token transfer can observe or interact with partially updated protocol state.
The contract becomes harder to reason about and more fragile to integration changes, even if no immediate exploit exists with standard USDC.
The issue is visible directly from the execution order in mintNft() and buy(): both functions call usdc.transferFrom(...) before all related protocol state has been finalized. This breaks the checks-effects-interactions pattern and leaves the contract in a partially updated state during the external token call.
Refactor these flows to follow checks-effects-interactions more closely. Finalize all internal state before making external calls where possible, and consider using a reentrancy guard on functions that transfer tokens and NFTs in the same execution path.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.