Skip to content

Latest commit

 

History

History
126 lines (90 loc) · 7.03 KB

File metadata and controls

126 lines (90 loc) · 7.03 KB
id TIP-1026
title Token Logo URI
description Adds a logoURI string field to TIP-20 tokens for on-chain token icon metadata.
authors Dan Robinson
status Approved
related TIP-20
protocolVersion T5

TIP-1026: Token Logo URI

Abstract

Adds a logoURI field to TIP-20 tokens — a string capped at 256 bytes, mutable by the token admin and validated against a small allowlist of URI schemes. This allows wallets and explorers to read a token's icon URI directly from the contract for metadata distribution; curation/verification of trusted tokens remains an off-chain concern (see Out of Scope).

Motivation

Token icons are currently distributed through an off-chain token list registry (tokenlist.tempo.xyz). Wallets, explorers, and other apps must query this external service to display token icons, and issuers must submit a PR to a separate repository after deploying their token.

Adding logoURI as a first-class on-chain field makes token metadata self-describing: any token deployed with TIP-1026 metadata gets discoverability without an off-chain registry round-trip. The 256-byte cap prevents abuse (e.g., storing excessively large strings that could degrade indexer or explorer performance).

Out of Scope

This TIP is limited to metadata distribution. It does not define which tokens are trusted, verified, or suitable for integration by wallets, DEXes, or explorers. Decisions around trust and curation, such as gas tokens or swappable assets remain offchain and at the discretion of integrators.


Specification

Interface

The following functions are added to ITIP20:

/// @notice Returns the logo URI for this token
/// @return The logo URI string (max 256 bytes)
function logoURI() external view returns (string memory);

/// @notice Sets the logo URI for this token (requires DEFAULT_ADMIN_ROLE)
/// @param newLogoURI The new logo URI (must be <= 256 bytes and, if non-empty,
///                   a valid URI with an allowed scheme — see Behavior).
/// @dev Reverts with LogoURITooLong if the URI exceeds 256 bytes.
///      Reverts with InvalidLogoURI if the URI is non-empty and either not
///      syntactically a URI or its scheme is not in the allowlist.
///      An empty string is valid and clears the logo URI.
function setLogoURI(string calldata newLogoURI) external;

Events

/// @notice Emitted when the logo URI is updated.
/// @param updater The account that performed the update.
/// @param newLogoURI The new logo URI.
event LogoURIUpdated(address indexed updater, string newLogoURI);

Errors

/// @notice The provided logo URI exceeds the maximum length of 256 bytes
error LogoURITooLong();

/// @notice The provided logo URI is non-empty and is either not a syntactically
///         valid URI or its scheme is not in the allowlist (see Behavior).
error InvalidLogoURI();

Behavior

  • logoURI() returns the current logo URI. Returns an empty string if not set.
  • setLogoURI(string) updates the logo URI. Restricted to DEFAULT_ADMIN_ROLE.
    • Reverts with LogoURITooLong if bytes(newLogoURI).length > 256.

    • Reverts with InvalidLogoURI if newLogoURI is non-empty and either does not have a scheme parseable per RFC 3986 §3.1 (scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) followed by :) or the scheme is not in the allowlist:

      Scheme Notes
      https Recommended for general web-hosted assets.
      http Allowed for completeness; integrators should prefer https.
      ipfs Recommended for content-addressed assets.
      data Useful for small inline images; subject to the 256-byte cap.

      Scheme matching is ASCII-case-insensitive (e.g. HTTPS and https are equivalent).

    • Empty strings ("") are explicitly valid and clear the logo URI; no scheme check is performed in that case.

Factory Support

A new Solidity overload of TIP20Factory.createToken is added that accepts an additional logoURI argument:

function createToken(
    string calldata name,
    string calldata symbol,
    string calldata currency,
    address quoteToken,
    address admin,
    bytes32 salt,
    string calldata logoURI
) external returns (address);

The new overload validates logoURI with the same rules as setLogoURI. Validation MAY occur before or after deployment, but a rejected URI MUST cause the entire transaction to revert so no partially-created token is observable. If logoURI is non-empty, the overload writes it and emits LogoURIUpdated from the new token's address with updater = msg.sender. An empty logoURI skips both the slot write and the event.

This TIP is non-breaking. The existing createToken selector and TokenCreated event remain unchanged, new functionality is additive and gated behind the activating hardfork, and existing integrations continue to work without modification.

Recommended Formats

  • HTTPS: https://example.com/icon.png (~40–120 bytes)
  • IPFS: ipfs://QmXfzKRvjZz3u5JRgC4v5mGVbm9ahrUiB4DgzHBsnWbTMM (~53 bytes)

Square aspect ratio is recommended. Rasterized formats (PNG / WebP / static, single-frame) are recommended over SVG; integrators that accept SVG must follow the SVG-handling guidance in Security Considerations.

Security Considerations

The protocol enforces only structural checks: a 256-byte length cap and a scheme allowlist (https, http, ipfs, data). The resolved endpoint and its content must be treated as untrusted by all consumers.

The protocol only validates URI structure. Integrators are responsible for accounting for tracking, as direct logo fetches expose user metadata such as IP address to the endpoint operator, for executable SVG content which should not be rendered inline, for image decoder vulnerabilities since all fetched images are untrusted input, and for impersonation since tokens may claim arbitrary branding and trust must come from offchain curation.

Invariants

  1. Length cap. bytes(logoURI()).length <= 256 must always hold.
  2. Backwards compatibility. The legacy 6-argument createToken selector and the TokenCreated event signature are unchanged by this TIP.
  3. Admin-only mutation. setLogoURI MUST revert with Unauthorized for any caller other than the token admin; only the admin can mutate logoURI.
  4. URI validation. setLogoURI and the 7-argument createToken overload MUST reject any non-empty URI that has no parseable scheme (RFC 3986 §3.1) or whose scheme is not in the allowlist (https, http, ipfs, data, ASCII-case-insensitive), reverting with InvalidLogoURI. Oversized URIs MUST revert with LogoURITooLong.
  5. Factory atomicity. The 7-argument createToken overload is atomic: a rejected logoURI MUST revert the entire transaction and leave the address returned by getTokenAddress(sender, salt) undeployed.