Skip to content

Commit

Permalink
Merge pull request #180 from ERC725Alliance/develop
Browse files Browse the repository at this point in the history
chore(release): 4.0.0
  • Loading branch information
frozeman authored Nov 1, 2022
2 parents 185b024 + e6de166 commit 9d45532
Show file tree
Hide file tree
Showing 44 changed files with 14,296 additions and 20,702 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# ERC 725 · [![npm version](https://img.shields.io/npm/v/@erc725/smart-contracts.svg?style=flat)](https://www.npmjs.com/package/@erc725/smart-contracts) [![Coverage Status](https://coveralls.io/repos/github/ERC725Alliance/ERC725/badge.svg?branch=develop)](https://coveralls.io/github/ERC725Alliance/ERC725?branch=develop)
# ERC725 · [![npm version](https://img.shields.io/npm/v/@erc725/smart-contracts.svg?style=flat)](https://www.npmjs.com/package/@erc725/smart-contracts) [![Coverage Status](https://coveralls.io/repos/github/ERC725Alliance/ERC725/badge.svg?branch=develop)](https://coveralls.io/github/ERC725Alliance/ERC725?branch=develop)

Repository for the code and standard documents around ERC725 and related standards

## ERC 725 Use Cases
## ERC725 Use Cases

Projects building on ERC725 are invited to add themselves to the table [here](https://github.com/ERC725Alliance/ERC725/blob/master/docs/use-cases.md).

Expand Down
189 changes: 114 additions & 75 deletions docs/ERC-725.md
Original file line number Diff line number Diff line change
@@ -1,96 +1,146 @@
---
eip: 725
title: General data key/value store and execution standard
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://github.com/ethereum/EIPs/issues/725
status: Review
type: Standards Track
category: ERC
requires: 165, 173
created: 2017-10-02
requires: 165, 173
---

## Simple Summary
## Abstract

A standard interface for a smart contract based account with attachable data key/value store.
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.

## Abstract
## Motivation

The following describes standard functions for a unique smart contract based account that can be used by humans,
groups, organisations, objects and machines.
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 standardisable, but are in its current form a generic set of standardised modules to be used in all forms of smart contracts.

The standard is divided into two sub standards:
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 verison of ERC725 is standardised under [LSP0 ERC725Account](https://github.com/lukso-network/LIPs/blob/master/LSPs/LSP-0-ERC725Account.md).

`ERC725X`:
Can execute arbitrary smart contracts and deploy other smart contracts.
These standareds (ERC725 X and Y) can also be used seperately to enhance NFTs and Token meta data, or allow generic exection for all kinds of smart contracts.

`ERC725Y`:
Can hold arbitrary data through a generic data key/value store.
## Specification

## Motivation
### Ownership

This contract is controlled by an owner. The owner can be a smart contract or an external account.
This standard requires [ERC173](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-173.md) and SHOULD implement the functions:

Standardizing a minimal interface for a smart contract based account allows any interface to operate through these account types.
Smart contact based accounts following this standard have the following advantages:
- `owner() view`
- `transferOwnership(address newOwner)`

- can hold any asset (native token, e.g. ERC20 like tokens)
- can execute any smart contract and deploy smart contracts
- have upgradeable security (through owner change, e.g. to a gnosis safe)
- are basic enough to work for a long time
- are extensible though additional standardisation of the key/value data.
- can function as an owner/controller or proxy of other smart contracts
And the event:

## Specification
- `OwnershipTransferred(address indexed previousOwner, address indexed newOwner)`

### ERC725X

ERC165 identifier: `0x44c028fe`
ERC165 identifier: `0x570ef073`

**Note:** The `execute()` function use function overloading, therefore it is better to reference them by the given function signature as follows:

```js
// web3.js example
myContract.methods['execute(uint256,address,uint256,bytes)'](OPERATION_CALL, target.address, 2WEI, "0x").send();

myContract.methods['execute(uint256[],address[],uint256[],bytes[])']([OPERATION_CALL, OPERATION_CREATE], [target.address, ZERO_ADDRESS], [2WEI, 0WEI], ["0x", CONTRACT_BYTECODE]).send()

// or
myContract.methods['0x44c028fe'](OPERATION_CALL, target.address, 2WEI, "0x").send();
```

#### execute

```solidity
function execute(uint256 operationType, address to, uint256 value, bytes calldata data) public payable returns(bytes memory)
function execute(uint256 operationType, address target, uint256 value, bytes memory data) public payable returns(bytes memory)
```

Executes a call on any other smart contracts, transfers the blockchains native token, or deploys a new smart contract.
Function Selector: `0x44c028fe`

Executes a call 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 the execution fails.

_Parameters:_

- `operationType`: the operation to execute.
- `to`: the smart contract or address to interact with. `to` will be unused if a contract is created (operation 1 and 2).
- `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 bytecode of the contract to deploy.
- `data`: the call data, or the creation bytecode of the contract to deploy.

#### 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>
```

_Returns:_ `bytes` , the returned data of the called function, or the address of the contract created (operation 1 and 2).
> Check [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014) for more information.
The `operationType` can be the following:
_Returns:_ `bytes` , the returned data of the called function, or the address of the contract deployed (operation types 1 and 2).

- `0` for `call`
- `1` for `create`
- `2` for `create2`
- `3` for `staticcall`
- `4` for `delegatecall`
The following `operationType` MUST 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.

**Triggers Event:** [ContractCreated](#contractcreated), [Executed](#executed)

> **Note:** the operation types `staticcall` (`3`) and `delegatecall` (`4`) do not allow to transfer value.
#### execute (Array)

```solidity
function execute(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes[] memory datas) public payable returns(bytes[] memory)
```

Function Selector: `0x13ced88d`

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.

_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

### Events

#### Executed

```solidity
event Executed(uint256 indexed operation, address indexed to, uint256 indexed _value, bytes4 data);
event Executed(uint256 indexed operationType, address indexed to, uint256 indexed _value, bytes4 data);
```

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

#### ContractCreated

```solidity
event ContractCreated(uint256 indexed operation, address indexed contractAddress, uint256 indexed value);
event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value);
```

MUST be triggered when `execute` creates a new contract using the `operationType` `1`, `2`.
Expand All @@ -113,9 +163,9 @@ myContract.methods['0x14a6e293']([dataKeys, ...], [dataValues, ...]).send()
function getData(bytes32 dataKey) public view returns(bytes memory)
```

Function Signature: `0x54f6127f`
Function Selector: `0x54f6127f`

Gets the data set for the given dataKey.
Gets the data set for the given data key.

_Parameters:_

Expand All @@ -129,23 +179,23 @@ _Returns:_ `bytes` , The data for the requested key.
function getData(bytes32[] memory dataKeys) public view returns(bytes[] memory)
```

Function Signature: `0x4e3e6e9c`
Function Selector: `0x4e3e6e9c`

Gets array of data at multiple given key.

_Parameters:_

- `dataKeys`: the keys which values to retrieve.

_Returns:_ `bytes[]` , array of the values for the requested dataKeys.
_Returns:_ `bytes[]` , array of data values for the requested data keys.

#### setData

```solidity
function setData(bytes32 dataKey, bytes memory dataValue) public
```

Function Signature: `0x7f23690c`
Function Selector: `0x7f23690c`

Sets data as bytes in the storage for a single key. MUST only be called by the current owner of the contract.

Expand All @@ -162,7 +212,7 @@ _Parameters:_
function setData(bytes32[] memory dataKeys, bytes[] memory dataValues) public
```

Function Signature: `0x14a6e293`
Function Selector: `0x14a6e293`

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

Expand All @@ -181,60 +231,49 @@ _Parameters:_
event DataChanged(bytes32 indexed dataKey, bytes dataValue)
```

MUST be triggered when `setData` was successfully called.
MUST be triggered when a data key was successfully set.

### Ownership
### ERC725Y Data keys

This contract is controlled by an owner. The owner can be a smart contract or an external account.
This standard requires [ERC173](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-173.md) and should implement the functions:
Data keys, are the way to retrieve values via `getData()`. These `bytes32` values can be freely chosen, or defined by a standard.
A common ways to define data keys is the hash of a word, e.g. `keccak256('ERCXXXMyNewKeyType')` which results in: `0x6935a24ea384927f250ee0b954ed498cd9203fc5d2bf95c735e52e6ca675e047`

- `owner() view`
- `transferOwnership(address newOwner)` <br>

The event:
The [LSP2 ERC725JSONSchema standard](https://github.com/lukso-network/LIPs/blob/master/LSPs/LSP-2-ERC725YJSONSchema.md) is a more explicit ERC725Y data key standard, that defines key types and value types, and their encoding.

- `OwnershipTransferred(address indexed previousOwner, address indexed newOwner)`

### Data keys

Data keys, should be the keccak256 hash of a type name.
e.g. `keccak256('ERCXXXMyNewKeyType')` is `0x6935a24ea384927f250ee0b954ed498cd9203fc5d2bf95c735e52e6ca675e047`

The [ERC725JSONSchema standard](https://github.com/lukso-network/LIPs/blob/master/LSPs/LSP-2-ERC725YJSONSchema.md) defines how keys should be named and generated.
This JSON schema can be used to auto decode ERC725Y values from smart contracts for application and smart contract interactions.
## Rationale

#### Default key values
Special care went into ensuring that data in this smart contract can be read not only by external applications, but also by other smart contracts in a gas efficient manner. Therefore function overwriting is used to allow for both single and multiple data keys to be retreived.

ERC725 key standards need to be defined within new standards, we suggest the following defaults:
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.

| Name | Description | Key | value |
| ---------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| SupportedStandards:XYZ | Allows to determine standards supported by this contract | `0xeafec4d89fa9619884b6b89135626455000000000000000000000000xxxxxxxx`, where `xxxxxxxx` is the 4 bytes identifier of the standard supported | Value can be defined by the standard, by default it should be the 4 bytes identifier e.g. `0x7a30e6fc` |
## Backwards Compatibility

#### ERC725Account
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 `getData(bytes32[])` and `setData(bytes32[], bytes[])` was added as an efficient way to set/get multiple keys at once. The same applies for execution, as `execute(..[])` was added as an efficient way to batch calls at once.

The specification of an ERC725Account can be found in [LSP0-ERC725Account](https://github.com/lukso-network/LIPs/blob/master/LSPs/LSP-0-ERC725Account.md).
## Reference Implementation

## Rationale
Reference implementations can be found [here](../assets/eip-725)

The purpose of an smart contract account is to allow an entity to exist as a first-class citizen with the ability to execute arbitrary contract calls.
## Security Consideration

## Implementation
This contract allows generic executions, therefore special care need to be take care to prevent re-entrancy attacks and other forms for call chain attacks.

- [Latest implementation](https://github.com/ERC725Alliance/ERC725/tree/master/implementations/contracts)
When using the operation type `4` for `delegatecall`, it is important to consider that called contracts can alter the state of the calling contract and also change owner variables 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: `0x44c028fe`
// ERC165 identifier: `0x570ef073`
interface IERC725X /* is ERC165, ERC173 */ {
event ContractCreated(uint256 indexed operation, address indexed contractAddress, uint256 indexed value);
event Executed(uint256 indexed operation, address indexed to, uint256 indexed value, bytes4 data);
event ContractCreated(uint256 indexed operationType, address indexed contractAddress, uint256 indexed value);
event Executed(uint256 indexed operationType, address indexed to, uint256 indexed value, bytes4 data);
function execute(uint256 operationType, address to, uint256 value, bytes memory data) external payable returns(bytes memory);
function execute(uint256 operationType, address to, uint256 value, bytes calldata data) external payable returns(bytes memory);
function execute(uint256[] memory operationsType, address[] memory targets, uint256[] memory values, bytes memory datas) external payable returns(bytes[] memory);
}
// ERC165 identifier: `0x714df77c`
Expand Down
2 changes: 1 addition & 1 deletion docs/ERC-734.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A contract for key management of a blockchain proxy account.

## Abstract
The following describes standard functions for a key manager to be used in conjunction with [ERC725](https://github.com/ethereum/EIPs/issues/725).
This contract can hold keys to sign actions (transactions, documents, logins, access, etc), as well as execute instructions through an ERC 725 proxy account.
This contract can hold keys to sign actions (transactions, documents, logins, access, etc), as well as execute instructions through an ERC725 proxy account.

## Motivation
This key manager standard allows for more complex management of an [ERC725](https://github.com/ethereum/EIPs/issues/725) proxy account.
Expand Down
7 changes: 6 additions & 1 deletion implementations/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ types
cache
artifacts

# Hardhat holders
build
solc
cache
types
coverage

.openzeppelin/.session

# Solidity generated files/folders
solc

# Mac
.DS_Store
16 changes: 16 additions & 0 deletions implementations/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## 4.0.0 (2022-10-31)

### ⚠ BREAKING CHANGES

- add underscore to variable name `store` -> `_store` (#174)
- replace error strings by custom errors (#175)
- add execute batch function to ERC725X (#177)

### Features

- add execute batch function to ERC725X ([a0b08fa](https://github.com/ERC725Alliance/ERC725/commit/a0b08fafccd1f009a497ca400efd50933a478457))

### Bug Fixes

- emit `Executed` event before the external call ([#173](https://github.com/ERC725Alliance/ERC725/issues/173)) ([13743ae](https://github.com/ERC725Alliance/ERC725/commit/13743aedc1d6dce3e50cd8dd3b82b0e51fbd6827))

## [3.2.0](https://github.com/ERC725Alliance/ERC725/compare/v3.1.0...v3.2.0) (2022-09-01)

### ⚠ BREAKING CHANGES
Expand Down
2 changes: 2 additions & 0 deletions implementations/analyse.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# you need to install the solc compiler to run these commands (not solcjs from the npm package, it does not include these options)
# See installation instructions: https://docs.soliditylang.org/en/v0.8.16/installing-solidity.html
solc --storage-layout @openzeppelin/="$(pwd)"/node_modules/@openzeppelin/ solidity-bytes-utils/="$(pwd)"/node_modules/solidity-bytes-utils/ ../Utils="$(pwd)/contracts/Utils" contracts/ERC725.sol -o ./analyse/storage-layout/ --pretty-json --overwrite
solc --hashes @openzeppelin/="$(pwd)"/node_modules/@openzeppelin/ solidity-bytes-utils/="$(pwd)"/node_modules/solidity-bytes-utils/ ../Utils="$(pwd)/contracts/Utils" contracts/ERC725.sol -o ./analyse/selectors/ --overwrite
solc --gas @openzeppelin/="$(pwd)"/node_modules/@openzeppelin/ solidity-bytes-utils/="$(pwd)"/node_modules/solidity-bytes-utils/ ../Utils="$(pwd)/contracts/Utils" contracts/ERC725.sol >> ./analyse/gas-costs.md --overwrite
Expand Down
Loading

0 comments on commit 9d45532

Please sign in to comment.