The expected behavior is that mintNft() collects the minting collateral exclusively in USDC via transferFrom, and any ETH accidentally included in the transaction should be rejected. The function does not need to accept ETH at any point.
What actually happens is that mintNft() is declared payable, meaning the EVM will accept any native ETH sent alongside the call without complaint. The function body never reads msg.value, never returns it, and the contract has no withdrawETH() function or ETH-capable fallback. ETH sent to this function is permanently locked.
The payable modifier is entirely unnecessary here — the function's payment mechanism is USDC, not ETH.
Likelihood:
Any user who calls mintNft via a script, multisig, or wallet UI that populates a native value field by default is at risk
Etherscan's "Write Contract" interface exposes a payableAmount field for payable functions — users interacting directly may enter a value there thinking it is required
Probability per individual user is low, but the protocol has a fixed MAX_SUPPLY of 1,000 mints, so the cumulative exposure across all minters is non-trivial
Impact:
ETH sent is permanently lost — there is no recovery path for affected users
The owner cannot rescue it either, as there is no ETH withdrawal function
Loss scales linearly with the amount sent: a user who sends 1 ETH loses 1 ETH with no recourse
Run with:
Expected console output:
Remove the payable modifier from mintNft(). This makes the function reject any transaction that includes ETH at the EVM level — no additional validation code is needed.
Why this works: a non-payable function in Solidity will automatically revert with a built-in error if msg.value > 0 is detected. No ETH can enter the function, so no ETH can be trapped.
Alternative: if there is ever a legitimate reason to accept ETH (e.g. a future native-token payment option), add an explicit guard at the top instead:
The simpler and preferred fix is removing payable entirely.
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.