57268 sc insight erc1155base missing collection uri fallback causes significant gas waste on every token mint

Submitted on Oct 24th 2025 at 20:37:12 UTC by @Happy_Hunter for Audit Comp | Belongarrow-up-right

  • Report ID: #57268

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/tokens/base/ERC1155Base.sol

  • Impacts: Operational gas inefficiency (higher mint gas costs when storing full per-token URIs)

Description

Brief / Intro

The ERC1155Base.sol contract stores token URIs individually and the mint() function documentation indicates the design is to set a "Token-specific URI to set (overrides collection URI)". While this provides per-token metadata control, it causes avoidable gas costs when many tokens share the same metadata pattern. Adopting an optional fallback pattern (like OpenZeppelin's ERC1155URIStorage) can avoid writing duplicate/empty URIs to storage and significantly reduce gas consumed by mint operations.

Vulnerability Details

Affected contract:

  • contracts/v2/tokens/base/ERC1155Base.sol (lines referenced: 88-96, 146-153)

Root cause (two compounding design choices):

  1. No fallback logic: uri(uint256 tokenId) returns only the per-token _tokenUri[tokenId] and does not fall back to the collection-level _uri even when the per-token URI is empty.

// ERC1155Base.sol lines 146-153
string private _uri;  // Collection-level base URI
mapping(uint256 tokenId => string tokenUri) private _tokenUri;  // Per-token overrides

function uri(uint256 tokenId) public view override returns (string memory) {
    return _tokenUri[tokenId];  // No fallback to _uri
}
  1. Forced storage writes: mint() always writes the tokenUri parameter into storage (even when empty or redundant), causing expensive SSTORE operations for every mint.

Gas impact analysis:

  • Storing strings requires multiple storage slots (32 bytes each).

  • A 40-character URI can consume ~3 storage slots.

  • Each cold SSTORE (zero -> non-zero) costs ~20,000 gas.

  • Rough total: ~60,000 gas for URI storage alone (approximate; varies by content and environment).

Comparison with OpenZeppelin: OpenZeppelin's ERC1155URIStorage.sol implements a fallback pattern allowing tokens without a specific URI to use the collection-level _uri:

Trade-off:

  • Adding a conditional check to uri() increases view-call gas slightly but is a view-only cost.

  • Avoiding SSTORE operations in mint() (by not storing per-token URIs when unnecessary) reduces expensive write gas on every mint, which is much more impactful.

Real-world example (BelongCheckIn):

  • Venue and promoter tokens often share metadata. Both tokens are minted with full URIs, duplicating storage writes.

  • Using a collection base URI (e.g., https://api.belong.com/metadata/venue/) and omitting per-token URIs lets clients compute token metadata by replacing id per ERC-1155 rules, avoiding per-token SSTORE.

Impact Details

This is classified as an Insight: the contract works as intended and is secure, but the current design causes avoidable operational gas costs when many tokens share metadata patterns. As adoption scales, these costs may become significant.

References

Project contracts:

  • contracts/v2/tokens/base/ERC1155Base.sol

Relevant OpenZeppelin references:

  • https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol

  • https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol

Recommendation

Implement a fallback pattern aligned with OpenZeppelin's ERC1155URIStorage and the ERC-1155 metadata expectations.

Add a fallback to the collection-level URI in uri() so that per-token storage writes are optional:

By using this pattern:

  • mints can omit the tokenUri parameter (or pass an empty string) for tokens that should use the collection base URI,

  • the expensive per-token SSTORE is avoided,

  • clients still receive correct metadata (base URI + id substitution) per ERC-1155 standard.

circle-info

This is an efficiency recommendation — not a security vulnerability. Apply if reducing mint gas costs is a priority for the project.

Proof of Concept

chevron-rightTest Setup & Test Casehashtag

File: test/v2/tokens/creditToken.test.ts

Run:

chevron-rightTest Results (console & reporter)hashtag

Console output:

Hardhat Gas Reporter excerpt:

Was this helpful?