Skip to content

Latest commit

 

History

History
324 lines (198 loc) · 12.5 KB

ERC-725.md

File metadata and controls

324 lines (198 loc) · 12.5 KB
eip title description author discussions-to status type category created requires
725
General data key/value store and execution
An interface for a smart contract based account with attachable data key/value store
Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka)
Review
Standards Track
ERC
2017-10-02
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 seperate or in conjunction and can serve as building blocks for smart contract accounts, upgradable meta data and other means.

Motivation

The initial motivation came out of the need to create a smart contract account system thats flexible enough to be viable long term, but also defined enough to be standardised. They are a generic set of two standardised 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 which in combination allow for a very flexible and long lasting account system. The account version of ERC725 is standardised under LSP0 ERC725Account.

These standards (ERC725 X and Y) can also be used separately to enhance NFTs and Token meta data or other types of smart contracts. ERC725X allows for a generic execution through a smart contract, functioning as an account or actor.

Specification

Ownership

This contract is controlled by a single owner. The owner can be a smart contract or an external account. This standard requires ERC173 and SHOULD implement the functions:

  • owner() view
  • transferOwnership(address newOwner)

And the event:

  • OwnershipTransferred(address indexed previousOwner, address indexed newOwner)

ERC725X

ERC725X interface id according to ERC165: 0x7545acac.

Smart contracts implementing the ERC725X standard MUST implement the ERC165 supportsInterface(..) function and MUST support the ERC165 and ERC725X interface ids.

Methods

Smart contracts implementing the ERC725X standard SHOULD implement all of the functions listed below:

execute

function execute(uint256 operationType, address target, uint256 value, bytes memory data) external payable 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.

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.

Requirements:

  • 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 , the returned data of the called function, or the address of the contract deployed (operation types 1 and 2).

Triggers Event: ContractCreated, Executed

The following operationType COULD exist:

  • 0 for CALL
  • 1 for CREATE
  • 2 for CREATE2
  • 3 for STATICCALL
  • 4 for DELEGATECALL - NOTE This is a potentially dangerous operation type

Others may be added in the future.

data parameter

  • For operationType, CALL, STATICCALL and DELEGATECALL the data field can be random bytes or an abi-encoded function call.

  • For operationType, CREATE the data field is the creation bytecode of the contract to deploy appended with the constructor argument(s) abi-encoded.

  • 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.
data = <contract-creation-code> + <abi-encoded-constructor-arguments> + <bytes32-salt>

See EIP-1014: Skinny CREATE2 for more information.

executeBatch

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

Function Selector: 0x31858452

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:

  • 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:

  • 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).

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, Executed on each call iteration

Events

Executed

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

MUST be triggered when execute creates a new call using the operationType 0, 3, 4.

ContractCreated

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

MUST be triggered when execute creates a new contract using the operationType 1, 2.


ERC725Y

ERC725Y interface id according to ERC165: 0x629aa694.

Smart contracts implementing the ERC725Y standard MUST implement the ERC165 supportsInterface(..) function and MUST support the ERC165 and ERC725Y interface ids.

Methods

Smart contracts implementing the ERC725Y standard MUST implement all of the functions listed below:

getData

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

Function Selector: 0x54f6127f

Gets the data set for the given data key.

Parameters:

  • dataKey: the data key which value to retrieve.

Returns: bytes , The data for the requested data key.

getDataBatch

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

Function Selector: 0xdedff9c6

Gets array of data at multiple given data keys.

Parameters:

  • dataKeys: the data keys which values to retrieve.

Returns: bytes[] , array of data values for the requested data keys.

setData

function setData(bytes32 dataKey, bytes memory dataValue) external payable

Function Selector: 0x7f23690c

Sets data as bytes in the storage for a single data key.

Parameters:

  • dataKey: the data key which value to set.
  • dataValue: the data to store.

Requirements:

  • MUST only be called by the current owner of the contract.

Triggers Event: DataChanged

setDataBatch

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

Function Selector: 0x97902421

Sets array of data at multiple data keys. MUST only be called by the current owner of the contract.

Parameters:

  • dataKeys: the data keys which values to set.
  • dataValues: the array of bytes to set.

Requirements:

  • Array parameters MUST have the same length.
  • MUST only be called by the current owner of the contract.

Triggers Event: DataChanged

Events

DataChanged

event DataChanged(bytes32 indexed dataKey, bytes dataValue)

MUST be triggered when a data key was successfully set.

ERC725Y Data keys

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 ERC725JSONSchema standard is a more explicit ERC725Y data key standard, that defines key types and value types, and their encoding and decoding.

Rationale

The generic way of storing data key with values was chosen to allow upgradablity 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 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 for single and multiple keys, to keep gas costs minimal for both uses cases.

Backwards Compatibility

All contracts since ERC725v2 from 2018/19 should be compatible to the current version of the standard. Mainly interface ID and Event parameters have changed, while getDataBatch(bytes32[]) and setDataBatch(bytes32[], bytes[]) was added as an efficient way to set/get multiple keys at once. The same applies for execution, as executeBatch(..[]) was added as an efficient way to batch calls.

Reference Implementation

Reference implementations can be found here

Security Considerations

This contract allows generic executions, therefore special care need to be take care 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 storge entries at will. Additionally calls to selfdestruct are possible and other harmful state changing operations.

Solidity Interfaces

// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.5.0 <0.7.0;

interface IERC725X  /* is ERC165, ERC173 */ {
    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 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 */ {

}

Additional References

Copyright

Copyright and related rights waived via CC0.