mirror of https://github.com/status-im/EIPs.git
Automatically merged updates to draft EIP(s) 725
Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing
This commit is contained in:
parent
822dc9d73f
commit
f357d88854
297
EIPS/eip-725.md
297
EIPS/eip-725.md
|
@ -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.
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
### Methods
|
||||
|
||||
Keys are cryptographic public keys, or contract addresses associated with this identity.
|
||||
The structure should be as follows:
|
||||
|
||||
- `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);
|
||||
```js
|
||||
function changeOwner(address _owner);
|
||||
```
|
||||
|
||||
#### keyHasPurpose
|
||||
**Triggers Event:** [OwnerChanged](#ownerchanged)
|
||||
|
||||
Returns `TRUE` if a key is present and has the given purpose. If the key is not present it returns `FALSE`.
|
||||
#### getData
|
||||
|
||||
``` js
|
||||
function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists);
|
||||
Returns the data at the specified key.
|
||||
|
||||
```js
|
||||
function getData(bytes32 _key) external view returns (bytes _value);
|
||||
```
|
||||
|
||||
#### setData
|
||||
|
||||
#### getKeysByPurpose
|
||||
Sets the data at a specific key. MUST only be called by the current owner of the contract.
|
||||
|
||||
Returns an array of public key bytes32 held by this identity.
|
||||
**Triggers Event:** [DataChanged](#datachanged)
|
||||
|
||||
``` js
|
||||
function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys);
|
||||
```js
|
||||
function setData(bytes32 _key, bytes _value) external;
|
||||
```
|
||||
|
||||
|
||||
#### addKey
|
||||
|
||||
Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes:
|
||||
|
||||
- `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)
|
||||
```
|
||||
|
||||
|
||||
#### removeKey
|
||||
|
||||
Removes `_key` from the identity.
|
||||
|
||||
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:** [KeyRemoved](#keyremoved)
|
||||
|
||||
``` js
|
||||
function removeKey(bytes32 _key, uint256 _purpose) returns (bool success)
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
### 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.
|
||||
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.
|
||||
|
||||
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)
|
||||
```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`
|
||||
|
||||
#### approve
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
|
||||
### 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
|
||||
#### DataChanged
|
||||
|
||||
MUST be triggered when `addKey` was successfully called.
|
||||
MUST be triggered when `setData` was successfully called.
|
||||
|
||||
``` js
|
||||
event KeyAdded(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`.
|
||||
|
||||
```js
|
||||
event ContractCreated(address indexed contractAddress);
|
||||
```
|
||||
|
||||
#### OwnerChanged
|
||||
|
||||
MUST be triggered when `changeOwner` was successfully called.
|
||||
|
||||
```js
|
||||
event OwnerChanged(address indexed ownerAddress);
|
||||
```
|
||||
|
||||
|
||||
#### KeyRemoved
|
||||
### Ownership
|
||||
|
||||
MUST be triggered when `removeKey` was successfully called.
|
||||
This contract is controlled by the owner. The owner can be a smart contract or an address, or itself.
|
||||
|
||||
``` js
|
||||
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType)
|
||||
```
|
||||
### Data keys
|
||||
|
||||
Data keys, should be the keccak256 hash of a type name.
|
||||
e.g. `myNewKeyType` is `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4`
|
||||
|
||||
#### Multiple keys of the same type
|
||||
|
||||
#### ExecutionRequested
|
||||
Multiple keys for the same key type must add a `keyTypeName-1` at the end of the key type.
|
||||
|
||||
MUST be triggered when `execute` was successfully called.
|
||||
|
||||
``` js
|
||||
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)
|
||||
```
|
||||
|
||||
|
||||
#### Executed
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
|
||||
#### Approved
|
||||
|
||||
MUST be triggered when `approve` was successfully called.
|
||||
|
||||
``` js
|
||||
event Approved(uint256 indexed executionId, bool approved)
|
||||
```
|
||||
|
||||
##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED:
|
||||
|
||||
#### ClaimRequested
|
||||
|
||||
MUST be triggered when `addClaim` was successfully called.
|
||||
|
||||
|
||||
#### ClaimAdded
|
||||
|
||||
MUST be triggered when `approve` was called and the claim was successfully added.
|
||||
|
||||
|
||||
## Constraints
|
||||
|
||||
- A claim can only be one type per type per issuer.
|
||||
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.
|
||||
|
||||
| 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` |
|
||||
|
||||
## 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.
|
||||
|
||||
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 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.
|
||||
|
||||
The rationale of this standard is to function as an open and very flexible container for identity.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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;
|
||||
pragma solidity ^0.5.4;
|
||||
|
||||
contract ERC725 {
|
||||
interface ERC725 {
|
||||
event DataChanged(bytes32 indexed key, bytes32 indexed value);
|
||||
event OwnerChanged(address indexed ownerAddress);
|
||||
event ContractCreated(address indexed contractAddress);
|
||||
|
||||
uint256 constant MANAGEMENT_KEY = 1;
|
||||
uint256 constant ACTION_KEY = 2;
|
||||
uint256 constant CLAIM_SIGNER_KEY = 3;
|
||||
uint256 constant ENCRYPTION_KEY = 4;
|
||||
// address public owner;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in New Issue