diff --git a/ERCS/erc-725.md b/ERCS/erc-725.md index 64d68734b89..94d8387daa9 100644 --- a/ERCS/erc-725.md +++ b/ERCS/erc-725.md @@ -4,7 +4,7 @@ title: General data key/value store and execution description: An interface for a smart contract based account with attachable data key/value store author: Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka) discussions-to: https://ethereum-magicians.org/t/discussion-for-eip725/12158 -status: Draft +status: Review type: Standards Track category: ERC created: 2017-10-02 @@ -13,15 +13,15 @@ requires: 165, 173 ## Abstract -The following describes two standards that allow for a generic data storage in a smart contract and a generic execution through a smart contract. These can be used separately or in conjunction and can serve as building blocks for smart contract accounts, upgradable metadata, and other means. +The following describes two standards that allow for generic data storage in a smart contract and a generic execution through a smart contract. These can be used separately or in conjunction and can serve as building blocks for smart contract accounts, upgradable metadata, and other means. ## Motivation The initial motivation came out of the need to create a smart contract account system that's flexible enough to be viable long-term but also defined enough to be standardized. They are a generic set of two standardized building blocks to be used in all forms of smart contracts. -This standard consists of two sub-standards, a generic data key/value store (`ERC725Y`) and a generic execute function (`ERC725X`). Both of these in combination allow for a very flexible and long-lasting account system. The account version of `ERC725` is standardized under `LSP0-ERC725Account`. +This standard consists of two sub-standards, a generic data key/value store (Y) and a generic execute function (X). Both of these in combination allow for a very flexible and long-lasting account system. -These standards (`ERC725` X and Y) can also be used separately as `ERC725Y` can be used to enhance NFTs and Token metadata or other types of smart contracts. `ERC725X` allows for a generic execution through a smart contract, functioning as an account or actor. +These standards (X and Y) can also be used separately to enhance NFTs and Token metadata or other types of smart contracts. X allows for a generic execution through a smart contract, functioning as an account or actor. ## Specification @@ -37,270 +37,249 @@ And the event: - `OwnershipTransferred(address indexed previousOwner, address indexed newOwner)` ---- - -### `ERC725X` +### Y -**`ERC725X`** interface id according to [ERC-165](./eip-165.md): `0x7545acac`. +**Y** interface id according to [ERC-165]: `0x629aa694`. -Smart contracts implementing the `ERC725X` standard MUST implement the [ERC-165](./eip-165.md) `supportsInterface(..)` function and MUST support the `ERC165` and `ERC725X` interface ids. +Smart contracts implementing the ERC-725 Y standard MUST implement the [ERC-165] `supportsInterface(..)` function and MUST support the ERC-165 and Y interface ids. -### `ERC725X` Methods +### Methods -Smart contracts implementing the `ERC725X` standard SHOULD implement all of the functions listed below: +Smart contracts implementing the Y standard MUST implement all of the functions listed below: -#### execute +#### `getData` ```solidity -function execute(uint256 operationType, address target, uint256 value, bytes memory data) external payable returns(bytes memory) +function getData(bytes32 dataKey) external view returns(bytes memory) ``` -Function Selector: `0x44c028fe` - -Executes a call on any other smart contracts or address, transfers the blockchains native token, or deploys a new smart contract. +Function Selector: `0x54f6127f` +Gets the data set for the given data key. _Parameters:_ -- `operationType`: the operation type used to execute. -- `target`: the smart contract or address to call. `target` will be unused if a contract is created (operation types 1 and 2). -- `value`: the amount of native tokens to transfer (in Wei). -- `data`: the call data, or the creation bytecode of the contract to deploy. +- `dataKey`: the data key which value to retrieve. +_Returns:_ `bytes` , The data for the requested data key. -_Requirements:_ +#### `getDataBatch` -- MUST only be called by the current owner of the contract. -- MUST revert when the execution or the contract creation fails. -- `target` SHOULD be address(0) in case of contract creation with `CREATE` and `CREATE2` (operation types 1 and 2). -- `value` SHOULD be zero in case of `STATICCALL` or `DELEGATECALL` (operation types 3 and 4). +```solidity +function getDataBatch(bytes32[] memory dataKeys) external view returns(bytes[] memory) +``` +Function Selector: `0xdedff9c6` -_Returns:_ `bytes` , the returned data of the called function, or the address of the contract deployed (operation types 1 and 2). +Gets array of data at multiple given data keys. -**Triggers Event:** [ContractCreated](#contractcreated), [Executed](#executed) +_Parameters:_ -The following `operationType` COULD exist: +- `dataKeys`: the data keys which values to retrieve. -- `0` for `CALL` -- `1` for `CREATE` -- `2` for `CREATE2` -- `3` for `STATICCALL` -- `4` for `DELEGATECALL` - **NOTE** This is a potentially dangerous operation type +_Returns:_ `bytes[]` , array of data values for the requested data keys. -Others may be added in the future. +#### `setData` -#### data parameter +```solidity +function setData(bytes32 dataKey, bytes memory dataValue) external payable +``` -- For operationType, `CALL`, `STATICCALL` and `DELEGATECALL` the data field can be random bytes or an abi-encoded function call. +Function Selector: `0x7f23690c` -- For operationType, `CREATE` the `data` field is the creation bytecode of the contract to deploy appended with the constructor argument(s) abi-encoded. +Sets data as bytes in the storage for a single data key. -- For operationType, `CREATE2` the `data` field is the creation bytecode of the contract to deploy appended with: - 1. the constructor argument(s) abi-encoded - 2. a `bytes32` salt. +_Parameters:_ -``` -data = + + -``` +- `dataKey`: the data key which value to set. +- `dataValue`: the data to store. + +_Requirements:_ -> See [EIP-1014: Skinny CREATE2](./eip-1014.md) for more information. +- MUST only be called by the current owner of the contract. + +**Triggers Event:** [DataChanged](#datachanged) -#### executeBatch +#### `setDataBatch` ```solidity -function executeBatch(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes[] memory datas) external payable returns(bytes[] memory) +function setDataBatch(bytes32[] memory dataKeys, bytes[] memory dataValues) external payable ``` -Function Selector: `0x31858452` +Function Selector: `0x97902421` -Executes a batch of calls on any other smart contracts, transfers the blockchain native token, or deploys a new smart contract. +Sets array of data at multiple data keys. MUST only be called by the current owner of the contract. _Parameters:_ -- `operationsType`: the list of operations type used to execute. -- `targets`: the list of addresses to call. `targets` will be unused if a contract is created (operation types 1 and 2). -- `values`: the list of native token amounts to transfer (in Wei). -- `datas`: the list of call data, or the creation bytecode of the contract to deploy. +- `dataKeys`: the data keys which values to set. +- `dataValues`: the array of bytes to set. _Requirements:_ -- Parameters array MUST have the same length. +- Array parameters MUST have the same length. - MUST only be called by the current owner of the contract. -- MUST revert when the execution or the contract creation fails. -- `target` SHOULD be address(0) in case of contract creation with `CREATE` and `CREATE2` (operation types 1 and 2). -- `value` SHOULD be zero in case of `STATICCALL` or `DELEGATECALL` (operation types 3 and 4). - -_Returns:_ `bytes[]` , array list of returned data of the called function, or the address(es) of the contract deployed (operation types 1 and 2). -**Triggers Event:** [ContractCreated](#contractcreated), [Executed](#executed) on each call iteration +**Triggers Event:** [DataChanged](#datachanged) -### `ERC725X` Events +### Events -#### Executed +#### `DataChanged` ```solidity -event Executed(uint256 indexed operationType, address indexed target, uint256 indexed value, bytes4 data); +event DataChanged(bytes32 indexed dataKey, bytes dataValue) ``` -MUST be triggered when `execute` creates a new call using the `operationType` `0`, `3`, `4`. - -#### ContractCreated +MUST be triggered when a data key is successfully set. -```solidity -event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value, bytes32 salt); -``` +### Y Data keys -MUST be triggered when `execute` creates a new contract using the `operationType` `1`, `2`. +Data keys, are the way to retrieve values via `getData()`. These `bytes32` values can be freely chosen, or defined by a standard. +A common way to define data keys is the hash of a word, e.g. `keccak256('ERCXXXMyNewKeyType')` which results in: `0x6935a24ea384927f250ee0b954ed498cd9203fc5d2bf95c735e52e6ca675e047` ---- +The LSP2 ERC-725 JSON Schema standard is a more explicit ERC-725 Y data key standard, that defines key types and value types, and their encoding and decoding. -### `ERC725Y` +### X -**`ERC725Y`** interface id according to [ERC-165](./eip-165.md): `0x629aa694`. +**X** interface id according to [ERC-165]: `0x7545acac`. -Smart contracts implementing the `ERC725Y` standard MUST implement the [ERC-165](./eip-165.md) `supportsInterface(..)` function and MUST support the `ERC165` and `ERC725Y` interface ids. +Smart contracts implementing the X standard MUST implement the [ERC-165] `supportsInterface(..)` function and MUST support the ERC-165 and X interface ids. -### `ERC725Y` Methods +### Methods -Smart contracts implementing the `ERC725Y` standard MUST implement all of the functions listed below: +Smart contracts implementing the X standard SHOULD implement all of the functions listed below: -#### getData +#### `execute` ```solidity -function getData(bytes32 dataKey) external view returns(bytes memory) +function execute(uint256 operationType, address target, uint256 value, bytes memory data) external payable returns(bytes memory) ``` -Function Selector: `0x54f6127f` +Function Selector: `0x44c028fe` -Gets the data set for the given data key. +Executes a call on any other smart contracts or address, transfers the blockchains native token, or deploys a new smart contract. _Parameters:_ -- `dataKey`: the data key which value to retrieve. - -_Returns:_ `bytes` , The data for the requested data key. - -#### getDataBatch - -```solidity -function getDataBatch(bytes32[] memory dataKeys) external view returns(bytes[] memory) -``` - -Function Selector: `0xdedff9c6` +- `operationType`: the operation type used to execute. +- `target`: the smart contract or address to call. `target` will be unused if a contract is created (operation types 1 and 2). +- `value`: the amount of native tokens to transfer (in Wei). +- `data`: the call data, or the creation bytecode of the contract to deploy. -Gets array of data at multiple given data keys. +_Requirements:_ -_Parameters:_ +- MUST only be called by the current owner of the contract. +- MUST revert when the execution or the contract creation fails. +- `target` SHOULD be address(0) in case of contract creation with `CREATE` and `CREATE2` (operation types 1 and 2). +- `value` SHOULD be zero in case of `STATICCALL` or `DELEGATECALL` (operation types 3 and 4). -- `dataKeys`: the data keys which values to retrieve. +_Returns:_ `bytes` , the returned data of the called function, or the address of the contract deployed (operation types 1 and 2). -_Returns:_ `bytes[]` , array of data values for the requested data keys. +**Triggers Event:** [ContractCreated](#contractcreated), [Executed](#executed) -#### setData +The following `operationType` COULD exist: -```solidity -function setData(bytes32 dataKey, bytes memory dataValue) external -``` +- `0` for `CALL` +- `1` for `CREATE` +- `2` for `CREATE2` +- `3` for `STATICCALL` +- `4` for `DELEGATECALL` - **NOTE** This is a potentially dangerous operation type -Function Selector: `0x7f23690c` +Others may be added in the future. -Sets data as bytes in the storage for a single data key. +#### data parameter -_Parameters:_ +- For operationType, `CALL`, `STATICCALL` and `DELEGATECALL` the data field can be random bytes or an abi-encoded function call. -- `dataKey`: the data key which value to set. -- `dataValue`: the data to store. +- For operationType, `CREATE` the `data` field is the creation bytecode of the contract to deploy appended with the constructor argument(s) abi-encoded. -_Requirements:_ +- For operationType, `CREATE2` the `data` field is the creation bytecode of the contract to deploy appended with: + 1. the constructor argument(s) abi-encoded + 2. a `bytes32` salt. -- MUST only be called by the current owner of the contract. +``` +data = + + +``` -**Triggers Event:** [DataChanged](#datachanged) +> See [EIP-1014](./eip-1014.md): Skinny CREATE2 for more information. -#### setDataBatch +#### `executeBatch` ```solidity -function setDataBatch(bytes32[] memory dataKeys, bytes[] memory dataValues) external +function executeBatch(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes[] memory datas) external payable returns(bytes[] memory) ``` -Function Selector: `0x97902421` +Function Selector: `0x31858452` -Sets array of data at multiple data keys. MUST only be called by the current owner of the contract. +Executes a batch of calls on any other smart contracts, transfers the blockchain native token, or deploys a new smart contract. +MUST only be called by the current owner of the contract. +MUST revert when one execution at least fails. _Parameters:_ -- `dataKeys`: the data keys which values to set. -- `dataValues`: the array of bytes to set. +- `operationsType`: the list of operations type used to execute. +- `targets`: the list of addresses to call. `targets` will be unused if a contract is created (operation types 1 and 2). +- `values`: the list of native token amounts to transfer (in Wei). +- `datas`: the list of call data, or the creation bytecode of the contract to deploy. _Requirements:_ -- Array parameters MUST have the same length. +- Parameters array MUST have the same length. - MUST only be called by the current owner of the contract. +- MUST revert when the execution or the contract creation fails. +- `target` SHOULD be address(0) in case of contract creation with `CREATE` and `CREATE2` (operation types 1 and 2). +- `value` SHOULD be zero in case of `STATICCALL` or `DELEGATECALL` (operation types 3 and 4). -**Triggers Event:** [DataChanged](#datachanged) +_Returns:_ `bytes[]` , array list of returned data of the called function, or the address(es) of the contract deployed (operation types 1 and 2). -### `ERC725Y` Events +**Triggers Event:** [ContractCreated](#contractcreated), [Executed](#executed) on each call iteration + +### Events -#### DataChanged +#### `Executed` ```solidity -event DataChanged(bytes32 indexed dataKey, bytes dataValue) +event Executed(uint256 indexed operationType, address indexed target, uint256 value, bytes4 indexed selector); ``` -MUST be triggered when a data key was successfully set. +MUST be triggered when `execute` creates a new call using the `operationType` `0`, `3`, `4`. -### `ERC725Y` Data keys +#### `ContractCreated` -Data keys, are the way to retrieve values via `getData()`. These `bytes32` values can be freely chosen, or defined by a standard. -A common way to define data keys is the hash of a word, e.g. `keccak256('ERCXXXMyNewKeyType')` which results in: `0x6935a24ea384927f250ee0b954ed498cd9203fc5d2bf95c735e52e6ca675e047` +```solidity +event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 value, bytes32 indexed salt); +``` -The `LSP2-ERC725JSONSchema` standard is a more explicit `ERC725Y` data key standard, that defines key types and value types, and their encoding and decoding. +MUST be triggered when `execute` creates a new contract using the `operationType` `1`, `2`. ## Rationale -The generic way of storing data keys with values was chosen to allow upgradability over time. Stored data values can be changed over time. Other smart contract protocols can then interpret this data in new ways and react to interactions from a `ERC725` smart contract differently. +The generic way of storing data keys with values was chosen to allow upgradability over time. Stored data values can be changed over time. Other smart contract protocols can then interpret this data in new ways and react to interactions from an ERC-725 smart contract differently. -The data stored in an `ERC725Y` smart contract is not only readable/writable by off-chain applications, but also by other smart contracts. Function overloading was used to allow for the retrievable of single and multiple keys, to keep gas costs minimal for both use cases. +The data stored in a Y smart contract is not only readable/writable by off-chain applications, but also by other smart contracts. Function overloading was used to allow for the retrievable for single and multiple keys, to keep gas costs minimal for both use cases. ## Backwards Compatibility -All contracts since `ERC725v2` from 2018/19 should be compatible with the current version of the standard. Mainly interface ID and Event parameters have changed, while `getData(bytes32[])` and `setData(bytes32[], bytes[])` was added as an efficient way to set/get multiple keys at once. The same applies to execution, as `execute(..[])` was added as an efficient way to batch calls. - -From 2023 onward, overloading was removed from `ERC-725` (including `ERC725-X` and `ERC725-Y`). This is because, while overloading is accommodated in Solidity, it isn't broadly supported across most blockchain languages. In order to make the standard language-independent, it was decided to shift from overloading to simply attach the term "Batch" to the functions that accept an array as parameters. +All contracts following previous versions of this standard (from 2018/19) should be compatible with the current version of the standard. Mainly interface ID and event parameters have changed, while `getDataBatch(bytes32[])` and `setDataBatch(bytes32[], bytes[])` were added as an efficient way to set/get multiple keys at once. The same applies to execution, as `executeBatch(..[])` was added as an efficient way to batch calls. ## Reference Implementation -Reference implementations can be found in [`ERC725.sol`](../assets/eip-725/ERC725.sol). +Reference implementations can be found at the `ERC725Alliance` Github. ## Security Considerations -This contract allows generic executions, therefore special care needs to be taken to prevent re-entrancy attacks and other forms of call chain attacks. +This contract allows generic executions, therefore special care should be taken to prevent re-entrancy attacks and other forms of call chain attacks. -When using the operation type `4` for `delegatecall`, it is important to consider that the called contracts can alter the state of the calling contract and also change owner variables and `ERC725Y` data storage entries at will. Additionally calls to `selfdestruct` are possible and other harmful state-changing operations. +When using the operation type `4` for `delegatecall`, it is important to consider that the called contracts can alter the state of the calling contract and also change owner variables and ERC-725 Y data storage entries at will. Additionally calls to `selfdestruct` are possible and other harmful state-changing operations. ### Solidity Interfaces ```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 */ { - +interface IERC725Y /* is ERC-165, ERC-173 */ { event DataChanged(bytes32 indexed dataKey, bytes dataValue); function getData(bytes32 dataKey) external view returns(bytes memory); @@ -309,10 +288,25 @@ interface IERC725Y /* is ERC165, ERC173 */ { function setData(bytes32 dataKey, bytes memory dataValue) external; function setDataBatch(bytes32[] memory dataKeys, bytes[] memory dataValues) external; } + +interface IERC725X /* is ERC-165, ERC-173 */ { + event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 value, bytes32 indexed salt); + event Executed(uint256 indexed operationType, address indexed target, uint256 value, bytes4 indexed selector); + + 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); +} + interface IERC725 /* is IERC725X, IERC725Y */ { + } + ``` + ## Copyright -Copyright and related rights waived via [CC0](../LICENSE.md). +Copyright and related rights waived via CC0. + +[ERC-165]: ./eip-165