Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-725: 通用的数据key/value存储和执行

用于具有可附加数据key/value存储的基于智能合约的账户的接口

Authors Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka)
Created 2017-10-02
Discussion Link https://ethereum-magicians.org/t/discussion-for-eip725/12158
Requires EIP-165, EIP-173

摘要

以下描述了两个标准,它们允许在智能合约中进行通用数据存储,并通过智能合约进行通用执行。 这些标准可以单独使用或结合使用,并可以用作智能合约账户、可升级元数据和其他方式的构建块。

动机

最初的动机是需要创建一个足够灵活且可长期使用的智能合约帐户系统,同时也要有足够的定义以进行标准化。 它们是一组通用的两个标准化构建块,可用于所有形式的智能合约。

此标准包含两个子标准:通用数据key/value存储 (ERC725Y) 和通用执行函数 (ERC725X)。 这两者结合使用可实现非常灵活和持久的帐户系统。ERC725 的帐户版本在 LSP0-ERC725Account 下进行了标准化。

这些标准(ERC725 X 和 Y)也可以单独使用,因为 ERC725Y 可用于增强 NFT 和 Token 元数据或其他类型的智能合约。 ERC725X 允许通过智能合约进行通用执行,充当帐户或参与者。

规范

所有权

该合约由单个所有者控制。 所有者可以是智能合约或外部帐户。 此标准需要 ERC-173 并且应该实现以下功能:

  • owner() view
  • transferOwnership(address newOwner)

以及事件:

  • OwnershipTransferred(address indexed previousOwner, address indexed newOwner)

ERC725X

根据 ERC-165ERC725X 接口 ID:0x7545acac

实现 ERC725X 标准的智能合约必须实现 ERC-165 supportsInterface(..) 函数,并且必须支持 ERC165ERC725X 接口 ID。

ERC725X 方法

实现 ERC725X 标准的智能合约应该实现以下列出的所有函数:

execute

function execute(uint256 operationType, address target, uint256 value, bytes memory data) external payable returns(bytes memory)

函数选择器:0x44c028fe

在任何其他智能合约或地址上执行调用,转移区块链原生代币,或部署新的智能合约。

参数:

  • operationType:用于执行的操作类型。
  • target:要调用的智能合约或地址。 如果创建合约(操作类型 1 和 2),则 target 将不使用。
  • value:要转移的本地代币数量(以 Wei 为单位)。
  • data:调用数据,或要部署的合约的创建字节码。

要求:

  • 必须仅由合约的当前所有者调用。
  • 当执行或合约创建失败时,必须恢复。
  • 在使用 CREATECREATE2 创建合约时(操作类型 1 和 2),target 应该是 address(0)。
  • STATICCALLDELEGATECALL 的情况下(操作类型 3 和 4),value 应该是零。

返回值: bytes,被调用函数返回的数据,或已部署合约的地址(操作类型 1 和 2)。

触发事件: ContractCreated, Executed

可能存在以下 operationType

  • 0 代表 CALL
  • 1 代表 CREATE
  • 2 代表 CREATE2
  • 3 代表 STATICCALL
  • 4 代表 DELEGATECALL - 注意 这是一个潜在的危险操作类型

将来可能会添加其他操作类型。

data 参数

  • 对于 CALLSTATICCALLDELEGATECALL 操作类型,数据字段可以是随机字节或abi编码的函数调用。

  • 对于 CREATE 操作类型,data 字段是要部署的合约的创建字节码,附加了构造函数参数(abi编码)。

  • 对于 CREATE2 操作类型,data 字段是要部署的合约的创建字节码,附加了:

    1. 构造函数参数(abi编码)
    2. 一个 bytes32 salt。
data = <contract-creation-code> + <abi-encoded-constructor-arguments> + <bytes32-salt>

有关更多信息,请参见EIP-1014: Skinny CREATE2

executeBatch

function executeBatch(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes[] memory datas) external payable returns(bytes[] memory)

函数选择器:0x31858452

在一批智能合约上执行调用,转移区块链原生代币,或部署新的智能合约。

参数:

  • operationsType:用于执行的操作类型列表。
  • targets:要调用的地址列表。 如果创建合约(操作类型 1 和 2),则 targets 将不使用。
  • values:要转移的本地令牌金额列表(以 Wei 为单位)。
  • datas:调用数据列表,或要部署的合约的创建字节码。

要求:

  • 参数数组必须具有相同的长度。
  • 必须仅由合约的当前所有者调用。
  • 当执行或合约创建失败时,必须恢复。
  • 在使用 CREATECREATE2 创建合约时(操作类型 1 和 2),target 应该是 address(0)。
  • STATICCALLDELEGATECALL 的情况下(操作类型 3 和 4),value 应该是零。

返回值: bytes[],被调用函数返回的数据的数组列表,或已部署合约的地址(操作类型 1 和 2)。

触发事件: 每次调用迭代时触发 ContractCreated, Executed

ERC725X 事件

Executed

event Executed(uint256 indexed operationType, address indexed target, uint256 indexed value, bytes4 data);

execute 使用 operationType 034 创建新调用时,必须被触发。

ContractCreated

event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value, bytes32 salt);

execute 使用 operationType 12 创建新合约时,必须被触发。


ERC725Y

根据 ERC-165ERC725Y 接口 ID:0x629aa694

实现 ERC725Y 标准的智能合约必须实现 ERC-165 supportsInterface(..) 函数,并且必须支持 ERC165ERC725Y 接口 ID。

ERC725Y 方法

实现 ERC725Y 标准的智能合约必须实现以下列出的所有函数:

getData

function getData(bytes32 dataKey) external view returns(bytes memory)

函数选择器:0x54f6127f

获取给定数据key设置的数据。

参数:

  • dataKey:要检索其值的数据key。

返回值: bytes,请求的数据key的数据。

getDataBatch

function getDataBatch(bytes32[] memory dataKeys) external view returns(bytes[] memory)

函数选择器:0xdedff9c6

获取多个给定数据key处的数据数组。

参数:

  • dataKeys:要检索其值的数据key。

返回值: bytes[],请求的数据key的数据值数组。

setData

function setData(bytes32 dataKey, bytes memory dataValue) external

函数选择器:0x7f23690c

在存储中为单个数据key设置数据(作为字节)。

参数:

  • dataKey:要设置其值的数据key。
  • dataValue:要存储的数据。

要求:

  • 必须仅由合约的当前所有者调用。

触发事件: DataChanged

setDataBatch

function setDataBatch(bytes32[] memory dataKeys, bytes[] memory dataValues) external

函数选择器:0x97902421

在多个数据key处设置数据数组。 必须仅由合约的当前所有者调用。

参数:

  • dataKeys:要设置其值的数据key。
  • dataValues:要设置的字节数组。

要求:

  • 数组参数必须具有相同的长度。
  • 必须仅由合约的当前所有者调用。

触发事件: DataChanged

ERC725Y 事件

DataChanged

event DataChanged(bytes32 indexed dataKey, bytes dataValue)

当成功设置数据key时,必须触发。

ERC725Y 数据 keys

数据 keys 是通过 getData() 检索值的方式。 这些 bytes32 值可以自由选择,也可以由标准定义。 定义数据 keys 的常用方法是单词的哈希,例如 keccak256('ERCXXXMyNewKeyType'),其结果为:0x6935a24ea384927f250ee0b954ed498cd9203fc5d2bf95c735e52e6ca675e047

LSP2-ERC725JSONSchema 标准是更明确的 ERC725Y 数据key标准,它定义了key类型和值类型,以及它们的编码和解码。

理由

选择使用值存储数据 keys 的通用方法是为了允许随时间推移进行升级。 存储的数据值可以随时间更改。 然后,其他智能合约协议可以以新的方式解释这些数据,并对来自 ERC725 智能合约的交互做出不同的反应。

存储在 ERC725Y 智能合约中的数据不仅可以由链下应用程序读取/写入,还可以由其他智能合约读取/写入。 使用函数重载来允许检索单个和多个 keys,以使两种用例的 gas 成本保持最低。

向后兼容性

自 2018/19 年以来的所有 ERC725v2 合约都应与当前版本的标准兼容。 主要更改了接口 ID 和事件参数,同时添加了 getData(bytes32[])setData(bytes32[], bytes[]) 作为一次设置/获取多个 keys 的有效方法。 同样适用于执行,因为 execute(..[]) 已添加作为批量调用的一种有效方式。

从 2023 年起,从 ERC-725(包括 ERC725-XERC725-Y)中删除了重载。 这是因为,虽然 Solidity 中容纳了重载,但大多数区块链语言并不广泛支持它。 为了使标准与语言无关,决定从重载转换为简单地将术语“Batch”附加到接受数组作为参数的函数。

参考实现

参考实现可以在 ERC725.sol 中找到。

安全注意事项

此合约允许通用执行,因此需要特别注意以防止重入攻击和其他形式的调用链攻击。

当对 delegatecall 使用操作类型 4 时,重要的是要考虑到被调用的合约可以随意更改调用合约的状态,还可以更改所有者变量和 ERC725Y 数据存储条目。 此外,可以调用 selfdestruct 和其他有害的状态更改操作。

Solidity 接口

// SPDX-License-Identifier: CC0-1.0

pragma solidity >=0.5.0 <0.7.0;

// ERC165 identifier: `0x7545acac`
interface IERC725X  /* is ERC165, ERC173 */ {

    event Executed(uint256 indexed operationType, address indexed target, uint256 indexed  value, bytes4 data);
    event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value, bytes32 salt);


    function execute(uint256 operationType, address target, uint256 value, bytes memory data) external payable returns(bytes memory);

    function executeBatch(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes memory datas) external payable returns(bytes[] memory);
}

// ERC165 identifier: `0x629aa694`
interface IERC725Y /* is ERC165, ERC173 */ {
    
    event DataChanged(bytes32 indexed dataKey, bytes dataValue);

    function getData(bytes32 dataKey) external view returns(bytes memory);
    function getDataBatch(bytes32[] memory dataKeys) external view returns(bytes[] memory);

    function setData(bytes32 dataKey, bytes memory dataValue) external;
    function setDataBatch(bytes32[] memory dataKeys, bytes[] memory dataValues) external;
}
interface IERC725 /* is IERC725X, IERC725Y */ {
}

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka), "ERC-725: 通用的数据key/value存储和执行 [DRAFT]," Ethereum Improvement Proposals, no. 725, October 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-725.