EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-8129: Non-Transferable Token

An interface for tokens permanently and structurally bound to a single address, with no transfer function defined at the interface level

Authors
Created2026-01-19
Discussion Linkhttps://ethereum-magicians.org/t/erc-8129-non-transferable-token/27407
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#1479PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationCore InterfaceMetadata Interface (Required)Behavior SpecificationEventsERC-165 Interface IdentificationRationaleWhy Not Extend ERC-721 or Use Consensual Transfer?ERC-721 Extensions (ERC-5192, ERC-5484)Consensual TransferThis StandardMinimal Interface DesignWhy Include address to Parameter in Mint?Why Allow Burning?Comparison with Existing StandardsBackwards CompatibilityReference ImplementationSecurity ConsiderationsPrivate Key CompromisePermanent BindingMinting AuthorizationInterface DetectionReentrancyCopyright

Abstract

A non-transferable token is bound to a single address for its entire lifetime: once minted, it can never be moved, sold, or reassigned by any party, including its owner. This makes non-transferable tokens suitable for representing credentials, achievements, certifications, memberships, and other identity attestations that only have meaning when tied to the party they were issued to.

This EIP defines such tokens by omission rather than restriction: the interface defines minting, burning, and ownership queries, and simply does not define any transfer function. There is no transferFrom, no approve, and no signature-gated handoff to block or bypass - non-transferability is a property of the interface itself, not a rule enforced on top of a transferable one.

Motivation

Non-transferable tokens represent credentials, achievements, certifications, memberships, and identity attestations - assets that by their nature should be permanently bound to their owner. A university diploma, a proof of attendance, or a revocable membership badge only has meaning if it cannot be sold, gifted, or otherwise separated from the identity it was issued to. These use cases deserve a dedicated standard that explicitly communicates non-transferability through the absence of transfer functions, not their restriction.

Current Soulbound token implementations take different approaches but all retain some form of token movement between addresses:

Both approaches create several problems:

  1. Semantic Mismatch: Tokens that should never move between addresses still carry mechanisms for doing so - either through blocked transfer functions (ERC-5192, ERC-5484) or consensual movement (via signature-gated give/take schemes). True soulbound tokens should be permanently bound to their recipient.

  2. Bytecode Bloat: Standards extending ERC-721 inherit functions like transferFrom, safeTransferFrom, approve, setApprovalForAll, getApproved, and isApprovedForAll in the contract bytecode, even when these functions will never execute successfully. This increases deployment costs and reduces available space for actual token functionality.

  3. Interface Confusion: External contracts and interfaces may incorrectly assume transfer or movement capabilities exist, leading to integration issues and user confusion.

  4. Not Truly Non-Transferable: Existing implementations either block transfers through restrictions or allow consensual movement between addresses. In both cases, the token is not fundamentally bound to a single address - it's restricted from free transfer or requires consent to move.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Core Interface

Every compliant contract MUST implement the ERC8129 (Non-Transferable Token) interface:

pragma solidity ^0.8.0;

/// @title ERC-8129 Non-Transferable Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-8129
/// Note: the ERC-165 identifier for this interface is 0x4ba63534.
interface ERC8129 {
    /// @dev Emitted when a token is minted and bound to an address
    /// @param to The address the token is bound to
    /// @param tokenId The identifier of the minted token
    event Mint(address indexed to, uint256 indexed tokenId);

    /// @dev Emitted when a token is burned
    /// @param from The address the token was bound to
    /// @param tokenId The identifier of the burned token
    event Burn(address indexed from, uint256 indexed tokenId);

    /// @notice Mint a new non-transferable token to a specified address
    /// @dev The token MUST be bound to the address specified in the 'to' parameter
    /// @param to The address to bind the token to
    /// @return tokenId The identifier of the newly minted token
    function mint(address to) external returns (uint256 tokenId);

    /// @notice Burn a non-transferable token
    /// @dev MUST revert if msg.sender is not the owner of tokenId
    /// @param tokenId The identifier of the token to burn
    function burn(uint256 tokenId) external;

    /// @notice Get the owner of a token
    /// @dev MUST revert if tokenId does not exist
    /// @param tokenId The identifier of the token
    /// @return owner The address that owns the token
    function ownerOf(uint256 tokenId) external view returns (address owner);
}

Metadata Interface (Required)

Compliant contracts MUST implement ERC-721's ERC721Metadata interface for human-readable token information.

See ERC-721 for a definition of its metadata JSON Schema.

All compliant contracts MUST implement both ERC8129 and IERC721Metadata interfaces.

Behavior Specification

  1. Minting:

    • Tokens MUST be minted to a specified address via the to parameter
    • The minting function MUST emit the Mint event
    • Each token MUST have a unique identifier
    • The to parameter allows issuers to mint tokens directly to recipients (e.g., educational certificates, membership cards)
  2. Burning:

    • Only the token owner MUST be able to burn their token
    • The burning function MUST emit the Burn event
    • After burning, ownerOf(uint256 tokenId) for that token MUST revert
  3. Non-Transferability:

    • Compliant contracts MUST NOT implement any transfer functionality
    • There MUST be no mechanism to change the owner of an existing token
    • The only way to change token ownership is through burn and re-mint operations by authorized parties
  4. Owner Queries:

    • ownerOf(uint256 tokenId) MUST return the address that owns the specified token
    • ownerOf(uint256 tokenId) MUST revert for non-existent tokens

Events

  • The Mint event MUST be emitted whenever a token is created and bound to an address, regardless of which function performs the creation (e.g., batch-minting functions MUST emit one Mint event per token created).
  • The Burn event MUST be emitted whenever a token is destroyed and its binding to an address is removed, regardless of which function performs the destruction.
  • Implementations MUST NOT emit Mint or Burn events for operations that do not change whether a token exists (e.g., metadata updates).

ERC-165 Interface Identification

Contracts implementing this standard MUST implement the ERC-165 supportsInterface function and MUST return true for:

  • The IERC8129 interface ID 0x4ba63534
  • The IERC721Metadata interface ID 0x5b5e139f
  • The ERC-165 interface ID 0x01ffc9a7

External contracts MUST NOT assume transfer capabilities based solely on the presence of metadata functions; they MUST rely on ERC-165 interface support to determine capabilities.

Rationale

Why Not Extend ERC-721 or Use Consensual Transfer?

ERC-721 Extensions (ERC-5192, ERC-5484)

ERC-721 is architecturally designed around transferability. Every aspect of its interface assumes tokens can move between addresses. Attempting to create non-transferable tokens by blocking these functions creates an architectural mismatch:

  • Transfer functions exist but always revert
  • Approval mechanisms serve no purpose
  • Events like Transfer and Approval create confusion
  • Storage slots for approvals and operators are unused

Consensual Transfer

While some approaches avoid implementing ERC-721's transfer interface directly, they still expose give()/take()-style functions that let tokens move between addresses with signature consent. This creates a fundamental contradiction:

  • Tokens can still change owners through consensual operations
  • The give/take mechanism contradicts the concept of permanent binding
  • Adds complexity through signature verification and structured data
  • The token is "movable with consent" rather than truly soulbound

This Standard

A dedicated standard removes transfer baggage entirely and eliminates any mechanism for tokens to move between addresses, even with consent. Once minted to an address, the token is permanently bound.

Minimal Interface Design

The core interface contains only what is essential for non-transferable tokens:

  • mint(address to): Create and bind token to specified address
  • burn(uint256 tokenId): Destroy token
  • ownerOf(uint256 tokenId): Verify ownership

Additionally, the standard REQUIRES ERC-721 Metadata interface (name(), symbol(), tokenURI(uint256 tokenId)) for compatibility with existing wallet and indexer infrastructure while maintaining minimalism.

Why Include address to Parameter in Mint?

The mint(address to) function allows issuers to directly mint tokens to recipients, which is essential for use cases such as:

  • Educational institutions issuing diplomas to graduates
  • Organizations issuing membership credentials
  • Event organizers issuing attendance certificates
  • Credential issuers binding attestations to specific addresses

This design pattern aligns with real-world issuance scenarios where the issuer (contract caller) is different from the recipient.

Why Allow Burning?

While tokens cannot be transferred, allowing the owner to burn their token provides:

  • User autonomy to remove unwanted credentials
  • Mechanisms for credential revocation
  • Compatibility with credential lifecycle management

Comparison with Existing Standards

FeatureERC-721 Extensions (5192, 5484)Consent-Based ApproachesThis Standard
Implements ERC-721YesNoNo
Transfer functionsPresent but blockedAbsentAbsent
Movement between addressesBlockedVia give/takeImpossible
Approval mechanismsPresent but unusedAbsentAbsent
Deployment bytecode~500+ lines~300 lines~100 lines
Semantic clarityTransferable with restrictionsMovable with consentPermanently bound
Truly non-transferableNo (logic exists)No (can move)Yes

Backwards Compatibility

This standard is not backwards compatible with ERC-721. This is intentional - tokens that are fundamentally non-transferable should not masquerade as transferable tokens.

Wallets and marketplaces can detect this standard via ERC-165 and treat these tokens appropriately (e.g., not showing transfer or listing options).

Reference Implementation

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

import "./IERC8129.sol";
import "./IERC721Metadata.sol";

contract ERC8129 is IERC8129, IERC721Metadata {
    uint256 private _tokenIdCounter;
    string private _name;
    string private _symbol;
    string private _baseURI;

    mapping(uint256 => address) private _owners;

    error NotOwner();
    error TokenNotFound();
    error InvalidAddress();

    constructor(string memory name_, string memory symbol_, string memory baseURI_) {
        _name = name_;
        _symbol = symbol_;
        _baseURI = baseURI_;
    }

    function mint(address to) external override returns (uint256) {
        if (to == address(0)) revert InvalidAddress();

        _tokenIdCounter++;
        uint256 tokenId = _tokenIdCounter;
        _owners[tokenId] = to;

        emit Mint(to, tokenId);
        return tokenId;
    }

    function burn(uint256 tokenId) external override {
        if (_owners[tokenId] != msg.sender) revert NotOwner();

        address owner = _owners[tokenId];
        delete _owners[tokenId];

        emit Burn(owner, tokenId);
    }

    function ownerOf(uint256 tokenId) external view override returns (address) {
        address owner = _owners[tokenId];
        if (owner == address(0)) revert TokenNotFound();
        return owner;
    }

    function name() external view override returns (string memory) {
        return _name;
    }

    function symbol() external view override returns (string memory) {
        return _symbol;
    }

    function tokenURI(uint256 tokenId) external view override returns (string memory) {
        if (_owners[tokenId] == address(0)) revert TokenNotFound();
        return _baseURI;
    }

    function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
        return
            interfaceId == type(IERC8129).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == 0x01ffc9a7; // ERC-165
    }
}

Security Considerations

Private Key Compromise

If a user's private key is compromised, the attacker gains access to all non-transferable tokens bound to that address. Unlike transferable tokens, there is no way to recover these credentials by moving them to a secure address.

Mitigation: Applications should consider:

  • Multi-signature schemes for high-value credentials
  • Time-locked or conditional burning mechanisms
  • Off-chain verification in addition to on-chain ownership

Permanent Binding

Tokens are permanently bound to their initial recipient address. If that address becomes inaccessible (lost keys, smart contract bugs), the token cannot be recovered.

Mitigation: Consider implementing optional issuer-controlled burning for recovery scenarios, clearly documented in token metadata.

Minting Authorization

The mint(address to) function allows minting to any address. Implementations should include appropriate access controls to ensure only authorized parties can mint tokens.

Interface Detection

Because this standard requires the ERC-721 metadata interface, a contract implementing ERC8129 exposes name(), symbol(), and tokenURI() just like a transferable ERC-721 token would. Integrators that infer transfer capability from the presence of these metadata functions, instead of checking ERC-165 support for the ERC8129 interface, risk treating a non-transferable token as transferable - for example, listing it on a marketplace or attempting a transfer that will always fail.

Reentrancy

The minimal interface reduces reentrancy attack surface, but implementations should still follow checks-effects-interactions pattern, especially if mint(address to) or burn(uint256 tokenId) trigger external calls.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth