Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed draft to ERC725v2 #1867

Merged
merged 1 commit into from
Mar 25, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 79 additions & 204 deletions EIPS/eip-725.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,283 +10,158 @@ created: 2017-10-02
---

## Simple Summary
A proxy contract for key management and execution, to establish a Blockchain identity.
A standard interface for a simple proxy account.

## Abstract
The following describes standard functions for a unique identity for humans, groups, objects and machines.
This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self-attested ([#ERC735](https://github.com/ethereum/EIPs/issues/735)), as well as a proxy function, to act directly on the blockchain.

## Motivation
This standardized identity interface will allow Dapps, smart contracts and third parties to check the validity of a person, organization, object or machine through 2 steps as described in the function XXX. Trust is here transferred to the issuers of claims.

The most important functions to verify an identity are: `XXX`

The most important functions to manage an identity are: `XXX`


## Definitions

- `keys`: Keys are public keys from either external accounts, or contracts' addresses.
- `claim issuer`: is another smart contract or external account, which issues claims about this identity. The claim issuer can be an identity contract itself.
- `claim`: For details about claims see [#ERC735](https://github.com/ethereum/EIPs/issues/735)
The following describes standard functions for a unique identifiable proxy account to be used by humans, groups, organisations, objects and machines. The proxy has 2 abilities: (1) it can execute arbitrary contract calls, and (2) it can hold arbitrary data through a generic key/value store. One of these keys should hold the owner of the contract. The owner may be an address or a key manager contract for more complex management logic. Most importantly, this contract should be the reference point for a long-lasting identifiable profiles.

## Motivation

Standardizing a minimal interface for an proxy account allows third parties to interact with various proxy accounts contracts in a consistent manner.
the benefit is a persistent account that is independed from single keys and can attach an arbitrary amount of information to verifiy, or enhance the accounts purpose.

## Specification


### Key Management

Keys are cryptographic public keys, or contract addresses associated with this identity.
The structure should be as follows:
### Methods

- `key`: A public key owned by this identity
- `purpose`: `uint256` The key purpose. e.g., 1 = MANAGEMENT, 2 = ACTION, 3 = CLAIM, 4 = ENCRYPTION
- `keyType`: The type of key used, which would be a `uint256` for different key types. e.g. 1 = ECDSA, 2 = RSA, etc.
- `key`: `bytes32` The public key. // for non-hex and long keys, its the Keccak256 hash of the key
#### owner

Returns the current owner

```js
struct Key {
uint256 purpose;
uint256 keyType;
bytes32 key;
}
function address public owner;
```

#### getKey
#### changeOwner

Returns the full key data, if present in the identity.
Changes the current owner. MUST only be called by the current owner of the contract.

``` js
function getKey(bytes32 _key) constant returns(uint256 purpose, uint256 keyType, bytes32 key);
```

#### keyHasPurpose

Returns `TRUE` if a key is present and has the given purpose. If the key is not present it returns `FALSE`.

``` js
function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists);
```


#### getKeysByPurpose

Returns an array of public key bytes32 held by this identity.

``` js
function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys);
```js
function changeOwner(address _owner);
```

**Triggers Event:** [OwnerChanged](#ownerchanged)

#### addKey
#### getData

Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes:
Returns the data at the specified key.

- `1`: MANAGEMENT keys, which can manage the identity
- `2`: ACTION keys, which perform actions in this identity's name (signing, logins, transactions, etc.)
- `3`: CLAIM signer keys, used to sign claims on other identities which need to be revocable.
- `4`: ENCRYPTION keys, used to encrypt data e.g. hold in claims.

MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.

**Triggers Event:** [KeyAdded](#keyadded)

``` js
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) returns (bool success)
```js
function getData(bytes32 _key) external view returns (bytes _value);
```

#### setData

#### removeKey

Removes `_key` from the identity.
Sets the data at a specific key. MUST only be called by the current owner of the contract.

MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.
**Triggers Event:** [DataChanged](#datachanged)

**Triggers Event:** [KeyRemoved](#keyremoved)

``` js
function removeKey(bytes32 _key, uint256 _purpose) returns (bool success)
```js
function setData(bytes32 _key, bytes _value) external;
```


--------------------------------------------------------

### Identity usage


#### execute

Executes an action on other contracts, or itself, or a transfer of ether.
SHOULD require `approve` to be called with one or more keys of purpose `1` or `2` to approve this execution.

Execute COULD be used as the only accessor for `addKey`, `removeKey` and `replaceKey` and `removeClaim`.

**Returns `executionId`:** SHOULD be sent to the `approve` function, to approve or reject this execution.

**Triggers Event:** [ExecutionRequested](#executionrequested)
**Triggers on direct execution Event:** [Executed](#executed)

``` js
function execute(address _to, uint256 _value, bytes _data) returns (uint256 executionId)
```


#### approve
Executes an action on other contracts or a transfer of the blockchains native cryptocurrency. MUST only be called by the current owner of the contract.

Approves an execution or claim addition.
This SHOULD require `n` of `m` approvals of keys purpose `1`, if the `_to` of the execution is the identity contract itself, to successfully approve an execution.
And COULD require `n` of `m` approvals of keys purpose `2`, if the `_to` of the execution is another contract, to successfully approve an execution.

**Triggers Event:** [Approved](#approved)
**Triggers on successfull execution Event:** [Executed](#executed)
**Triggers on successfull claim addition Event:** [ClaimAdded](#claimadded)

``` js
function approve(uint256 _id, bool _approve) returns (bool success)
```js
function execute(uint256 _operationType, address _to, uint256 _value, bytes _data) external;
```

The `operationType` should represent the assembly operation as follows:
- `0` for `call`
- `1` for `create`

--------------------------------------------------------


### Identity verification

Requires: [ERC 735](https://github.com/ethereum/EIPs/issues/735)

##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED:

#### addClaim

This SHOULD create a pending claim, which SHOULD be approved or rejected by `n` of `m` `approve` calls from keys of purpose `1`.

Only Events:
**Triggers if the claim is new Event and approval process exists:** [ClaimRequested](#claimrequested)
**Triggers if the claim index existed Event:** [ClaimChanged](https://github.com/ethereum/EIPs/issues/735)


#### removeClaim

MUST only be done by the `issuer` of the claim, or keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.


--------------------------------------------------------

Others may be added in the future. Inspired by [ERC1077](https://eips.ethereum.org/EIPS/eip-1077) and [Gnosis](https://github.com/gnosis/safe-contracts/blob/master/contracts/Enum.sol#L7)

### Events


#### KeyAdded

MUST be triggered when `addKey` was successfully called.

``` js
event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType)
```


#### KeyRemoved
#### DataChanged

MUST be triggered when `removeKey` was successfully called.
MUST be triggered when `setData` was successfully called.

``` js
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType)
```js
event DataChanged(bytes32 indexed key, bytes value);
```

#### ContractCreated

MUST be triggered when `execute` creates a new contract using the `_operationType` `1`.

#### ExecutionRequested

MUST be triggered when `execute` was successfully called.

``` js
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)
```js
event ContractCreated(address indexed contractAddress);
```

#### OwnerChanged

#### Executed
MUST be triggered when `changeOwner` was successfully called.

MUST be triggered when `approve` was called and the execution was successfully approved.

``` js
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)
```js
event OwnerChanged(address indexed ownerAddress);
```


#### Approved
### Ownership

MUST be triggered when `approve` was successfully called.
This contract is controlled by the owner. The owner can be a smart contract or an address, or itself.

``` js
event Approved(uint256 indexed executionId, bool approved)
```

##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED:

#### ClaimRequested
### Data keys

MUST be triggered when `addClaim` was successfully called.
Data keys, should be the keccak256 hash of a type name.
e.g. `myNewKeyType` is `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4`

#### Multiple keys of the same type

#### ClaimAdded
Multiple keys for the same key type must add a `keyTypeName-1` at the end of the key type.

MUST be triggered when `approve` was called and the claim was successfully added.
This would looks as follows for `myNewKeyType`:
version 0 `myNewKeyType`: `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4`
version 1 `myNewKeyType-1`: `0xb6dace1ed14874742c4d1b8cd9b270305176f769e0ae22118a02c2db4e620f29`
version 2 `myNewKeyType-2`: `0x6cc96a01de588f4550e8c3a821aed065ae7897f8dfb61836c78c0389e499d9ed`
...

Anyone that would like to standardize a new data key should make a pull request to update the table below.

## Constraints
| Name | Description | Key | value |
| --- | --- | --- | --- |
| owner | The owner of the proxy account | 0x0000000000000000000000000000000000000000000000000000000000000000 | left padded owner address, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |
| 735 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xb0f23aea7d77ce19f9393243a7b50a3bcaac893c7d68a5a309dea7cacf035fd0 | left padded address of the claim holder contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |
| 780 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xdaf52dba5981246bcf8fd7c6b00dce587fdcf5e2a95b281eea95dcd1376afdcd | left padded address of the claim registry contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |

- A claim can only be one type per type per issuer.
## Rationale

The purpose of an identity proxy is to allow an entity to exist as a first-class citizen in Ethereum, with the ability to execute arbitrary contract calls. At that same time the proxy account should be managed by an arbitrary simple or complex logic.

It also opens up the possibility of [meta transactions](https://medium.com/@austin_48503/ethereum-meta-transactions-90ccf0859e84), where a third party can send a transaction to the owner contract, that then verifies the execution permission based on a signed message.

## Rationale
This specification was chosen to allow most flexibility and experimentation around identity. By having each identity in a separate contract it allows for cross identity compatibility, but at the same time extra and altered functionality for new use cases.
It further allows any information to be attached to that proxy accounts which can be in the forms of claims via [ERC735](https://github.com/ethereum/EIPs/issues/735) or [ERC780](https://github.com/ethereum/EIPs/issues/780), or any arbitrary new systems and protocols.

The main critic of this standard is the verification where each identity that issues a claim, also should have a separate CLAIM signing key attached. While [#ERC780](https://github.com/ethereum/EIPs/issues/780) uses a standardized registry to assign claims to addresses.
Both systems could work in conjunction and should be explored.
While also off-chain claims using DID verifiable claims and merkle tries can be added as claims and should be explored.

The rationale of this standard is to function as an open and very flexible container for identity.
This specification was chosen to allow the most flexibility and experimentation around verifiable manageable accounts.


## Implementation

- [DID resolver specification](https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-spring2018/blob/master/topics-and-advance-readings/DID-Method-erc725.md)
- [Implementation by mirceapasoi](https://github.com/mirceapasoi/erc725-735)
- [Implementation by Nick Poulden](https://github.com/OriginProtocol/identity-playground), interface at: https://erc725.originprotocol.com/
- [Implementation by ERC725Alliance](https://github.com/ERC725Alliance/erc725/tree/master/contracts/contracts)


### Solidity Interface
```js
pragma solidity ^0.4.18;

contract ERC725 {

uint256 constant MANAGEMENT_KEY = 1;
uint256 constant ACTION_KEY = 2;
uint256 constant CLAIM_SIGNER_KEY = 3;
uint256 constant ENCRYPTION_KEY = 4;

event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
event Approved(uint256 indexed executionId, bool approved);

struct Key {
uint256 purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc.
uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc.
bytes32 key;
}

function getKey(bytes32 _key) public constant returns(uint256 purpose, uint256 keyType, bytes32 key);
function keyHasPurpose(bytes32 _key, uint256 _purpose) public constant returns (bool exists);
function getKeysByPurpose(uint256 _purpose) public constant returns (bytes32[] keys);
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success);
function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success);
function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId);
function approve(uint256 _id, bool _approve) public returns (bool success);
pragma solidity ^0.5.4;

interface ERC725 {
event DataChanged(bytes32 indexed key, bytes32 indexed value);
event OwnerChanged(address indexed ownerAddress);
event ContractCreated(address indexed contractAddress);

// address public owner;

function changeOwner(address _owner) external;
function getData(bytes32 _key) external view returns (bytes32 _value);
function setData(bytes32 _key, bytes32 _value) external;
function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data) external;
}
```

Expand Down