This proposal introduces a protocol that establishes a unified interface for managing both ERC-20 fungible tokens and ERC-721 non-fungible tokens (NFTs) on the Ethereum blockchain. By defining a common set of functions applicable to both token types, developers can seamlessly interact with ERC-20 and ERC-721 tokens using a single interface. This simplifies integration efforts and enhances interoperability within decentralized applications (DApps).
Motivation
The proposal aims to address the demand for assets combining the liquidity of ERC-20 tokens and the uniqueness of ERC-721 tokens. Current standards present a fragmentation, requiring users to choose between these features. This proposal fills that gap by providing a unified token interface, enabling smooth transitions between ERC-20 and ERC-721 characteristics to accommodate diverse blockchain applications.
Specification
Introduces a token contract that combines features from both ERC-20 and ERC-721 standards.
Supports state transitions between ERC-20 and ERC-721 modes, facilitating seamless conversion and utilization of both liquidity and non-fungibility.
Defines essential functions and events to support token interactions, conversions, and queries.
Implements low gas consumption ERC-20 mode to maintain efficiency comparable to typical ERC-20 token transfers.
Compliant contracts MUST implement the following Solidity interface:
pragmasolidity^0.8.0;/**
* @title ERC-7629 Unify Token Interface
* @dev This interface defines the ERC-7629 Unify Token, which unifies ERC-721 and ERC-20 assets.
*/interfaceIERC7629isIERC165{// ERC-20 Transfer event
eventERC20Transfer(addressindexedfrom,addressindexedto,uint256amount);// ERC-721 Transfer event
eventERC721Transfer(addressindexedfrom,addressindexedto,uint256indexedtokenId);// ERC-721 Transfer event
eventTransfer(addressindexedfrom,addressindexedto,uint256indexedtokenId);// Approval event for ERC-20 and ERC-721
eventApproval(addressindexedowner,addressindexedapproved,uint256indexedtokenId);// Approval event for ERC-20 and ERC-721
eventApproval(addressindexedowner,addressindexedapproved,uint256indexedtokenId);// Approval event for ERC-20
eventERC20Approval(addressindexedowner,addressindexedapproved,uint256indexedtokenId);// ApprovalForAll event for ERC-721
eventApprovalForAll(addressindexedowner,addressindexedoperator,boolapproved);// ERC-20 to ERC-721 Conversion event
eventERC20ToERC721(addressindexedto,uint256amount,uint256tokenId);// ERC-721 to ERC-20 Conversion event
eventERC20ToERC721(addressindexedto,uint256amount,uint256[]tokenIds);/**
* @dev Returns the name of the token.
*/functionname()externalviewreturns(stringmemory);/**
* @dev Returns the symbol of the token.
*/functionsymbol()externalviewreturns(stringmemory);/**
* @dev Returns the number of decimals used in the token.
*/functiondecimals()externalviewreturns(uint8);/**
* @dev Returns the total supply of the ERC-20 tokens.
*/functiontotalSupply()externalviewreturns(uint256);/**
* @dev Returns the balance of an address for ERC-20 tokens.
* @param owner The address to query the balance of.
*/functionbalanceOf(addressowner)externalviewreturns(uint256);/**
* @dev Returns the total supply of ERC-20 tokens.
*/functionerc20TotalSupply()externalviewreturns(uint256);/**
* @dev Returns the balance of an address for ERC-20 tokens.
* @param owner The address to query the balance of.
*/functionerc20BalanceOf(addressowner)externalviewreturns(uint256);/**
* @dev Returns the total supply of ERC-721 tokens.
*/functionerc721TotalSupply()externalviewreturns(uint256);/**
* @dev Returns the balance of an address for ERC-721 tokens.
* @param owner The address to query the balance of.
*/functionerc721BalanceOf(addressowner)externalviewreturns(uint256);/**
* @notice Get the approved address for a single NFT
* @dev Throws if `tokenId` is not a valid NFT.
* @param tokenId The NFT to find the approved address for
* @return The approved address for this NFT, or the zero address if there is none
*/functiongetApproved(uint256tokenId)externalviewreturns(address);/**
* @dev Checks if an operator is approved for all tokens of a given owner.
* @param owner The address of the token owner.
* @param operator The address of the operator to check.
*/functionisApprovedForAll(addressowner,addressoperator)externalviewreturns(bool);/**
* @dev Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner.
* @param owner The address of the token owner.
* @param spender The address of the spender.
*/functionallowance(addressowner,addressspender)externalviewreturns(uint256);/**
* @dev Returns the array of ERC-721 token IDs owned by a specific address.
* @param owner The address to query the tokens of.
*/functionowned(addressowner)externalviewreturns(uint256[]memory);/**
* @dev Returns the address that owns a specific ERC-721 token.
* @param tokenId The token ID.
*/functionownerOf(uint256tokenId)externalviewreturns(addresserc721Owner);/**
* @dev Returns the URI for a specific ERC-721 token.
* @param tokenId The token ID.
*/functiontokenURI(uint256tokenId)externalviewreturns(stringmemory);/**
* @dev Approve or disapprove the operator to spend or transfer all of the sender's tokens.
* @param spender The address of the spender.
* @param amountOrId The amount of ERC-20 tokens or ID of ERC-721 tokens.
*/functionapprove(addressspender,uint256amountOrId)externalreturns(bool);/**
* @dev Set or unset the approval of an operator for all tokens.
* @param operator The address of the operator.
* @param approved The approval status.
*/functionsetApprovalForAll(addressoperator,boolapproved)external;/**
* @dev Transfer ERC-20 tokens or ERC-721 token from one address to another.
* @param from The address to transfer ERC-20 tokens or ERC-721 token from.
* @param to The address to transfer ERC-20 tokens or ERC-721 token to.
* @param amountOrId The amount of ERC-20 tokens or ID of ERC-721 tokens to transfer.
*/functiontransferFrom(addressfrom,addressto,uint256amountOrId)externalreturns(bool);/**
* @notice Transfers the ownership of an NFT from one address to another address
* @dev Throws unless `msg.sender` is the current owner, an authorized
* operator, or the approved address for this NFT. Throws if `_rom` is
* not the current owner. Throws if `_to` is the zero address. Throws if
* `tokenId` is not a valid NFT. When transfer is complete, this function
* checks if `to` is a smart contract (code size > 0). If so, it calls
* `onERC721Received` on `to` and throws if the return value is not
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
* @param from The current owner of the NFT
* @param to The new owner
* @param tokenId The NFT to transfer
* @param data Additional data with no specified format, sent in call to `to`
*/functionsafeTransferFrom(addressfrom,addressto,uint256tokenId,bytescalldatadata)externalpayable;/**
* @notice Transfers the ownership of an NFT from one address to another address
* @dev This works identically to the other function with an extra data parameter,
* except this function just sets data to "".
* @param from The current owner of the NFT
* @param to The new owner
* @param tokenId The NFT to transfer
*/functionsafeTransferFrom(addressfrom,addressto,uint256tokenId)externalpayable;/**
* @dev Transfer ERC-20 tokens to an address.
* @param to The address to transfer ERC-20 tokens to.
* @param amount The amount of ERC-20 tokens to transfer.
*/functiontransfer(addressto,uint256amount)externalreturns(bool);/**
* @dev Retrieves the unit value associated with the token.
* @return The unit value.
*/functiongetUnit()externalviewreturns(uint256);/**
* @dev Converts ERC-721 token to ERC-20 tokens.
* @param tokenId The unique identifier of the ERC-721 token.
*/functionerc721ToERC20(uint256tokenId)external;/**
* @dev Converts ERC-20 tokens to an ERC-721 token.
* @param amount The amount of ERC-20 tokens to convert.
*/functionerc20ToERC721(uint256amount)external;}
Rationale
Common Interface for Different Token Types:
Introduces a unified interface to address the fragmentation caused by separate ERC-20 and ERC-721 standards.
Standardizes functions like transferFrom, mint, and burn, enabling developers to interact with both token types without implementing distinct logic.
Transfer Functionality:
Includes transferFrom function for seamless movement of tokens between addresses, as it’s a core component of both ERC-20 and ERC-721 standards.
Minting and Burning:
Incorporates mint and burn functions for creating and destroying tokens, essential for managing token supply and lifecycle.
Balance and Ownership Queries:
Provides functions like balanceOf and ownerOf for retrieving token balances and ownership information, crucial for both ERC-20 and ERC-721 tokens.
Compatibility and Extensibility:
Ensures compatibility with existing ERC-20 and ERC-721 implementations, minimizing disruption during transition.
Allows extension with additional functions and events for future enhancements.
Security Considerations:
Implements mechanisms to prevent common issues like reentrancy attacks and overflows, ensuring the security and robustness of the unified interface.
Backwards Compatibility
The proposed this proposal introduces a challenge in terms of backward compatibility due to the distinct balance query mechanisms utilized by ERC-20 and ERC-721 standards. ERC-20 employs balanceOf to check an account’s token balance, while ERC-721 uses balanceOf to inquire about the quantity of tokens owned by an account. To reconcile these differences, the ERC must consider providing either two separate functions catering to each standard or adopting a more generalized approach.
Compatibility Points
The primary compatibility point lies in the discrepancy between ERC-20’s balanceOf and ERC-721’s balanceOf functionalities. Developers accustomed to the specific balance query methods in each standard may face challenges when transitioning to this proposal.
Proposed Solutions
Dual Balance Query Functions:
Introduce two distinct functions, erc20BalanceOf and erc721TotalSupply, to align with the conventions of ERC-20 and ERC-721, respectively. Developers can choose the function based on the token type they are working with.
Security Considerations
Due to the dual nature of this proposal, potential differences in protocol interpretation may arise, necessitating careful consideration during development.
Comprehensive security audits are recommended, especially during mode transitions by users, to ensure the safety of user assets.