Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7629: ERC-20/ERC-721 统一代币接口

引入了一个用于 ERC-20/ERC-721 代币的单一接口,通过为两种代币类型定义通用函数来实现无缝交互。

Authors 0xZeus1111 (@0xZeus1111), Nvuwa (@Nvuwa)
Created 2024-02-18
Discussion Link https://ethereum-magicians.org/t/erc-7629-unified-token/18793
Requires EIP-20, EIP-165, EIP-721

摘要

本提案引入了一个协议,该协议为管理以太坊区块链上的 ERC-20 同质化代币和 ERC-721 非同质化代币 (NFT) 建立了一个统一的接口。通过定义适用于两种代币类型的通用函数集,开发人员可以使用单个接口与 ERC-20ERC-721 代币进行无缝交互。这简化了集成工作并增强了去中心化应用程序 (DApp) 中的互操作性。

动机

该提案旨在满足对结合 ERC-20 代币的流动性和 ERC-721 代币的独特性的资产的需求。当前的各种标准造成了碎片化,要求用户在这些功能之间进行选择。本提案通过提供统一的代币接口来填补这一空白,从而实现 ERC-20ERC-721 特性之间的平滑过渡,以适应各种区块链应用。

规范

  • 引入了一种代币合约,该合约结合了 ERC-20ERC-721 标准的功能。
  • 支持 ERC-20ERC-721 模式之间的状态转换,从而促进流动性和非同质化的无缝转换和利用。
  • 定义基本函数和事件以支持代币交互、转换和查询。
  • 实施低 gas 消耗的 ERC-20 模式,以保持与典型 ERC-20 代币转移相当的效率。

符合规范的合约必须实现以下 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.
 * @dev 此接口定义了 ERC-7629 统一代币,它统一了 ERC-721 和 ERC-20 资产。
 */
interface IERC7629  is IERC165 {
    // ERC-20 Transfer event
    // ERC-20 转移事件
    event ERC20Transfer(
        address indexed from,
        address indexed to,
        uint256 amount
    );

    // ERC-721 Transfer event
    // ERC-721 转移事件
    event ERC721Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    // ERC-721 Transfer event
    // ERC-721 转移事件
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    // Approval event for ERC-20 and ERC-721
    // ERC-20 和 ERC-721 的批准事件
    event Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    // Approval event for ERC-20 and ERC-721
    // ERC-20 和 ERC-721 的批准事件
    event Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    // Approval event for ERC-20
    // ERC-20 的批准事件
    event ERC20Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    // ApprovalForAll event for ERC-721
    // ERC-721 的 ApprovalForAll 事件
    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );

    // ERC-20 to ERC-721 Conversion event
    // ERC-20 到 ERC-721 转换事件
    event ERC20ToERC721(address indexed to, uint256 amount, uint256 tokenId);

    // ERC-721 to ERC-20 Conversion event
    // ERC-721 到 ERC-20 转换事件
    event ERC20ToERC721(address indexed to, uint256 amount, uint256[] tokenIds);

    /**
     * @dev Returns the name of the token.
     * @dev 返回代币的名称。
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     * @dev 返回代币的符号。
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the number of decimals used in the token.
     * @dev 返回代币中使用的小数位数。
     */
    function decimals() external view returns (uint8);

    /**
     * @dev Returns the total supply of the ERC-20 tokens.
     * @dev 返回 ERC-20 代币的总供应量。
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the balance of an address for ERC-20 tokens.
     * @dev 返回地址的 ERC-20 代币余额。
     * @param owner The address to query the balance of.
     * @param owner 要查询余额的地址。
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Returns the total supply of ERC-20 tokens.
     * @dev 返回 ERC-20 代币的总供应量。
     */
    function erc20TotalSupply() external view returns (uint256);

    /**
     * @dev Returns the balance of an address for ERC-20 tokens.
     * @dev 返回地址的 ERC-20 代币余额。
     * @param owner The address to query the balance of.
     * @param owner 要查询余额的地址。
     */
    function erc20BalanceOf(address owner) external view returns (uint256);

    /**
     * @dev Returns the total supply of ERC-721 tokens.
     * @dev 返回 ERC-721 代币的总供应量。
     */
    function erc721TotalSupply() external view returns (uint256);

    /**
     * @dev Returns the balance of an address for ERC-721 tokens.
     * @dev 返回地址的 ERC-721 代币余额。
     * @param owner The address to query the balance of.
     * @param owner 要查询余额的地址。
     */
    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.
     * @dev 如果 `tokenId` 不是有效的 NFT,则抛出异常。
     * @param tokenId The NFT to find the approved address for
     * @param tokenId 要查找批准地址的 NFT
     * @return The approved address for this NFT, or the zero address if there is none
     * @return 此 NFT 的批准地址,如果没有则为零地址
     */
    function getApproved(uint256 tokenId) external view returns (address);

    /**
     * @dev Checks if an operator is approved for all tokens of a given owner.
     * @dev 检查某个 operator 是否已获得特定所有者的所有代币的批准。
     * @param owner The address of the token owner.
     * @param owner 代币所有者的地址。
     * @param operator The address of the operator to check.
     * @param operator 要检查的 operator 的地址。
     */
    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.
     * @dev 返回 spender 将被允许代表 owner 花费的剩余代币数量。
     * @param owner The address of the token owner.
     * @param owner 代币所有者的地址。
     * @param spender The address of the spender.
     * @param spender 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.
     * @dev 返回特定地址拥有的 ERC-721 代币 ID 数组。
     * @param owner The address to query the tokens of.
     * @param owner 要查询代币的地址。
     */
    function owned(address owner) external view returns (uint256[] memory);

    /**
     * @dev Returns the address that owns a specific ERC-721 token.
     * @dev 返回拥有特定 ERC-721 代币的地址。
     * @param tokenId The token ID.
     * @param tokenId 代币 ID。
     */
    function ownerOf(uint256 tokenId) external view returns (address erc721Owner);

    /**
     * @dev Returns the URI for a specific ERC-721 token.
     * @dev 返回特定 ERC-721 代币的 URI。
     * @param tokenId The token ID.
     * @param tokenId 代币 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.
     * @dev 批准或不批准 operator 花费或转移发送者的所有代币。
     * @param spender The address of the spender.
     * @param spender spender 的地址。
     * @param amountOrId The amount of ERC-20 tokens or ID of ERC-721 tokens.
     * @param amountOrId ERC-20 代币的数量或 ERC-721 代币的 ID。
     */
    function approve(
        address spender,
        uint256 amountOrId
    ) external returns (bool);

    /**
     * @dev Set or unset the approval of an operator for all tokens.
     * @dev 设置或取消设置 operator 对所有代币的批准。
     * @param operator The address of the operator.
     * @param operator operator 的地址。
     * @param approved The approval status.
     * @param approved 批准状态。
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Transfer ERC-20 tokens or ERC-721 token from one address to another.
     * @dev 将 ERC-20 代币或 ERC-721 代币从一个地址转移到另一个地址。
     * @param from The address to transfer ERC-20 tokens or ERC-721 token from.
     * @param from 从中转移 ERC-20 代币或 ERC-721 代币的地址。
     * @param to The address to transfer ERC-20 tokens or ERC-721 token to.
     * @param to 将 ERC-20 代币或 ERC-721 代币转移到的地址。
     * @param amountOrId The amount of ERC-20 tokens or ID of ERC-721 tokens to transfer.
     * @param amountOrId 要转移的 ERC-20 代币的数量或 ERC-721 代币的 ID。
     */
    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)"))`.
     * @dev 只有当 `msg.sender` 是当前所有者、授权的 operator 或此 NFT 的批准地址时,才会抛出异常。如果 `_rom` 不是当前所有者,则抛出异常。如果 `_to` 是零地址,则抛出异常。如果 `tokenId` 不是有效的 NFT,则抛出异常。传输完成后,此函数检查 `to` 是否为智能合约(代码大小 > 0)。如果是,它会在 `to` 上调用 `onERC721Received`,如果返回值不是 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,则抛出异常。
     * @param from The current owner of the NFT
     * @param from NFT 的当前所有者
     * @param to The new owner
     * @param to 新所有者
     * @param tokenId The NFT to transfer
     * @param tokenId 要转移的 NFT
     * @param data Additional data with no specified format, sent in call to `to`
     * @param data 没有指定格式的附加数据,在调用 `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 "".
     * @dev 此函数的工作方式与带有额外数据参数的另一个函数相同,只是此函数将数据设置为“”。
     * @param from The current owner of the NFT
     * @param from NFT 的当前所有者
     * @param to The new owner
     * @param to 新所有者
     * @param tokenId The NFT to transfer
     * @param tokenId 要转移的 NFT
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external payable;

    /**
     * @dev Transfer ERC-20 tokens to an address.
     * @dev 将 ERC-20 代币转移到地址。
     * @param to The address to transfer ERC-20 tokens to.
     * @param to 将 ERC-20 代币转移到的地址。
     * @param amount The amount of ERC-20 tokens to transfer.
     * @param amount 要转移的 ERC-20 代币的数量。
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Retrieves the unit value associated with the token.
     * @dev 检索与代币关联的单位值。
     * @return The unit value.
     * @return 单位值。
     */
    function getUnit() external view returns (uint256);

    /**
     * @dev Converts ERC-721 token to ERC-20 tokens.
     * @dev 将 ERC-721 代币转换为 ERC-20 代币。
     * @param tokenId The unique identifier of the ERC-721 token.
     * @param tokenId ERC-721 代币的唯一标识符。
     */
    function erc721ToERC20(uint256 tokenId) external;

    /**
     * @dev Converts ERC-20 tokens to an ERC-721 token.
     * @dev  将 ERC-20 代币转换为 ERC-721 代币。
     * @param amount The amount of ERC-20 tokens to convert.
     * @param amount 要转换的 ERC-20 代币数量。
     */
    function erc20ToERC721(uint256 amount) external;
}


理由

不同代币类型的通用接口:

  • 引入统一接口以解决由独立的 ERC-20ERC-721 标准造成的碎片化。
  • 标准化诸如 transferFrom、mint 和 burn 之类的函数,使开发人员无需实现不同的逻辑即可与这两种代币类型进行交互。

转移功能:

  • 包括 transferFrom 函数,用于在地址之间无缝移动代币,因为它是 ERC-20ERC-721 标准的核心组件。

铸造和销毁:

  • 合并 mint 和 burn 函数以创建和销毁代币,这对于管理代币供应和生命周期至关重要。

余额和所有权查询:

  • 提供诸如 balanceOf 和 ownerOf 之类的函数来检索代币余额和所有权信息,这对于 ERC-20ERC-721 代币都至关重要。

兼容性和可扩展性:

  • 确保与现有 ERC-20ERC-721 实现的兼容性,最大限度地减少过渡期间的破坏。
  • 允许使用其他函数和事件进行扩展,以实现未来的增强。

安全注意事项:

  • 实施相关机制以防止诸如重入攻击和溢出之类的常见问题,从而确保统一接口的安全性和稳健性。

向后兼容性

提出的本提案由于 ERC-20ERC-721 标准使用的不同余额查询机制,因此在向后兼容性方面提出了挑战。ERC-20 采用 balanceOf 来检查帐户的代币余额,而 ERC-721 使用 balanceOf 来查询帐户拥有的代币数量。为了协调这些差异,ERC 必须考虑提供满足每个标准的两个单独的函数,或者采用更通用的方法。

兼容性要点

主要的兼容性要点在于 ERC-20 的 balanceOf 和 ERC-721 的 balanceOf 功能之间的差异。习惯于每个标准中特定余额查询方法的开发人员在过渡到此提案时可能会面临挑战。

建议的解决方案

双重余额查询函数:

引入两个不同的函数 erc20BalanceOferc721TotalSupply,以分别与 ERC-20ERC-721 的约定保持一致。开发人员可以根据他们使用的代币类型选择函数。

安全注意事项

  • 由于本提案的双重性质,可能会出现协议解释上的潜在差异,因此在开发过程中需要仔细考虑。
  • 建议进行全面的安全审核,尤其是在用户进行模式转换期间,以确保用户资产的安全。

版权

版权和相关权利已通过 CC0 放弃。

Citation

Please cite this document as:

0xZeus1111 (@0xZeus1111), Nvuwa (@Nvuwa), "ERC-7629: ERC-20/ERC-721 统一代币接口 [DRAFT]," Ethereum Improvement Proposals, no. 7629, February 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7629.