--- eip: 7629 title: ERC-20/ERC-721 Unified Token Interface description: introduces a single interface for ERC-20/ERC-721 tokens, enabling seamless interaction by defining common functions for both token types. author: 0xZeus1111 (@0xZeus1111), Nvuwa (@Nvuwa) discussions-to: https://ethereum-magicians.org/t/erc-7629-unified-token/18793 status: Draft type: Standards Track category: ERC created: 2024-02-18 requires: 20, 165, 721 --- ## Abstract This proposal introduces a protocol that establishes a unified interface for managing both [ERC-20](./eip-20.md) fungible tokens and [ERC-721](./eip-721.md) 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](./eip-20.md) and [ERC-721](./eip-721.md) 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](./eip-20.md) tokens and the uniqueness of [ERC-721](./eip-721.md) 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](./eip-20.md) and [ERC-721](./eip-721.md) characteristics to accommodate diverse blockchain applications. ## Specification - Introduces a token contract that combines features from both [ERC-20](./eip-20.md) and [ERC-721](./eip-721.md) standards. - Supports state transitions between [ERC-20](./eip-20.md) and [ERC-721](./eip-721.md) 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](./eip-20.md) mode to maintain efficiency comparable to typical [ERC-20](./eip-20.md) token transfers. Compliant contracts MUST implement the following Solidity interface: ```solidity pragma solidity ^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. */ interface IERC7629 is IERC165 { // ERC-20 Transfer event event ERC20Transfer( address indexed from, address indexed to, uint256 amount ); // ERC-721 Transfer event event ERC721Transfer( address indexed from, address indexed to, uint256 indexed tokenId ); // ERC-721 Transfer event event Transfer( address indexed from, address indexed to, uint256 indexed tokenId ); // Approval event for ERC-20 and ERC-721 event Approval( address indexed owner, address indexed approved, uint256 indexed tokenId ); // Approval event for ERC-20 and ERC-721 event Approval( address indexed owner, address indexed approved, uint256 indexed tokenId ); // Approval event for ERC-20 event ERC20Approval( address indexed owner, address indexed approved, uint256 indexed tokenId ); // ApprovalForAll event for ERC-721 event ApprovalForAll( address indexed owner, address indexed operator, bool approved ); // ERC-20 to ERC-721 Conversion event event ERC20ToERC721(address indexed to, uint256 amount, uint256 tokenId); // ERC-721 to ERC-20 Conversion event event ERC20ToERC721(address indexed to, uint256 amount, uint256[] tokenIds); /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the number of decimals used in the token. */ function decimals() external view returns (uint8); /** * @dev Returns the total supply of the ERC-20 tokens. */ function totalSupply() external view returns (uint256); /** * @dev Returns the balance of an address for ERC-20 tokens. * @param owner The address to query the balance of. */ function balanceOf(address owner) external view returns (uint256); /** * @dev Returns the total supply of ERC-20 tokens. */ function erc20TotalSupply() external view returns (uint256); /** * @dev Returns the balance of an address for ERC-20 tokens. * @param owner The address to query the balance of. */ function erc20BalanceOf(address owner) external view returns (uint256); /** * @dev Returns the total supply of ERC-721 tokens. */ function erc721TotalSupply() external view returns (uint256); /** * @dev Returns the balance of an address for ERC-721 tokens. * @param owner The address to query the balance of. */ function erc721BalanceOf(address owner) external view returns (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 */ function getApproved(uint256 tokenId) external view returns (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. */ function isApprovedForAll( address owner, address operator ) external view returns (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. */ function allowance( address owner, address spender ) external view returns (uint256); /** * @dev Returns the array of ERC-721 token IDs owned by a specific address. * @param owner The address to query the tokens of. */ function owned(address owner) external view returns (uint256[] memory); /** * @dev Returns the address that owns a specific ERC-721 token. * @param tokenId The token ID. */ function ownerOf(uint256 tokenId) external view returns (address erc721Owner); /** * @dev Returns the URI for a specific ERC-721 token. * @param tokenId The token ID. */ function tokenURI(uint256 tokenId) external view returns (string memory); /** * @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. */ function approve( address spender, uint256 amountOrId ) external returns (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. */ function setApprovalForAll(address operator, bool approved) 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. */ function transferFrom( address from, address to, uint256 amountOrId ) external returns (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` */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external payable; /** * @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 */ function safeTransferFrom(address from, address to, uint256 tokenId) external payable; /** * @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. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Retrieves the unit value associated with the token. * @return The unit value. */ function getUnit() external view returns (uint256); /** * @dev Converts ERC-721 token to ERC-20 tokens. * @param tokenId The unique identifier of the ERC-721 token. */ function erc721ToERC20(uint256 tokenId) external; /** * @dev Converts ERC-20 tokens to an ERC-721 token. * @param amount The amount of ERC-20 tokens to convert. */ function erc20ToERC721(uint256 amount) external; } ``` ## Rationale Common Interface for Different Token Types: - Introduces a unified interface to address the fragmentation caused by separate [ERC-20](./eip-20.md) and [ERC-721](./eip-721.md) 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](./eip-20.md) and [ERC-721](./eip-721.md) 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](./eip-20.md) and [ERC-721](./eip-721.md) tokens. Compatibility and Extensibility: - Ensures compatibility with existing [ERC-20](./eip-20.md) and [ERC-721](./eip-721.md) 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](./eip-20.md) and [ERC-721](./eip-721.md) standards. [ERC-20](./eip-20.md) employs `balanceOf` to check an account's token balance, while [ERC-721](./eip-721.md) 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](./eip-20.md)'s balanceOf and [ERC-721](./eip-721.md)'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](./eip-20.md) and [ERC-721](./eip-721.md), 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. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).