Alert Source Discuss
⚠️ Review Standards Track: ERC

ERC-7656: 通用的合约链接服务

定义一个工厂,用于链接到任何合约类型的通用服务,包括 ERC-4337 账户和 NFT

Authors Francesco Sullo (@sullof)
Created 2024-03-15
Requires EIP-20, EIP-165, EIP-721, EIP-1155, EIP-1167, EIP-4337, EIP-6551

摘要

本提案定义了一个工厂,能够部署链接到特定合约的通用服务,例如 ERC-4337 账户或 ERC-721 代币(NFT)。这些链接的服务扩展了目标合约的功能,在合约或 NFT 所有者的所有权下运行,而无需修改原始合约的代码。作为次要效果,本提案有助于减少需要更改基本标准的 ERC 的扩散。

动机

现有的标准,如 ERC-6551 成功地将智能账户绑定到 NFT,允许注册表部署由特定代币 ID 拥有的账户。然而,这些标准有两个主要限制:

  1. 它们通常要求已部署的合约实现特定的接口,用于处理资产和执行事务,从而实际上要求已部署的合约必须作为账户运行。
  2. 它们仅限于 NFT,而许多其他合约类型(特别是 ERC-4337 账户)可以从类似的链接机制中受益,以扩展其功能。

本 ERC 提出了一个更通用的工厂规范,该规范能够部署指向任何合约的代理,以增强相关合约的功能,无论是 NFT 还是账户合约。

主要优点

  • 通用可链接性:使服务能够链接到任何兼容的合约类型,而不仅仅是 NFT,从而创建统一的合约扩展方法。

  • 非侵入式增强:服务可以向现有智能账户添加功能,而无需修改底层合约,从而保持与钱包和索引器等基础设施的兼容性。

  • 向后兼容性:保持与现有 token-bound 账户标准 (ERC-6551) 的兼容性,同时将功能扩展到新的用例。

  • 灵活的实现mode 参数支持不同的链接类型(带或不带代币 ID),同时确保一致的确定性寻址。

  • 减少标准扩散:通过提供可应用于现有标准的扩展机制来减少对新的专用 ERC 的需求,从而简化生态系统。

ERC-4337 智能账户的用例

  1. 社交恢复服务:部署链接到现有 ERC-4337 钱包的社交恢复机制,如果凭据丢失,可以恢复访问权限,而无需钱包以原生方式实现恢复功能。

  2. 可定制的权限系统:向账户添加精细的权限(限时访问、消费限额、多重签名批准),而无需从头开始重建账户。

  3. 账户抽象扩展:将批量交易、gas 赞助或会话密钥等高级功能实现为链接的服务,允许钱包有选择地采用这些功能。

  4. 身份和声誉服务:将可验证的凭据或声誉系统链接到账户,从而实现保护隐私的身份验证。

NFT 的用例

  1. 增强的代币效用:为 NFT 提供金融功能,如质押、借贷或收入分配。

  2. 动态元数据服务:使 NFT 元数据能够根据链上活动演变,而无需更改 NFT 本身。

  3. 部分所有权:通过链接的合约为高价值 NFT 实现部分所有权机制。

  4. 有条件访问控制:创建对 NFT 限制的内容或服务的限时或基于挑战的访问。

  5. 现实世界资产管理:通过链接处理合规性、法律文件、托管验证、转让限制和监管报告的服务,扩展 NFT 以表示和管理现实世界资产 (RWA),而无需为每个资产类别使用专门的 NFT 标准。

规范

本文档中的关键词“必须 (MUST)”、“禁止 (MUST NOT)”、“必需 (REQUIRED)”、“应该 (SHALL)”、“不应该 (SHALL NOT)”、“建议 (SHOULD)”、“不建议 (SHOULD NOT)”、“推荐 (RECOMMENDED)”、“不推荐 (NOT RECOMMENDED)”、“可以 (MAY)”和“可选 (OPTIONAL)”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。

IERC7656Factory 接口定义如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title ERC7656
 * @dev ERC165 接口 ID: 0x9e23230a
 * @notice 管理合约链接服务的创建
 */
interface IERC7656Factory {
  event Created(
    address contractAddress,
    address indexed implementation,
    bytes32 salt,
    uint256 chainId,
    bytes12 mode,
    address indexed linkedContract,
    uint256 indexed linkedId
  );

  error CreationFailed();

  function create(
    address implementation,
    bytes32 salt,
    uint256 chainId,
    bytes12 mode,
    address linkedContract,
    uint256 linkedId
  ) external returns (address);

  function compute(
    address implementation,
    bytes32 salt,
    uint256 chainId,
    bytes12 mode,
    address linkedContract,
    uint256 linkedId
  ) external view returns (address service);
}

链接模式

mode 参数用作应如何解释和利用链接合约的选择器。目前,ERC-7656 定义了两种标准模式:

bytes12 constant NO_LINKED_ID = 0x000000000000000000000001;
bytes12 constant LINKED_ID = 0x000000000000000000000000;
  • LINKED_ID 模式 (0x000000000000000000000000):用于将服务链接到需要代币/实体 ID 的 NFT 或任何合约。此模式确保与 ERC-6551 的兼容性,从而允许与现有 token-bound 账户系统无缝集成。

  • NO_LINKED_ID 模式 (0x000000000000000000000001):用于将服务链接到不需要 ID 参数的合约,例如 ERC-4337 账户。在这种情况下,linkedId 参数仍然存在于接口中以保持一致性,但如果未使用它来存储与服务相关的替代数据,则应将其设置为零。

mode 参数(为 bytes12)允许在这些初始模式之外进行未来的扩展,从而能够根据生态系统需求的发展实现更复杂的链接模式。

部署要求

任何 ERC7656Factory 实现都必须支持 IERC7656Factory 接口 ID (0x9e23230a)。

每个链接的服务必须部署为 ERC-1167 最小代理,将不可变的常量数据附加到字节码。已部署的字节码结构为:

ERC-1167 Header               (10 bytes)
<implementation (address)>    (20 bytes)
ERC-1167 Footer               (15 bytes)
<salt (bytes32)>              (32 bytes)
<chainId (uint256)>           (32 bytes)
<mode (bytes12)>              (12 bytes)
<linkedContract (address)>    (20 bytes)
<linkedId (uint256)>          (32 bytes)

链接的服务应该实现 IERC7656Service 接口:

// Interface ID: 0x7e110a1d
interface IERC7656Service {
  function linkedData() external view
    returns (uint256 chainId, bytes12 mode, address linkedContract, uint256 linkedId);
}

实现模式

在实现链接的服务时,开发人员应考虑以下模式:

  1. 所有权验证:服务应包括验证操作是否已获得链接合约或代币的当前所有者授权的机制。

  2. 特定于模式的逻辑:服务应根据 mode 参数实现条件逻辑,以适当地处理 NFT 链接和账户链接的场景。

  3. 跨链感知:服务应检查操作是否在 chainId 参数中指定的链上执行,以防止跨链重放攻击。

理由

ERC-7656 的设计受几个关键原则的指导,这些原则解决了当前合约扩展方法的局限性:

为什么是统一的 Factory?

ERC-7656 没有为 NFT 扩展和账户扩展创建单独的标准,而是采用了一种统一的 Factory 方法。这种设计选择源于认识到将服务链接到代币和将服务链接到账户之间的基本相似性 - 两者都涉及扩展功能,同时保持清晰的所有权关系。

Mode 参数设计

mode 参数使用 12 个字节而不是简单的布尔标志,因为 12 字节格式为超出最初两个(NFT 链接和账户链接)的未来链接模式保留了空间。例如,如果服务与 ERC-1155 代币相关联,但要求用户的余额超过 1000 个代币,则模式可以是 0x000000000000000000003e802,其中最低有效字节 0x02 是主要模式,其余部分是最小所需余额。同样,有人可以想到与 ERC-20 代币相关联的服务,该服务需要特定的余额,其中所需的余额可以放在 linkedId 字段中,并相应地指定 mode

确定性寻址

ERC-7656 遵循 ERC-6551 建立的确定性寻址模式,将不可变数据附加到合约字节码,而不是将其存储在合约存储中。这确保了:

  1. 链接的服务具有可预测的地址,可以在链下计算
  2. Factory 保持无状态,从而降低 gas 成本
  3. 链接的服务可以按需部署,甚至可以在部署之前引用

ERC-6551 的兼容性

LINKED_ID 模式 (0x000000000000000000000000) 保持与 ERC-6551 token-bound 账户的字节对字节兼容性。 这种有意的设计确保了为 ERC-6551 构建的应用程序可以以这种模式与 ERC-7656 服务无缝协作,而无需进行任何修改。

通用链接机制

与在链接的合约上强制执行特定接口或行为的标准不同,ERC-7656 仍然与链接服务的实现细节无关。这种有意的设计选择允许开发人员最大限度地灵活地创建专用服务,同时保持一致的部署和所有权模型。

向后兼容性

当与 LINKED_ID 模式 (0x000000000000000000000000) 一起使用时,ERC-7656 保持与 ERC-6551 的兼容性。这确保了支持 token-bound 账户的现有应用程序和基础设施可以继续运行而无需修改。

对于使用 NO_LINKED_ID 模式 (0x000000000000000000000001) 的合约,可能需要专门的接口,但核心 Factory 机制保持一致。

参考实现

有关 IERC7656Factory 的示例实现,请参见 ERC7656Factory.sol。为方便起见,参考实现将部署在主 mainnet 和选定的 testnet 上的 erc7656.eth

IERC7656Service 的实现示例:

contract LinkedService is IERC7656Service, EIP5313 {

  function linkedData(address service) public view returns (uint256, bytes12, address, uint256) {
    bytes memory encodedData = new bytes(0x60);
    // solhint-disable-next-line no-inline-assembly
    assembly {
    // 从上下文末尾复制 0x60 字节
      extcodecopy(service, add(encodedData, 0x20), 0x4d, 0x60)
    }

    uint256 chainId;
    bytes32 linkedContract;
    uint256 linkedId;

    // solhint-disable-next-line no-inline-assembly
    assembly {
      chainId := mload(add(encodedData, 0x20))
      linkedContract := mload(add(encodedData, 0x40))
      linkedId := mload(add(encodedData, 0x60))
    }

    bytes12 mode = bytes12(linkedContract);

    address extractedAddress = address(uint160(uint256(linkedContract)));
    return (chainId, mode, extractedAddress, linkedId);
  }

  function owner() public view virtual override returns (address) {
    (uint256 chainId, , address tokenContract_, uint256 tokenId_) = linkedData();
    if (chainId != block.chainid) return address(0);
    return IERC721(tokenContract_).ownerOf(tokenId_);
  }
}

安全考虑

所有权循环

链接到 NFT 的智能钱包,然后由同一钱包持有,可能会产生所有权循环,从而可能导致无法访问资产。实施者应包括防止或检测此类循环的保护措施。

欺诈预防

恶意卖方可以在最终确定销售之前更改或撤销服务权限。可以实施防止最后一刻更改的锁定机制,特别是对于与 ERC-7656 服务集成的 NFT 市场。

恶意实现

注册表无法在链接服务时强制执行合法的所有权。用户应在部署之前查看或审核实现。与 ERC-7656 集成的前端应用程序应在与未经验证的实现交互时显示警告。

可升级性风险

可升级的链接服务存在意外更改或资产盗取的风险。在需要可升级性时,应实施具有时间锁控制或多重签名治理的安全升级机制。

重入和跨合约攻击

与资产或外部协议交互的链接服务可能容易受到重入利用。实施者应遵循安全最佳实践,例如检查-效果-交互模式,并考虑重入保护。

模式特定的漏洞

以不同模式(LINKED_IDNO_LINKED_ID)运行的服务可能具有不同的安全要求。实现应验证操作是否适合服务的配置模式。

用户教育和网络钓鱼风险

即使有安全的合约,用户也可能成为伪装成合法服务的欺诈服务的受害者。与 ERC-7656 集成的应用程序应提供清晰的 UI 警告、验证工具和教育资源。

版权

根据 CC0 许可。

Citation

Please cite this document as:

Francesco Sullo (@sullof), "ERC-7656: 通用的合约链接服务 [DRAFT]," Ethereum Improvement Proposals, no. 7656, March 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7656.