ERC-5489: NFT Hyperlink Extension
ERC-5489 lets NFTs carry embedded hyperlink slots: the holder allocates URL "slots" on their NFT and assigns each slot to a delegate who controls the link target. Used for:
- Promotional NFTs — brands buy hyperlink slots on popular collections, link to their landing pages.
- Sponsored content — NFT holders monetise their NFT's hyperlink slots without giving up ownership.
- Composable references — slot 1 → wiki, slot 2 → marketplace, slot 3 → forum thread.
- Time-limited promotions — slots expire so the URL doesn't get stuck pointing at a dead campaign.
The owner allocates slots; each slot has a slotURI controller (could be the owner themselves, or a delegated bidder); the controller sets / updates the URL.
Required Interface
solidity
interface IERC5489 {
event SlotUriUpdated(uint256 indexed tokenId, address indexed slotManagerAddr,
string slotUri);
function setSlotUri(uint256 tokenId, string calldata newUri) external;
function authorizeSlotTo(uint256 tokenId, address slotManagerAddr) external;
function revokeAuthorization(uint256 tokenId, address slotManagerAddr) external;
function revokeAllAuthorizations(uint256 tokenId) external;
function getSlotUri(uint256 tokenId, address slotManagerAddr)
external view returns (string memory);
}Each slotManagerAddr holds an independent slot. The owner can revoke slot authorizations at any time.
Neo Equivalent: NEP-11 + (tokenId, manager) URL Storage
csharp
public static void AuthorizeSlotTo(ByteString tokenId, UInt160 manager)
{
if (!Runtime.CheckWitness(OwnerOf(tokenId))) throw new Exception("NEP11:NotOwner");
Storage.Put(Storage.CurrentContext, AuthKey(tokenId, manager), 1);
}
public static void SetSlotUri(ByteString tokenId, string newUri)
{
var manager = Runtime.CallingScriptHash;
if (!Runtime.CheckWitness(manager)) throw new Exception("NEP11:NoAuth");
if (Storage.Get(Storage.CurrentContext, AuthKey(tokenId, manager)) is null)
throw new Exception("NEP11:NotAuthorised");
Storage.Put(Storage.CurrentContext, UriKey(tokenId, manager), newUri);
OnSlotUriUpdated(tokenId, manager, newUri);
}
public static string GetSlotUri(ByteString tokenId, UInt160 manager)
=> (string)Storage.Get(Storage.CurrentContext, UriKey(tokenId, manager));| ERC-5489 (Ethereum) | Neo Equivalent | Notes |
|---|---|---|
authorizeSlotTo(tokenId, manager) | AuthorizeSlotTo(tokenId, manager) owner-witness-checked | |
revokeAuthorization(tokenId, manager) | RevokeAuthorization(tokenId, manager) | Removes auth + clears URI |
revokeAllAuthorizations(tokenId) | RevokeAllAuthorizations(tokenId) | Iterates auth prefix |
setSlotUri(tokenId, uri) | SetSlotUri(tokenId, uri) manager-witness-checked | |
getSlotUri(tokenId, manager) | GetSlotUri(tokenId, manager) view | Direct port |
SlotUriUpdated event | OnSlotUriUpdated notification |
Composition
- ERC-7160 — multi-metadata. ERC-5489 slots complement multi-metadata: pinned metadata + per-slot promotional URLs.
- ERC-2135 — consumable. Promotional NFTs may have consumable slots (one-shot redemption).
- ERC-7432 — roles. Use roles for the slot manager delegation if a richer permission model is needed.
Migration Notes
For Solidity NFT collections monetising slots:
- Replace the slot authorization mapping with a Neo storage prefix.
- The slot URI storage uses the same per-(tokenId, manager) shape.
- Revocation = storage delete on the auth + URI keys.
- Renderers (wallets, marketplaces) iterate the manager prefix to show all active slot URIs for an NFT.
For NFT-as-billboard use cases, this is the standard. Wallets render the active slot URIs as a small panel beneath the NFT's primary metadata.
