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 |
Table of Contents
摘要
以下描述了两个标准,它们允许在智能合约中进行通用数据存储,并通过智能合约进行通用执行。 这些标准可以单独使用或结合使用,并可以用作智能合约账户、可升级元数据和其他方式的构建块。
动机
最初的动机是需要创建一个足够灵活且可长期使用的智能合约帐户系统,同时也要有足够的定义以进行标准化。 它们是一组通用的两个标准化构建块,可用于所有形式的智能合约。
此标准包含两个子标准:通用数据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-165 的 ERC725X
接口 ID:0x7545acac
。
实现 ERC725X
标准的智能合约必须实现 ERC-165 supportsInterface(..)
函数,并且必须支持 ERC165
和 ERC725X
接口 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
:调用数据,或要部署的合约的创建字节码。
要求:
- 必须仅由合约的当前所有者调用。
- 当执行或合约创建失败时,必须恢复。
- 在使用
CREATE
和CREATE2
创建合约时(操作类型 1 和 2),target
应该是 address(0)。 - 在
STATICCALL
或DELEGATECALL
的情况下(操作类型 3 和 4),value
应该是零。
返回值: bytes
,被调用函数返回的数据,或已部署合约的地址(操作类型 1 和 2)。
触发事件: ContractCreated, Executed
可能存在以下 operationType
:
0
代表CALL
1
代表CREATE
2
代表CREATE2
3
代表STATICCALL
4
代表DELEGATECALL
- 注意 这是一个潜在的危险操作类型
将来可能会添加其他操作类型。
data 参数
-
对于
CALL
、STATICCALL
和DELEGATECALL
操作类型,数据字段可以是随机字节或abi编码的函数调用。 -
对于
CREATE
操作类型,data
字段是要部署的合约的创建字节码,附加了构造函数参数(abi编码)。 -
对于
CREATE2
操作类型,data
字段是要部署的合约的创建字节码,附加了:- 构造函数参数(abi编码)
- 一个
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
:调用数据列表,或要部署的合约的创建字节码。
要求:
- 参数数组必须具有相同的长度。
- 必须仅由合约的当前所有者调用。
- 当执行或合约创建失败时,必须恢复。
- 在使用
CREATE
和CREATE2
创建合约时(操作类型 1 和 2),target
应该是 address(0)。 - 在
STATICCALL
或DELEGATECALL
的情况下(操作类型 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
0
、3
、4
创建新调用时,必须被触发。
ContractCreated
event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value, bytes32 salt);
当 execute
使用 operationType
1
、2
创建新合约时,必须被触发。
ERC725Y
根据 ERC-165 的 ERC725Y
接口 ID:0x629aa694
。
实现 ERC725Y
标准的智能合约必须实现 ERC-165 supportsInterface(..)
函数,并且必须支持 ERC165
和 ERC725Y
接口 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-X
和 ERC725-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.