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

ERC: Proxy Account #725

Closed
frozeman opened this issue Oct 2, 2017 · 276 comments
Closed

ERC: Proxy Account #725

frozeman opened this issue Oct 2, 2017 · 276 comments
Labels

Comments

@frozeman
Copy link
Contributor

frozeman commented Oct 2, 2017

This proposal has moved to ERC-725 (source).

This issue exists as an archive only.

Original Text
eip: <to be assigned>
title: ERC-725 Smart Contract Based Account
author: Fabian Vogelsteller <[email protected]>, Tyler Yasaka (@tyleryasaka)
discussions-to: https://github.com/ethereum/EIPs/issues/725
status: Draft
type: Standards Track
category: ERC
requires: ERC165, ERC173, ERC1271 (optional)
created: 2017-10-02
updated: 2020-07-02

This is the new 725 v2 standard, that is radically different from ERC 725 v1. ERC 725 v1 is be moved to #734 as a new key manager standard.

Simple Summary

A standard interface for a smart contract based account with attachable key value store.

Abstract

The following describes standard functions for a unique smart contract based account that can be used by humans,
groups, organisations, objects and machines.

The standard is divided into two sub standards:

ERC725X:
Can execute arbitrary smart contracts using and deploy other smart contracts.

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

Motivation

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:

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

Specification

ERC725X

ERC165 identifier: 0x44c028fe

execute

Executes a call on any other smart contracts, transfers the blockchains native token, or deploys a new smart contract.
MUST only be called by the current owner of the contract.

function execute(uint256 operationType, address to, uint256 value, bytes data)

The operationType can execute the following operations:

  • 0 for call
  • 1 for delegatecall
  • 2 for create2
  • 3 for create

Others may be added in the future.

Triggers Event: ContractCreated if a contract was created

Events

ContractCreated

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

event ContractCreated(address indexed contractAddress)

ERC725Y

ERC165 identifier: 0x2bd57b73

getData

Returns the data at the specified key.

function getData(bytes32 key) external view returns(bytes value)

setData

Sets the data at a specific key. MUST only be called by the current owner of the contract.

Triggers Event: DataChanged

function setData(bytes32 _key, bytes memory _value) external

Events

DataChanged

MUST be triggered when setData was successfully called.

event DataChanged(bytes32 indexed key, bytes value)

Ownership

This contract is controlled by an 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 event 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

Multiple keys of the same type

If you require multiple keys of the same key type they MUST be defined as follows:

  • The keytype name MUST have a [] add and then hashed
  • The key hash MUST contain the number of all elements, and is required to be updated when a new key element is added.

For all other elements:

  • The first 16 bytes are the first 16 bytes of the key hash
  • The second 16 bytes is a uint128 of the number of the element
  • Elements start at number 0
Example

This would looks as follows for ERCXXXMyNewKeyType[] (keccak256: 0x4f876465dbe22c8495f4e4f823d846957ddb8ce6006afe66ddc5bac4f0626767):

  • element number: key: 0x4f876465dbe22c8495f4e4f823d846957ddb8ce6006afe66ddc5bac4f0626767, value: 0x0000000000000000000000000000000000000000000000000000000000000002 (2 elements)
  • element 1: key: 0x4f876465dbe22c8495f4e4f823d8469500000000000000000000000000000000, value: 0x123... (element 0)
  • element 2: key: 0x4f876465dbe22c8495f4e4f823d8469500000000000000000000000000000001, value: 0x321... (element 1)
    ...

Default key values

ERC725 key standards need to be defined within new standards, we suggest the following defaults:

Name Description Key value
SupportedStandards 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
SupportedStandards > ERC725Account Allows to determine standards supported by this contract 0xeafec4d89fa9619884b6b89135626455000000000000000000000000afdeb5d6, where afdeb5d6 is the 4 bytes part of the hash of keccak256('ERC725Account') Value is the 4 bytes identifier 0xafdeb5d6
ERC725Account

An ERC725Account is an ERC725 smart contract based account for storing of assets and execution of other smart contracts.

  • ERC173 to be controllable by an owner, that could be am external account, or smart contract
  • ERC725X to interact with other smart contracts
  • ERC725Y to attach data to the account for future extensibility
  • COULD have ERC1271 to be able to verify signatures from owners.
  • Should fire the event ValueReceived(address indexed sender, uint256 indexed value) if ETH is received.

A full implementation of an ERC725Account can be found found here.

Rationale

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.

Implementation

Solidity Interfaces

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

//ERC165 identifier: `0x44c028fe`
interface IERC725X  /* is ERC165, ERC173 */ {
    event ContractCreated(address indexed contractAddress);
    event Executed(uint256 indexed operation, address indexed to, uint256 indexed  value, bytes data);

    function execute(uint256 operationType, address to, uint256 value, bytes memory data) external;
}

//ERC165 identifier: `0x2bd57b73`
interface IERC725Y /* is ERC165, ERC173 */ {
    event DataChanged(bytes32 indexed key, bytes value);

    function getData(bytes32 key) external view returns (bytes memory value);
    function setData(bytes32 key, bytes memory value) external;
}

interface IERC725 /* is IERC725X, IERC725Y */ {

}

interface IERC725Account /* is IERC725, IERC725Y, IERC1271 */ {
    event ValueReceived(address indexed sender, uint256 indexed value);
}

Flow chart

ERC725v2-flow

Additional References

Copyright

Copyright and related rights waived via CC0.

@frozeman frozeman added the ERC label Oct 2, 2017
@alexvandesande
Copy link

alexvandesande commented Oct 2, 2017

This is a very useful ERC. I would remove all the Must and Should comments regarding types of keys as it should really be left up to the implementation of the contract.

Some contract types might want to have the admin functions, like claim or addKey be made by some types of admin keys, some might want to make those available to different types of keys, some might want to make the process to addKeys to go through the same process as any execute call will go to. This actually doesn't add much complexity: if you want a contract like that, just make so that only the contract itself can call some functions, and then make functions like addKey be actually just a proxy that creates a proper request to execute them, via whatever mechanism execute needs to go.


function approve(uint256 _id) returns (bool success)

you should either add a second boolean parameter to say either you approve or not, or add a second function called reject

@frozeman
Copy link
Contributor Author

frozeman commented Oct 2, 2017

I added the bool to the approve, just forgot that.

Concerning the flexibility of key addition/removals, i added:
"MUST only be done by keys of type 1, or the identity itself. If its the identity itself, the approval process will determine its approval."

Which includes either using key type 1, or the identity itself, e.g. then only the identity contract itself can call those function, and they always go through the approval process.

@alexvandesande
Copy link

It's just that I don't believe defining key types should be in the scope of this ERC. For some cases, like a democracy, the strings can represent different types of agents: voters, election officials, ID validators, those who can propose new stuff, etc. For a more hierarchical organization, type can be a number representing their rank: for some smaller is more important, for others, bigger is more important.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 2, 2017

The reason to add key types, is to prevent people from running around with keys, which can overtake their identity, but rather only use they action keys on a daily basis. Those wont have the ability to remove or change keys, which reduces the risk to loose your identity all together.

The other advantage is that it allows to define purposes to keys, which other entities or contracts can then use to derive the purpose of a user action on their system. E.g. if key type 23 means award collector, then a game interface knows which one to assign awards to.

@MicahZoltu
Copy link
Contributor

I would like to see some details/arguments as to why this benefits from being a standard. In what ways do we gain interoperability benefits from having this standardized? What types of general purpose tooling are we expecting people to build that will need to work with unknown future implementations of this?

Looking over the methods, it seems like a large number of them would qualify as "implementation details" and are not relevant to creating an generic identity management standard. For example, how a particular identity provider does key management is not something that needs to work with many tools, it just needs to work with the identity provider's tool suite. Even some contract that supports 10 identity providers and wants to interface with them all presumably needs to trust those providers in advance, meaning they don't need to build their contract to support arbitrary future providers.

Given the current motivation section, I would recommend that this not be a standard and instead just be a contract/dApp that anyone can write and deploy. 😄

@alexvandesande
Copy link

@MicahZoltu I disagree there. If I'd like to be able to use an identity in Mist, it means that I want to create an account, allow that account do things on behalf of others. What I mostly need to be standardized is the addKey, execute and approve. We can use our own private contract, but I think it's nice to try to work together with others.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 2, 2017

This needs to be standardized so that other contracts can interact with real world identities, automatically check and verify them. It’s not mainly necessary for interfaces alone. Also this contract represents ONE identity. The addition of claims need to be standardized, so that other identities can issue claims about each other.

Verifying an identity would happen in the following ways:

  • either The calling contract knows the claimtype (are not defined yet, but would be things like address, biometric data etc) and issuer it trusts. Then he simply needs to retrieve that claim and verify that it’s signature contains the address of the identity and the claim number. And checks that this signing address belongs to the issuers identity.
  • or he will retrieve claim by type and then goes and checks the issuers identity claims. This can be done down as many ways as necessary to end up at an trusted claim.

But I assume over time known and trusted issuers will appear so only one check needs to be done.

I might write an extra document to explain all the ways of how one can interact with this contract. But I would like to keep that apart from the ERC itself to keep it easy to read.

@MicahZoltu
Copy link
Contributor

MicahZoltu commented Oct 2, 2017

In order for there to be value in a standard there needs to be interoperability concerns that are being addressed. We don't need a standard for prediction markets, or a standard for exchanges or a standard for gambling games unless there is a compelling argument as to how one of these things would be better if they were interoperable. There isn't significant value in making it so all gambling games have the same interface, since users will interact with each gambling game via a dApp custom built for that gambling game.

A good example of useful standardization is token contracts. There is value in standardizing tokens so that an application (e.g., Wallet, exchange, etc.) can interact with any token the user provides without needing to know about it in advance or write custom integrations for each token. However, there is little to no value in standardizing how tokens come into existence because there isn't a strong need for a general purpose UI for token management. Each token author can build a token management UI just for their token, end users won't be using this so it doesn't even need to have a familiar interface.

@alexvandesande You have indicated that you want addKey, execute and approve standardized. How would standardizing those add value to the ecosystem? What can you do with those things standardized across many implementations that you wouldn't be able to do if they were not standardized?

@frozeman It sounds like you have a grand vision in your head that isn't expressed clearly in this EIP or discussion. I would love to hear more about it.

As a dApp developer who wants to verify the identity of someone interacting with my contract, I need to go to an identity provider that I trust and and say, "account X claims to be UUID Y, please verify" (or similar) and they would then return true or false. This is certainly useful, but I do not see where in this process a standard adds value. Since I need a pre-existing trust relationship with the identity provider, my dApp won't be accepting any random identity provider that a user gives me. I must integrate my dApp with specific identity providers, and in almost all situations I can think of I will pick one (and only one).

To be really clear, I'm not arguing that Identity Providers are bad. I'm arguing that creating a "standard" (and going through the RFC process) for every useful contract someone can think of is bad. There may be value in this being standardized, but it is not immediately apparent to me and I want you to convince me that standardization adds value.

Edit: In case it isn't clear exactly what I'm looking for, I would like to see a problem statement that shows some problem that can't be solved without a standard. Right now this EIP is missing a problem statement.

@Arachnid
Copy link
Contributor

Arachnid commented Oct 3, 2017

Some upfront definitions would be good. What are keys? Are they cryptographic identities? Why not addresses? What is a claim for, and how does it work?

Interface definitions probably shouldn't contain Solidity-specific types (eg, mapping(foo=>bar) baz), but instead the interfaces they generate (eg, function baz(foo) returns(bar);). How it's implemented is an implementation detail for the contract.

I agree with @alexvandesande that principal types should be left up to the implementation. Role accounts are a good thing and should be encouraged, but there's no need for the spec to mandate what roles exist and what privileges they have.

@MicahZoltu I believe the purpose of standardising this is to allow multiple clients (eg, wallets) to interact with multiple implementations of identity providers (Eg, multisigs, etc). Without a standard, you have the current situation, where Mist has native UI for multisigs, but only for its own API, Parity has another, and so forth.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 3, 2017

@MicahZoltu i see this needs a lot more explanation. I kept the standard description concise to make it readable, but many of the concepts i introduce here are not apparent right from the start. I will address each of these points here in the discussion, but also keep in mind, as i wrote above; the ERC draft is not finished yet.
I will be giving a talk at the london meet up on the october 11th, where i will lay out my vision for that standard in more detail. This will be recorded and i will post the video here.

First of this is a standard for a self sovereign identity; This means the owner controls its identity and he allows claims about himself to be attached to his identity. There are no identity providers, but claim issuer (or certifiers). Those simply say: "I saw him in person, stored his biometric data, and attached a link on his identity". People who want to verify that they are dealing with a person, either in their contracts, or dapps, websites, etc. can then check on their identity - given they got a signed message from one of its keys - and look for a claim they trust.

But to answer you questions:

  • Why i think this needs to be standardised:
    Standardising this allows other contracts in the future to auto verify users, and implement permission models right in their contract. Standardising also allows other identities, or claim issuers to add claims to an identity. The less important part is standardisation for UI interfaces; But also here we gain the ability to take your identity and make it useful and accessible in Mist, MetaMask, Browsers, Government UIs, border control, community tools and what not... Once an identity is created, it is meant to be used for a long time and over many platforms and UIs, otherwise it can't function as your identity over time.

Do i think all of the current proposed functions need to be standardised? No; i just wanted to give a more or less complete set of functions, which make clear how they interact together.

  • What is an example use case
    Imagine the following: You want to interact with an smart contract of a bank to create an account. They need to make KYC on you. In the openAccount call from your identity, the bank contract can see this call is coming from an identity, so he will:
    -> look for claim type 1:biometric and 2:homeAddress and for a claim issuer they know they trust, like the German state for 1 and the Deutsche Post for 2. As they know their identity contract addresses, they simply do: keccak256(issuer address + claimTypeNumber) and get the index of the claim in YOUR identity.
    -> they retrieve the claim, check that the signed data matches keccak256(YOUR identity address + claimTypeNumber)
    -> Now they check that the key which this data was signed, is still hold by the issuers identity contract.
    -> They got their proof - without that they need to actually see the biometric data, nor the address, as they trust the issuer - and they can proceed in opening an account.

The whole example above, won't work automated and with unknown parties, if these processes and functions aren't standardised.

Another extension of this could be that you have to hop through multiple claim issuers, to reach one you trust, which in return makes you trust all the others, including the one you verify the identity of.

Also every claim issuer, needs to implement this identity interface himself, to make sure he is verifiable himself (and keys can be checked).

@Arachnid concerning key types: If we standardise them we allow many upcoming use cases for keys, as described in my previous comment. Currently i only propose two types: 1 management keys, and 2 action keys. The former is for manage your identity and they should stay safe. There can be n of m required for any change. The latter is for actions in the world, keys which can act in the name of your identity. Those are replaceable, and for everybody who wants to interact with you, should always check of you still hold those keys in your identity.

Claim types in return need to be predefined, to allow somebody who wants to verify you to look for what he want a proof about you.

I choose the word keys, over addresses as this is better understandable in the "off-chain" world. Keys are something we use on a daily basis to get into houses and objects, and the term is used in cryptography as well. Addresses is very blockchain specific. Though your identity contract address - i would call "address".

The current draft allows for all kind of different key management implementations, it doesn't force any, expect that there have to be at least one second step of approval to execute, as stated in the draft, some functions..:

"MUST only be done by keys of type 1, or the identity itself. If its the identity itself, the approval process will determine its approval."

(There is certainly a lot of improvement potential here, and when we think of compatible UIs, we will need to revise that)

Many of the above concepts may not be clear yet, but they are in the description of the ERC as a very concise sentence:

"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, as well as a proxy function to act directly on the blockchain."

@Arachnid
Copy link
Contributor

Arachnid commented Oct 3, 2017

I choose the word keys, over addresses, as this is better understandable in the "off-chain" world. Keys are something we use on a daily basis to get into houses and objects, and the term used in cryptography as well. Addresses is very blockchain specific. Though you identity contract address, i would call "address".

The problem is, 'keys' has a specific use in cryptography, and you're using them to refer to something that isn't a cryptographic key, or necessarily controlled by one. I'd really suggest choosing a different term.

In either case, the EIP definitely needs a definitions section.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 3, 2017

I agree we should add a definition section.

Short answer to the above. keys are public keys: Those keys are you hands in the real world, you sign things, you make transactions etc.
Through these keys and a pointer to your identity, others can go check that its really you.
If they want to know things about you: e.g. are you a human, or have an address, then they look on the claims about you by others.

‘Keys’ here can be public keys or other contract, like multisigs and reputation systems. If anybody has a better word for them, I’m happy to change that.

@overdrev
Copy link

overdrev commented Oct 3, 2017

claims :
a.I would suggest a logic that permits explicit approval of claim by issuer - perhaps requiring an asynchronous process.
b. Do we cover a single usage access method such that a third party can prove my info, but only once. Maybe time limited.

@alexvandesande
Copy link

@MicahZoltu

There is value in standardizing tokens so that an application (e.g., Wallet, exchange, etc.) can interact with any token the user provides without needing to know about it in advance or write custom integrations for each token.

Exactly. I'd like to be able to login with my uPort identity into Mist, use my Mist identity in Status, or log in with my Status identity on a ether play game or post a blog post in Steemit from my Aragon Company identity. Each one can be implemented differently, just keep some common interfaces.

@oed
Copy link
Contributor

oed commented Oct 3, 2017

This is very interesting and it overlaps a bunch with stuff we are doing with uport. Although we have a quite different design I think discussion and standardization around this will be very usefull. I'll give a breif description of our design before I go on.

As the base of our identity we use a very simple proxy contract, see also ERC: Proxy standard. This makes our system very flexible in terms of how you can control an identity.
To control a proxy contract we use a contract we call IdentityManager. The basic idea is that we want a single contract that multiple users can use to control their proxies, mostly to reduce gas cost. Here we have the ability to add multiple users etc, but this is something we want to iterate on in the future.
To issue and lookup claims we have a separate contract uport-registry. The basic idea here is that we want to separate the storing of the claims from the identity itself to a different contract.

I think this ERC touches two very interesting things, transaction execution and claim structures.

Transaction execution

The execute/approve looks promising and definitely something that should be used for high value transactions. e.g. transaction of > 100 eth needs to be aproved by my hardware wallet. But in the case of low value transactions it seems like a bit of overhead, e.g. I need to send two transactions in order to send a tweet on leeroy. Would be interesting to have a system where some execute are automatically approved.

Claims

We've opted for not storing claims in the identity contract itself, this makes it cheeper to depoy identities while claims can still be associated with the identity with the same level of security.
Another thing we have though a lot about is the privacy of claims. Right now there is basically no privacy for claims that are on-chain, which is basically a no-go for a lot of our use cases. Instead we are mostly using off-chain claims which also can be securely linked to the identity (proxy contract in our case). Of course we see the benefits of having on-chain claims as well, and standardization around the format of these is very useful, but they should be decoupled from the identity contract itself. Maybe the claim section could be put into a separate ERC?

@bneiluj
Copy link

bneiluj commented Oct 3, 2017

I agree with @Arachnid - 'keys' should refer to cryptographic key.

@frozeman Great initiative! This is so needed. It's a great step forward a standard for a self sovereign identity but it will not prevent people from creating more than one identity which is a no-go regarding KYC institution requirement process. Except if the identity public address is linked to multiple trustworthy services.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 3, 2017

@overdrev I’m not sure if a Claim permission process is needed, except when an entity wants to know the details of the claim, e.g. see the biometric data stored by the issuer. Then of course we need a async process. I have made some thoughts about that, but this is not really part of this ERC and can be a separate standard.

I see it as follows: claim data (referenced by ‘bytes claim’) is double encrypted by the issuer and me, if somebody wants to see the actual data they request it at the issuers ‘bytes _location’ and request the issuers part to be decrypted, then they come to me and ask for decrypting the second part, which i can always decline.

For b. I’m not sure how a single claim proof should look like, but interesting idea.

@oed thanks for participating, you guys should have actually started that standardization process ;)
Concerning your approaches:

Transaction execution: the excite function is mainly to act as your identity on the Blockchain in the least cases this contract should and will be used for storing and sending ether. If you want to move money and what that to be publicly visible and attached to your identity, use a multisig, or a wallet which is controlled by your keys from your identity .

Claim storage: I do understand you wanted to create a system which is cheap in gas, as uport will overtake most transaction costs in the beginning, but I don’t think this applies for a self owned standard, and would be the wrong approach to that. At the same time when a standard is found and a library is deployed, deploying a contract which uses that library is quite cheap.

Claims themself will be added by others, the owner of the identity will only pay for the confirmation. As I think A real used identity won’t attach every new app, or social network as new claim, those claim additions will be rather less. Things like this will be stored in other Reputation systems or uport like systems and can be attached as a self made claim to my identity, this way the identity can be kept rather raw. The “cool” stuff can happen on other experimental systems.

I’d say there are two main reasons why claims should be with the identity contract:

  1. It allows for on chain verifications and in the best case the contract, which wants to verify, only needs to call you identity once. He doesn’t have to go look on another address, or even outside of the BC. This allows for complex automated authentication systems purely running on the Blockchain.
  2. People want the feeling of having their things on one place, as funny as this sounds but it makes people feel more in control. It’s hard for people to acces their identity through registry contracts, if they don’t fully trust the registry. On top of that this standard allow for many different implementations of identities, which will all be able to create claims about each other.

There is probably more reasons, which don’t come to my mind now.

Concerning privacy: as the claim data is only meta data, the only viable information one can retrieve from your identity is: which claim issuer has claims about me (e.g. the German state, or Vitalik claims something about me), and when that data has changed.

This can be an issue, if I don’t want anybody to know I live or are German, but we share a lot more information on social networks daily. Also privacy focused claim provider can pop up, which claim things, like address etc globally, but are trusted by many. Then the only thing it leaks, is that you are privacy focused :)

@bneiluj people will have more than one identity for sure, as we just start to experiment with this, but once your have gone through the effort to get claims about biometric data and address, etc. you will treat this identity as more valueable. As long as you can add new claims of importance to more than one identity, that’s fine too. The person verifying your identity doesn’t need to care, as long as he can trust the claim issuer.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 3, 2017

@Arachnid I added a definitions section. I’m still open for better names for keys.

@Arachnid
Copy link
Contributor

Arachnid commented Oct 3, 2017

@frozeman Anything other than keys, really. I'd suggest 'principals', for instance.

It's still not clear to me what goes in this field. The definition says "public keys", but contracts don't have public keys. What would the 'key' for a contract be?

@alexvandesande
Copy link

@oed

I need to send two transactions in order to send a tweet on leeroy.

Actually I don't think that's how I would recommend. You can sign your tweet with any account, publish and say: "I am tweeting in behalf of foo.eth". Then the tweet app can check either that account is listed in one of these keys. No on-chain transaction required.

@jpitts
Copy link
Member

jpitts commented Oct 3, 2017

  1. Will the claimTypes enumeration be maintained as part of the standard?

  2. Claim location might be better represented as claim uri, even if it involves a hash. But is a URI scheme involving a hash defined for all cases? I saw a lot of discussions in IPLD / IPFS about URI schemes, and in that community it seems inconclusive.

Example discussion: ipfs/ipfs#227

https://en.wikipedia.org/wiki/Uniform_Resource_Identifier

@Wesley-Arrington
Copy link

Is the plan to allow claimTypes to not only be used to verify an identity but also to verify information about an identity?

claimTypes could be used to confirm accreditations from institutions, attendance at events and place of work. So for example if a decentralized Uber was created and this dApp only wanted drivers who had gone to driving school, then claimTypes could be used to confirm this. If the drivers received the proper claimType from a credible driving school they could be drivers for this decentralized application. So claimTypes if used this way could automate the process of checking the credentials of identities.

@MicahZoltu
Copy link
Contributor

MicahZoltu commented Oct 4, 2017

I understand that you want to keep the contents of the ERC "just the spec" but reading over all of the comments here I think the lack of a really clear problem statement and really clear and targeted solution is causing confusion. It sounds like there are several different interpretations of what this ERC is about in this discussion and everyone has a different image in their head as to what this will be used for.

@frozeman Can you provide a problem statement or user story as a starting point? Describe the problem that you are trying to solve (without describing the solution as part of the problem). I just tried to think of an example problem statement that requires this system but was unable to come up with one, which is why I'm struggling to understand the value of this being a standard. An example problem statement for a token standard (pre-ERC20) is:

I want to be able to build a smart wallet that can control any token the user desires, including future tokens that don't yet exist. The user needs to be able to transfer tokens into the wallet and out of the wallet without risk of the tokens being trapped in the wallet contract. Currently, each token has a slightly different API so it is not possible to build a wallet without designing it to support each token, and such a wallet would not support future tokens (with as of yet unknown APIs).

Note: Be prepared for me to offer alternative solutions to your problem statement that don't involve a standard. 😉

@frozeman
Copy link
Contributor Author

frozeman commented Oct 4, 2017

@jpitts thanks for sharing.
I would suggest coming up with a set of claimTypes and new standard additions can come up with new ones, that’s why it’s a uint256. We could also leave the type description out of here and make that a totally different standard.

URI makes sense, I will change that and also change it for a string for now.

@CDsigma your use case it exactly right, you can have people and institutions claiming things about you, and you can allow those claims attached to your identity. And yes; you can never verify an identity if you don’t verify claims about it.

@MicahZoltu I agree that it doesn’t seem to catch on right away what the use of this ERC is, though I brought already a few exmpakes which cover your points. But I can try to reformulate:

  • see KYC, currently everybody collects all information about you separately, to make sure they know who you are. E.g. banks, credit services, or any service which needs to have KYC. A standard will help in so far that everybody can auto check certain clams, and therefore don’t need to store your actually details about you anymore, as they - as long as they trust the claim issuer - don’t need to have the actual information. The current overcollecting is because of lack of a better system.
  • imagine you want to prove you are over eighteen. A trusted entity can add a bit ask as claim, which contains a bit that states that’s you are over eigtheen without revealing your age. Again the trust here is moved to the claim issuer, rather than the person want to prove something about themselves. In large th is can create complex trust graphs.

There are plenty more, and all come down to yourself wanting to prove something in front of others. And the claim model solves that: you can also take a look at https://sovrin.org/wp-content/uploads/2017/06/The-Inevitable-Rise-of-Self-Sovereign-Identity.pdf as they describe a similar system.

So in short the solution the ERC brings:

  1. I want to prove something
  2. Everybody can verify claims, as they know how and where to look - automatically.
  3. This can go as deep as it needs to reach a trusted claim issuer (jumping from issuer to issuer)
  4. Your identity can be taken to any interface which needs an identity, without creating a new one for every app.
  5. Smart contracts can verify claims automatically
  6. You can act outside of the Blockchain and third parties can check your identity on chain.

I am not aware of any system, which doesn’t require a central authority that allows to create a self sovereign identity. And I am unclear how this can be solved without a standard.

The token standard is quite the same. Everybody could have made their own tokens, but only by creating a standard we are able to use them anywhere, and with erc223 we will be able to have those tokens interact. And as you brought up ERC20 a lot, I assume you are aware that I proposed that standard.

Also for this standard, the target is not mainly the UIs, but other identities and smart contracts. Though UIs are as important, to be able to take your identity around.

@oed
Copy link
Contributor

oed commented Oct 4, 2017

@frozeman
Sorry I think I missunderstood what you are trying to do. Let me see if I understand correctly now.
Transaction execution: So this is more something along the lines of an identitfier for an identity that you can attach accounts to? It would mostly be used to attach claims to and send claims from. Uport are trying to come up with something similar, but without relying as much on on-chain logic to do so. Check out the work of the Decentralized Identity Foundation, in particular the DID spec which uport will be compatible with.

Claim storage: So this will be kind of like a personal registry of claims associated with your identity? If it's only meta data that is being stored on-chain, where would the claim itself be stored?

Right now claims are stored off-chain by the users themself in uport. One of the main reason for putting a claim on-chain would be if it needs to be verified by a smart contract. The smart contract is likely to want to know something about a particular account that it is interacting with, rather than the identity itself. Having the claims in a separate registry makes it possible to make claims on any kind of account. Not just this very specific identity contract. This opens upp for the possiblitity of proving something about an account with a zkp without revelaing which identity owns that account.

As for your two main reasons for keeping it in the identity contract:

  1. I don't really see a problem of having to look at another contract, as long as it's standardized, maybe accessable from a ENS record? Complex automated auth will still be very much possible.
  2. The end user will not know or care about how many contracts are involved. The end user will likely not even know what a smart contract is. The registry would of course be designed so it can be interacted with in a trust-less way.

This being said I can see some benefits of putting claims in an identity contract, but for the reasons I stated above I don't think that's the way to go.

Btw, you should also check out the work being done on verifiable claims

@frozeman
Copy link
Contributor Author

frozeman commented Oct 4, 2017

@oed thanks for the links, that looks very interesting and is very similar to what i am trying to do here as well, but with a purely on chain logic. What i can see every body in this space has come up with, is attributes, or claims and keys as actors. Same as me.

Let me try to break down the contract:

-> keys: public keys, or other owned smart contract address, which can interact in your name

- keys are there to prove identity ownership
- keys can hold money and act on the blockchain, and can be traced back to this identity
- smart contracts owned by this identity can be extension systems to the identity, e.g. reputation systems

-> execute: A function to allow this identity to act directly on other smart contracts, to be an actor "on-chain", including holding and transfer of ether.

-> claims: can be added by others, and verified by others. The claim content is stored off-chain, or onchain, but this is not defined here. Important is that the claim has to a have a proofable piece (which here is the signature) and a link to the claim, as well as the issuer.

- claims can requested to be added by anyone.
- claims can only be approved to be added by the owner of this identity
- claims can be removed at any time by the owner of this identity
- claims can be altered by the issuer, punishment would be removal (OR we add approval from the owner as well)

To compare that to the DID, its similar, just that its all in a smart contract and verifiable on chain.

To compare that with the W3C verifiable claims, its basically the same, though we can try to align them even more.

Also to be clear this is not standardising how claims can look like, how the content is stored, or where. Claims can easily be DDOs for example stored on IPFS. Also how identity verifications are handled off chain, e.g how the message will look like when signing off chain and including your identity address on chain. So there is a lot of defining necessary. This ERC mainly should give a very slick framework to put all those claims and claimtypes and keys inside.

Concerning the registry and the identity object (DID vs. DDOs), there can sure be a registry on top which holds the addresses of many identity contracts, e.g. governments could this way group citizens etc. but i don't see a need for that in the basic identity spec.

I am open for a call, to discuss that in person, as i see some misconceptions, or i myself have some.

@lukehedger
Copy link

We've been researching and prototyping a solution for identity in the META Network for the last few months and make use of a lot of the same primitives in this proposal and other projects. Our current implementation uses the ENS to register a subdomain to an identity owner's public address, which resolves to a content-addressed object (eg. stored in Swarm, IPFS) where the identity's metadata (or claims) can be retrieved and verified against signatures on that data. This way we utilise an existing standard and minimise what is stored on-chain.

Given how much of an essential component identity is to a system or network, it would be great to see a flexible standard that developers could build on - we know first-hand how complex this can be! If it can incorporate/accommodate other efforts (like W3C standards) then all the better.

@frozeman
Copy link
Contributor Author

frozeman commented Oct 5, 2017

@lukehedger looking forward to contributions.

I just had a fruitful in person discussion with @oed and we came upon with a few small alterations:

  • I removed the changeClaim, as addClaim will do the same, and SHOULD trigger already the approval process.
  • i added getKeyType function and getKeysByType, as well as getClaim and getClaimsByType to allow easy retrieval.
  • I added more key types 3: claim signer, 4: encryption key, which we can debate to change them or add more.
  • i added the bytes claim to the signature of the claim, so that it can't be altered by the claim holder.
  • We were thinking how this idenities could be converted to DDOs (DID descriptor objects), see https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-fall2016/blob/master/draft-documents/DID-Spec-Implementers-Draft-01.pdf for examples of DDOs
  • We were talking if its best to move the claim holder part (Identity verification in the spec), to a separate spec, which this spec then inherits. The reasoning is that there can be claim holders, which aren't themselves identities. E.g. a smart contract about which a validity claim is issued.

It would be really good if work on the holder spec is done first, so that its a good basis, for #725. I will create an issue to discuss this spec part in the coming days.

@m-schmoock
Copy link

m-schmoock commented Oct 5, 2017

@frozeman
I like the proposal, also, as already pointed out in this discussion, I would see the need to define a standard set of claimTypes. This can be done by defining a low-range of well known types: i.e. 0 - arbitrary_number also to be defined in this ERC). As the number 256 Bit number is big enough, we could also think about using a bit-mask to organize topics and sub-types or even claim multiple types as once... just a thought.

I also think some details are missing regarding the claim (bytes) storage and access.

... Also a question for a better undestanding:
Regarding the approve function, can you hint out what do you mean by "Triggers on successfull claim addition Event"

Does it mean that if the approve was called by the identity itself or a type 1/2 key, the approve function is automatically called by the Contract, as a self verified claims do not need to be approved? If so, please point that out.

@frozeman
Copy link
Contributor Author

frozeman commented Dec 12, 2019

@3esmit thanks for you feedback, those are actually good points.

I do think separating execute and the get/set data could make sense.
Though I think the owner should be in here, as otherwise its unclear who is allowed to set data. The owner can be set to no one, if its data that should be immutable.

As a use case like a digital certificate, which might have data that can be set - the execute function might not be necessary. But doesn't bother either, maybe such virtual asset will need to execute in the future, triggered by its owner??

I assume most assets/accounts will not need have custom erc725 version but use a deployed library contract, which makes the cost roughly 32k gas.

So I am a bit torn about separating into multiple standards, as this standard can be used for accounts, items, objects etc.

You separation of functions is a good point. i think separating at least create and call is important. but i would call call still execute, as this smart contract executes.
Whats your opinion on that?

In short:

  • separation of execute and getData/setData: maybe -> perhaps an ERC725A/B/C to not create confusion with all those ERC numbers
  • split execute: yes
  • name it call or execute? hm input please

@3esmit
Copy link
Contributor

3esmit commented Dec 12, 2019

The problem with using call is that solidity also uses call for the native type address, and might be confusing or misleading. However, call describes exactly what is the function.
execute is fine, it don't exactly describes de EVM behavior, but it describes the intended use of the function.

@3esmit
Copy link
Contributor

3esmit commented Dec 19, 2019

@frozeman I found out a good way to future proof the universal "execute" interface: function execute(bytes calldata _execData) external

For exampl, a minimal ERC725 implementation with this interface:

pragma solidity >=0.5.0 <0.6.0;

contract MinimalAccount {
    event DataChanged(bytes32 indexed key, bytes value);
    event OwnerChanged(address indexed ownerAddress);
    address public owner;
    mapping(bytes32 => bytes) store;

    modifier onlyOwner {
        require(msg.sender == address(owner), "Not authorized");
        _;
    }

    modifier self {
        require(msg.sender == address(this), "Not authorized");
        _;
    }

    constructor() public {
        owner = msg.sender;
    }

    function execute(
        bytes calldata _execData
    )
        external
        onlyOwner
        returns (bool success, bytes memory returndata)
    {
        (success, returndata) = address(this).call(_execData);
    }

    function call(
        address _to,
        bytes calldata _data
    )
        external
        self
        returns (bool success, bytes memory returndata)
    {
        (success, returndata) = _to.call(_data);
    }

    function setData(bytes32 _key, bytes calldata _value)
        external
        self
    {
        store[_key] = _value;
        emit DataChanged(_key, _value);
    }

    function changeOwner(address newOwner)
        external
        self
    {
        require(newOwner != address(0), "Bad parameter");
        owner = newOwner;
        emit OwnerChanged(newOwner);
    }

    function getData(bytes32 _key)
        external
        view
        returns (bytes memory _value)
    {
        return store[_key];
    }
}

In this MinimalAccount, only the "call" method is implemented, but its easy to support other types, like delegatedCall, create, create2, approveAndCall, and whatever comes in mind.

The execute(bytes) interface must be protected in a way that only the owner of the account can use it, which will be also who know what it can or cannot call.

In order to wallets list what an proxy account can or cannot perform under execute, ERC165 could be used, but try and gasEstimate error is also a possibility.

@3esmit
Copy link
Contributor

3esmit commented Dec 19, 2019

The final ERC725 I would suggest to be slim into the needed fields, which are:

interface ERC725 {
    event DataChanged(bytes32 indexed key, bytes value);

    function execute(bytes calldata _execData) external returns (bool success, bytes memory returndata);
    function getData(bytes32 _key) external view returns (bytes memory _value);
    function setData(bytes32 _key, bytes calldata _value) external;
}

I think is interesting to execute(bytes) having returns(bool,bytes), not having this might be limiting to some use case.

changeOwner(address), owner() and call(address,uint256,bytes) could be part of this standard if we agree that this is fundamental to accounts, but I don't see a good reason for that.

@m1cm1c
Copy link

m1cm1c commented Jun 6, 2020

I have a different problem with the execute function. I want to separate authorization of a transaction from paying the transaction fee. This is important in avoiding having to acquire a bank license or similar license where I live if you want to provide your users with the ability to issue transactions. It also generally makes sure that users don't steal your eth if you'd otherwise need to provision their addresses with gas money so they can issue entire Ethereum transactions themselves.

What I've come up with is this interface:

function executionNonce() public pure returns (uint256)
function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data) external onlyOwner
function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data, bytes calldata _signature) external

Note that the established execution function is still present. The second execution function can be called not only by the owner but by anyone. However, the calling party is required to produce a signature over the following structure:

abi.encodePacked(_operationType, _to, _value, _data, address(this), executionNonce)

This signature can only be generated by the owner. But being able to generate it does not require controlling a funded address. Therefore (along with a constructor allowing to set the owner explicitly), it is possible to have an identity contract that is fully controlled by an unfunded address.

Note that the signed structure includes a nonce. This is to eliminate replay attacks. Furthermore, it contains the identity contract's address to foil attacks where the attacker replays transactions previously issued via a different identity contract with the same owner.

As @3esmit's proposal has not yet been commented on by @frozeman, I built my proposal on the execution function stated in the opening post. However, my proposal can easily be modified to be compatible with his.

@frozeman
Copy link
Contributor Author

frozeman commented Jun 9, 2020

Thanks guys for the write up. I was incredible busy and still am, due to the Reversible ICO that just started for LUKSO.

This standard is instrumental for LUKSO, so I am very interested in finalizing it.

Here my short comments (longer will follow when I have more time)
@3esmit i like the universality of you’re execute function, but in my proposal it is mainly needed to talk to other contracts. Not to itself.

@m1cm1c it’s a good idea, but I am not sure if it should be part of this standard, as my idea here was that any permission system, or relay system could be added to the owner smart contract and this way be upgradable.

@forshtat
Copy link
Contributor

Hello @frozeman!

We are considering using the ERC-725 for the proxy account used in the GSN.

The GSN is a comprehensive modular meta-transactions network you can read about the previous version here and about the upcoming version 2.0 on our website

This is an almost 3 years long discussion here so I would be grateful if you could help me find up-to-date answers to a few questions to see if the proposed standard is a good choice for us. I hope we can prevent the creation of yet another Proxy Account EIP, and thank you for you time in advance :-)

  1. What is the status of this ERC? I see it was not modified for some time, but the status is still 'Draft'. Who are the parties promoting the ERC now?

  2. The ERC describes the motivation as "a minimal interface for an proxy account allows third parties to interact with various proxy accounts contracts in a consistent manner". I did not find any rationale for the key/value storage interface being bundled with the account proxy interface.
    To elaborate, there is no application for this functionality in the GSN the way we currently see it, so one could argue this functionality is not exactly 'minimal'. Would you consider declaring these methods optional to prevent implementations such as ours from being non-standard?

  3. The ERC mentions "This owner should be the only msg.sender that is allowed to call execute or setData." In GSN, the msg.sender is meaningless and instead the last 20 bytes of msg.data are treated as authenticated sender address. This approach is described in ERC-1613.
    Would you consider mentioning such approach as a way to enable meta-transactions as part of the core ERC?

@frozeman
Copy link
Contributor Author

frozeman commented Jun 22, 2020

Hey @forshtat happy to hear that you are considering this.
Lets have a call so i can better understand how you plan to integrate it. I pinged you in telegram.

To your questions:

  1. Its still in draft because I don't feel like it has enough adoption yet to lock it down. There are many interested parties and it has integrations in some places, but I have now overview, besides whats on https://erc725alliance.org

  2. The key value store is IMO super important as it makes it flexible about what kind of information can be attached to this account. From a profile image, to usernames, to links to token or reputation systems. It can be fully extended and grow to more than just an account holding assets.
    I am also using ERC725 as the basis for digital certificates, and the key value store is super important here as well. It gives us an extra layer of standardisation that can follow after adoption of those account types.

  3. I would be down for accepting signed tx, but the idea was that this is happening outside in an owner contract, which can then be upgradeable.
    One of the most important issues is the ability to improve security of accounts over time, and making the owner a smart contract allows for that.

Reach out to me on telegram @frozeman, and we can discuss your ideas.

@frozeman
Copy link
Contributor Author

Also @forshtat feel free to join the LUKSO discord as we are discussing 725 there in the standards channel: https://discord.gg/E2rJPP4

@frozeman
Copy link
Contributor Author

frozeman commented Jun 23, 2020

As I realize that were have sometime different understandings of what this ERC tries to achieve, i added a list to the motivation section:

The smart contract account SHOULD be:

  • able to hold any asset (native token, e.g. ERC20 like tokens) (execute() function can move those)
  • able to execute any smart contract (execute() function)
  • have upgradeable security (through owner change, e.g. to a gnosis safe) (owner and changeOwner() function)
  • be basic enough to work for for a long time (execute function)
  • flexible enough to allow future use cases that are unclear today (extensibility through the get/setData, which can link to new contracts that are owned by this one) (getDate(), setData() function)

@frozeman
Copy link
Contributor Author

frozeman commented Jun 27, 2020

After implementing this standard for two uses cases: LUKSOs digital certificates (NFT2.0) and LUKSO smart contract based accounts, I think it is necessary to split this standard in two. I think this will be a very welcome change, as now both can be used individually without confusion.

UPDATED edited to reflect the addition of ERC173

ERC725X: (x like execute)
ERC165 identifier: 0x44c028fe

    event ContractCreated(address indexed contractAddress);

    function execute(uint256 _operationType, address _to, uint256 _value, bytes memory data) external;

ERC725Y: (y like why, give me information)
ERC165 identifier: 0x2bd57b73

    event DataChanged(bytes32 indexed key, bytes value);

    function getData(bytes32 key) external view returns (bytes memory value);
    function setData(bytes32 key, bytes memory value) external;

ERC725 would then refer to both being implemented ERC725X and ERC725Y, and contract should return both interface Ids.

Any contract can either implement ERC725X, ERC725Y, or both.

@frozeman
Copy link
Contributor Author

frozeman commented Jun 27, 2020

Two proposals to dicusss:

  1. To be future proof, do we want execute to return returns(bytes) as future systems could potentially display the return value of transactions, and owner smart contracts can react on the return values.

2. event OwnerChanged(address indexed ownerAddress); should be event OwnerChanged(address indexed oldOwner, address indexed newOwner);, to be not ambiguous.

Btw the latter is important as it will change the 165 interface ID for both sub standards

@frozeman
Copy link
Contributor Author

frozeman commented Jun 27, 2020

I just discovered https://eips.ethereum.org/EIPS/eip-173, it makes obviously sense that ERC725 uses ERC173.
As its the same functions as we have here, just with different naming.

interface ERC173 /* is ERC165 */ {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    function owner() view external;
    function transferOwnership(address _newOwner) external;	
}

A full ERC725 then is made up of:
ERC725 = ERC173 + ERC725X + ERC725Y 🦾

@frozeman
Copy link
Contributor Author

frozeman commented Jun 27, 2020

One addition to ERC725Y that should be discussed could be:

bytes32[] public storeKeys;

function storeCount() public view returns (uint256) {
        return storeKeys.length;
    }

// the setData will also store the keys in the `storeKeys array`

As this would make it easily possible for an interface to list all key value pairs easily.

@frozeman
Copy link
Contributor Author

The top issues is updated and lates implementation can be found here:
https://github.com/lukso-network/standards-scenarios/tree/develop/contracts/_ERCs

@frozeman
Copy link
Contributor Author

What are thoughts about an execute event?

@frozeman
Copy link
Contributor Author

frozeman commented Jul 2, 2020

The data key for keys with multiple elements was changed to:

This would looks as follows for `ERCXXXMyNewKeyType[]` (keccak256: `0x4f876465dbe22c8495f4e4f823d846957ddb8ce6006afe66ddc5bac4f0626767`): 
- element number: key: `0x4f876465dbe22c8495f4e4f823d846957ddb8ce6006afe66ddc5bac4f0626767`, value: `0x0000000000000000000000000000000000000000000000000000000000000002` (2 elements)
- element 1: key: `0x4f876465dbe22c8495f4e4f823d8469500000000000000000000000000000000`, value: `0x123...` (element 0)
- element 2: key: `0x4f876465dbe22c8495f4e4f823d8469500000000000000000000000000000001`, value: `0x321...` (element 1)
...

@frozeman
Copy link
Contributor Author

frozeman commented Jul 9, 2020

The first erc725 package BETA is released:
https://www.npmjs.com/package/erc725

@jaredweinfurtner
Copy link

jaredweinfurtner commented Sep 9, 2020

What are thoughts about an execute event?

Was the idea meant to allow calling other contracts who have added msg.sender permissions/logic so that the address comes from the identity contract and not the tx.origin?

@frozeman
Copy link
Contributor Author

@jaredweinfurtner yes

Note: I changed the proposed key ERC725Type to SupportedStandards. See document above.

@github-actions
Copy link

github-actions bot commented Mar 5, 2022

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Mar 5, 2022
@github-actions
Copy link

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

@AnthonyAkentiev
Copy link

@frozeman Hi Fabian. What is the current status of the ERC725 tokens? Are they even used today? Asking also because of the recent Soulbound Tokens (SBTs) "hype". Thank you very much!

@Pandapip1
Copy link
Member

ERC-725 is still a draft, and should not be used in production applications: https://eips.ethereum.org/EIPS/eip-725

@ethereum ethereum locked and limited conversation to collaborators Feb 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests