Case Study: ERC-20 + NFT Hybrid Token Audit — Infinite Recursive Loop and Unbounded Gas Attacks on Ethereum
Executive Summary
This contract links ERC-20 token transfers and NFT minting/burning in a two-way relationship: transferring ERC-20 tokens triggers NFT logic, and NFT transfers trigger ERC-20 logic. This creates an infinite recursive loop — each hook calls the other, which calls the other again, until the transaction runs out of gas and fails. The loop effectively makes it impossible to transfer tokens or NFTs under many real-world conditions.
A secondary critical bug causes double-charging: a bulk NFT transfer function triggers individual ERC-20 transfers for each NFT and then applies another ERC-20 deduction at the end. Users lose more tokens than intended on every bulk operation.
Owner controls are unconstrained — core parameters like the price ratio between tokens and NFTs can be changed instantly with no delay, no cap, and no notice.
Risk Assessment
This contract has a critical recursive loop that can prevent all transfers, making the token functionally unusable. The double-charging bug compounds the risk. These are not edge-case bugs — they trigger in the normal operation of the contract.
Key Findings
Infinite Recursive Loop Between ERC-20 and NFT Transfer Hooks
What We Found
The ERC-20 transfer function triggers the NFT logic, and the NFT transfer function triggers the ERC-20 logic. Each one calls the other, which calls the first one again, in a loop that never ends. Every such transaction exhausts the gas limit and fails. Under many normal conditions, neither tokens nor NFTs can be transferred at all.
Why It Matters
All transfer transactions that touch both the ERC-20 and NFT layers will fail with an out-of-gas error. The token becomes functionally non-transferable.
What Should Be Done
Add a reentrancy guard or a dedicated 'in-transfer' flag to break the recursive cycle. Redesign the hook architecture so one layer does not call back into the other mid-execution.
Double-Charging in Bulk NFT Transfer — Tokens Burned Twice
What We Found
When you transfer multiple NFTs at once, the contract deducts ERC-20 tokens for each NFT individually and then deducts the total again at the end. You get charged twice: once per item and then once for the whole batch. Depending on the size of the batch, this can consume many times more tokens than the operation should cost.
Why It Matters
Users lose significantly more ERC-20 tokens than intended on every bulk NFT transfer. This makes bulk operations economically destructive and unpredictable.
What Should Be Done
Restructure the bulk transfer function to either batch the ERC-20 accounting once at the end or pass a flag to suppress per-item deductions inside the loop.
Untrusted External Call During NFT Minting Can DoS or Manipulate Traits
What We Found
When a new NFT is created, the contract calls an external address to generate the image parameters for that NFT. If that external address is changed by the owner or is itself compromised, an attacker can make minting fail for everyone (permanently blocking new NFTs) or inject arbitrary traits into newly minted items.
Why It Matters
A malicious or compromised external oracle can block all NFT minting or produce manipulated trait data for new tokens, undermining the integrity of the NFT collection.
What Should Be Done
Validate all return data from the external oracle before using it. Add a fallback minting path that works without the oracle. Restrict who can update the oracle address with a timelock.
Unbounded Loops in NFT Mint and Burn Functions Cause Gas DoS
What We Found
The functions that create or destroy large numbers of NFTs loop over every item one by one with no maximum count. If someone tries to mint or burn a large number of NFTs, the transaction can exceed the gas limit and fail. As the collection grows, even moderate-sized operations can become permanently impossible.
Why It Matters
Large mint or burn operations fail with out-of-gas errors. As the collection size grows, the gas cost increases until the functions become entirely unusable.
What Should Be Done
Add a maximum batch size parameter to all loop-based mint and burn functions. Consider an iterator-based pagination approach for large collections.
What a Secure Contract Should Have
Disclaimer: This case study is published for educational purposes only. It reflects the state of the analyzed contract at the time of audit and does not constitute investment advice, an endorsement, or a guarantee of security. Smart contracts may be modified after an audit. HyperAudit is not liable for losses arising from interaction with any contract referenced in this report. Project names and addresses have been removed to protect ongoing remediation efforts. For a full audit of your own contracts, visit hyperaudit.io.
Building a project?
Get the same depth of analysis on your own contracts before you deploy. Reports delivered in hours, not weeks.
Audit Your ContractThinking about buying a token?
Before you buy, find out if the contract is safe. We can audit any token on any EVM chain and tell you exactly what risks you're taking — in plain language you can act on.
Check a Token Before You Buy