ERC-1484: Digital Identity Aggregator
NoahZinsmeister opened this issue · comments
Official ERC-1484 Discussion Forum
- The full text of this EIP follows, and is also available as a markdown file
- The reference implementation is available here
- Documentation on best practices for this ERC can be found here
EIP | 1484 |
Title | Digital Identity Aggregator |
Author | Anurag Angara anurag.angara@gmail.com Andy Chorlian andychorlian@gmail.com Shane Hampton shanehampton1@gmail.com Noah Zinsmeister noahwz@gmail.com |
Discussions-To | #1495 |
Status | Draft |
Type | Standards Track |
Category | ERC |
Created | 2018-10-12 |
Requires | 191 |
Simple Summary
A protocol for aggregating digital identity information that's broadly interoperable with existing, proposed, and hypothetical future digital identity standards.
Abstract
This EIP proposes an identity management and aggregation framework on the Ethereum blockchain. It allows entities to claim an Identity
via a singular Identity Registry
smart contract, associate it with Ethereum addresses in a variety of meaningful ways, and use it to interact with smart contracts. This enables arbitrarily complex identity-related functionality. Notably (among other features) ERC-1484 Identities
: are self-sovereign, can natively support ERC-725 and ERC-1056 identities, are DID compliant, and can be fully powered by meta-transactions.
Motivation
Emerging identity standards and related frameworks proposed by the Ethereum community (including ERCs/EIPs 725, 735, 780, 1056, etc.) define and instrumentalize digital identity in a variety of ways. As existing approaches mature, new standards emerge, and isolated, non-standard approaches to identity develop, coordinating on identity will become increasingly burdensome for blockchain users and developers, and involve the unnecessary duplication of work.
The proliferation of on-chain identity solutions can be traced back to the fact that each codifies a notion of identity and links it to specific aspects of Ethereum (claims protocols, per-identity smart contracts, signature verification schemes, etc.). This proposal eschews that approach, instead introducing a protocol layer in between the Ethereum network and individual identity applications. This solves identity management and interoperability challenges by enabling any identity-driven application to leverage an un-opinionated identity management protocol.
Definitions
-
Identity Registry
: A single smart contract which is the hub for allIdentities
. The primary responsibility of theRegistry
is to define and enforce the rules of a global namespace forIdentities
, which are individually denominated by Ethereum Identification Numbers (EINs). -
Identity
: A data structure containing all the core information relevant to an identity, namely: aRecovery Address
, anAssociated Addresses
set, aProviders
set, and aResolvers
set.Identities
are denominated by EINs (incrementinguint
identifiers starting at 1), which are unique but otherwise uninformative. EachIdentity
is a Solidity struct:
struct Identity {
address recoveryAddress;
AddressSet.Set associatedAddresses;
AddressSet.Set providers;
AddressSet.Set resolvers;
}
-
Associated Address
: An Ethereum address publicly associated with anIdentity
. In order for an address to become anAssociated Address
, anIdentity
must either transact from or produce an appropriately signed message from the candidate address and an existingAssociated Address
, indicating intent to associate. AnAssociated Address
can be removed from anIdentity
by transacting/producing a signature indicating intent to disassociate. A given address may only be anAssociated Address
for oneIdentity
at any given time. -
Provider
: An Ethereum address (typically but not by definition a smart contract) authorized to act on behalf ofIdentities
who have authorized them to do so. This includes but is not limited to managing theAssociated Address
,Provider
, andResolver
sets for anIdentity
.Providers
exist to facilitate user adoption by making it easier to manageIdentities
. -
Resolver
: A smart contract containing arbitrary information pertaining toIdentities
. A resolver may implement an identity standard, such as ERC-725, or may consist of a smart contract leveraging or declaring identifying information aboutIdentities
. These could be simple attestation structures or more sophisticated financial dApps, social media dApps, etc. EachResolver
added to anIdentity
makes theIdentity
more informative. -
Recovery Address
: An Ethereum address (either an account or smart contract) that can be used to recover lostIdentities
as outlined in the Recovery section. -
Destruction
: In the event of irrecoverable loss of control of anIdentity
,Destruction
is a contingency measure to permanently disable theIdentity
. It removes allAssociated Addresses
,Providers
, and optionallyResolvers
while preserving theIdentity
. Evidence of the existence of theIdentity
persists, while control over theIdentity
is nullified.
Specification
A digital identity in this proposal can be viewed as an omnibus account, containing more information about an identity than any individual identity application could. This omnibus identity is resolvable to an unlimited number of sub-identities called Resolvers
. This allows an atomic entity, the Identity
, to be resolvable to abstract data structures, the Resolvers
. Resolvers
recognize Identities
by any of their Associated Addresses
, or by their EIN
.
The protocol revolves around claiming an Identity
and managing Associated Addresses
, Providers
and Resolvers
. Identities can delegate much or all of this responsibility to one or more Providers
, or perform it directly from an Associated Address
. Associated Addresses
/Providers
may add and remove Resolvers
and Providers
indiscriminately. Associated Addresses
may only be added or removed with the appropriate permission.
Identity Registry
The Identity Registry
contains functionality to create new Identities
and for existing Identities
to manage their Associated Addresses
, Providers
, and Resolvers
. It is important to note that this registry fundamentally requires transactions for every aspect of building out an Identity
. However, recognizing the importance of accessibility to dApps and identity applications, we empower Providers
to build out Identities
on the behalf of users, without requiring users to pay gas costs. An example of this pattern, often referred to as a meta transactions, can be seen in the reference implementation.
Due to the fact that multiple addresses can be associated with a given identity (though not the reverse), Identities
are denominated by EIN
. This uint
identifier can be encoded in QR format or mapped to more user-friendly formats, such as a string
, in registries at the Provider
or Resolver
level.
Address Management
The address management function consists of trustlessly connecting multiple user-owned Associated Addresses
to an Identity
. It does not give special status to any particular Associated Address
, rather leaving this (optional) specification to identity applications built on top of the protocol - for instance, management
, action
, claim
and encryption
keys denominated in the ERC-725 standard, or identifiers
and delegates
as denominated in ERC-1056. This allows a user to access common identity data from multiple wallets while still:
- retaining the ability to interact with contracts outside of their identity
- taking advantage of address-specific permissions established at the application layer of a user's identity.
Trustlessness in the address management function is achieved through a robust permissioning scheme. To add an Associated Address
to an Identity
, implicit permission from a transaction sender or explicit permission from a signature is required from 1) an address already within the registry and 2) an address to be claimed. Importantly, the transaction need not come from any particular address, as long as permission is established, which allows not only users but third parties (companies, governments, etc.) to bear the overhead of managing identities. To prevent a compromised Associated Address
from unilaterally removing other Associated Addresses
, it's only possible to remove an Associated Address
by transacting or producing a signature from it.
All signatures required in ERC-1484 are designed per the ERC-191 v0 specification. To avoid replay attacks, all signatures must include a timestamp within a rolling lagged window of the current block.timestamp
. For more information, see this best practices document in the reference implementation.
Provider Management
While the protocol allows users to directly call identity management functions, it also aims to be more robust and future-proof by allowing Providers
, typically smart contracts, to perform identity management functions on a user's behalf. A Provider
set by an Identity
can perform address management and resolver management functions by passing a user's EIN
in function calls.
Resolver Management
A Resolver
is any smart contract that encodes information which resolves to an Identity
. We remain agnostic about the specific information that can be encoded in a resolver and the functionality that this enables. The existence of Resolvers
is primarily what makes this ERC an identity protocol rather than an identity application. Resolvers
resolve abstract data in smart contracts to an atomic entity, the Identity
.
Recovery
If users lose control over an Associated Address
, the Recovery Address
provides a fallback mechanism. Upon Identity
creation, a Recovery Address
is passed as a parameter by the creator. Recovery functionality is triggered in three scenarios:
1. Changing Recovery Address: If a recovery key is lost, an Associated Address
/Provider
can triggerRecoveryAddressChange/triggerRecoveryAddressChangeFor. To prevent malicious behavior from someone who has gained control of an Associated Address
or Provider
and is changing the Recovery Address
to one under their control, this action triggers a 14 day challenge period during which the old Recovery Address
may reject the change by triggering recovery. If the Recovery Address
does not reject the change within 14 days, the Recovery Address
is changed.
2. Recovery: Recovery occurs when a user recognizes that an Associated Address
or the Recovery Address
belonging to the user is lost or stolen. In this instance the Recovery Address
must call triggerRecovery. This removes all Associated Addresses
and Providers
from the corresponding Identity
and replaces them with an address passed in the function call. The Identity
and associated Resolvers
maintain integrity. The user is now responsible for adding the appropriate un-compromised addresses back to their Identity
.
Importantly, the Recovery Address
can be a user-controlled wallet or another address, such as a multisig wallet or smart contract. This allows for arbitrarily sophisticated recovery logic! This includes the potential for recovery to be fully compliant with standards such as DID.
3. Destruction
The Recovery scheme offers considerable power to a Recovery Address
; accordingly, Destruction
is a nuclear option to combat malicious control over an Identity
when a Recovery Address
is compromised. If a malicious actor compromises a user's Recovery Address
and triggers recovery, any address removed in the Recovery
process can call triggerDestruction within 14 days to permanently disable the Identity
. The user would then need to create a new Identity
, and would be responsible for engaging in recovery schemes for any identity applications built in the Resolver
or Provider
layers.
Alternative Recovery Considerations
We considered many possible alternatives when devising the Recovery process outlined above. We ultimately selected the scheme that was most un-opinionated, modular, and consistent with the philosophy behind the Associated Address
, Provider
, and Resolver
components. Still, we feel that it is important to highlight some of the other recovery options we considered, to provide a rationale as to how we settled on what we did.
High Level Concerns
Fundamentally, a Recovery scheme needs to be resilient to a compromised address taking control of a user's Identity
. A secondary concern is preventing a compromised address from maliciously destroying a user's identity due to off-chain utility, which is not an optimal scenario, but is strictly better than if they've gained control.
Alternative 1: Nuclear Option
This approach would allow any Associated Address
to destroy an Identity
whenever another Associated Address
is compromised. While this may seem severe, we strongly considered it because this ERC is an identity protocol, not an identity application. This means that though a user's compromised Identity
is destroyed, they should still have recourse to whatever restoration mechanisms are available in each of their actual identities at the Resolver
and/or Provider
level. We ultimately dismissed this approach for two main reasons:
- It is not robust in cases where a user has only one
Associated Address
- It would increase the frequency of recovery requests to identity applications due to its unforgiving nature.
Alternative 2: Unilateral Address Removal via Providers
This would allow Associated Addresses
/Providers
to remove Associated Addresses
without a signature from said address. This implementation would allow Providers
to include arbitrarily sophisticated schemes for removing a rogue address - for instance, multi-sig requirements, centralized off-chain verification, user controlled master addresses, deferral to a jurisdictional contract, and more. To prevent a compromised Associated Address
from simply setting a malicious Provider
to remove un-compromised addresses, it would have required a waiting period between when a Provider
is set and when they would be able to remove an Associated Address
. We dismissed this approach because we felt it placed too high of a burden on Providers
. If a Provider
offered a sophisticated range of functionality to a user, but post-deployment a threat was found in the Recovery logic of the provider, Provider
-specific infrastructure would need to be rebuilt. We also considered including a flag that would allow a user to decide whether or not a Provider
may remove Associated Addresses
unilaterally. Ultimately, we concluded that only allowing removal of Associated Addresses
via the Recovery Address
enables equally sophisticated recovery logic while separating the functionality from Providers
, leaving less room for users to relinquish control to potentially flawed implementations.
Rationale
We find that at a protocol layer, identities should not rely on specific claim or attestation structures, but should instead be a part of a trustless framework upon which arbitrarily sophisticated claim and attestation structures may be built.
The main criticism of existing identity solutions is that they're overly restrictive. We aim to limit requirements, keep identities modular and future-proof, and remain un-opinionated regarding any functionality a particular identity component may have. This proposal gives users the option to interact on the blockchain using an robust Identity
rather than just an address.
Implementation
The reference implementation for ERC-1484 may be found in NoahZinsmeister/ERC-1484.
identityExists
Returns a bool
indicating whether or not an Identity
denominated by the passed EIN
exists.
function identityExists(uint ein) public view returns (bool);
hasIdentity
Returns a bool
indicating whether or not the passed _address
is associated with an Identity
.
function hasIdentity(address _address) public view returns (bool);
getEIN
Returns the EIN
associated with the passed _address
. Throws if the address is not associated with an EIN
.
function getEIN(address _address) public view returns (uint ein);
isAssociatedAddressFor
Returns a bool
indicating whether or not the passed _address
is associated with the passed EIN
.
function isAssociatedAddressFor(uint ein, address _address) public view returns (bool);
isProviderFor
Returns a bool
indicating whether or not the passed provider
has been set by the passed EIN
.
function isProviderFor(uint ein, address provider) public view returns (bool);
isResolverFor
Returns a bool
indicating whether or not the passed resolver
has been set by the passed EIN
.
function isResolverFor(uint ein, address resolver) public view returns (bool);
getIdentity
Returns the recoveryAddress
, associatedAddresses
, providers
and resolvers
of the passed EIN
.
function getIdentity(uint ein) public view
returns (
address recoveryAddress,
address[] memory associatedAddresses, address[] memory providers, address[] memory resolvers
);
createIdentity
Creates an Identity
, setting the msg.sender
as the sole Associated Address
. Returns the EIN
of the new Identity
.
function createIdentity(address recoveryAddress, address[] memory providers, address[] memory resolvers)
public returns (uint ein);
Triggers event: IdentityCreated
createIdentityDelegated
Preforms the same logic as createIdentity
, but can be called by any address. This function requires a signature from the associatedAddress
to ensure their consent.
function createIdentityDelegated(
address recoveryAddress, address associatedAddress, address[] memory providers, address[] memory resolvers,
uint8 v, bytes32 r, bytes32 s, uint timestamp
)
public returns (uint ein);
Triggers event: IdentityCreated
addAssociatedAddress
Adds the addressToAdd
to the EIN
of the approvingAddress
. The msg.sender
must be either of the approvingAddress
or the addressToAdd
, and the signature must be from the other one.
function addAssociatedAddress(
address approvingAddress, address addressToAdd, uint8 v, bytes32 r, bytes32 s, uint timestamp
)
public
Triggers event: AssociatedAddressAdded
addAssociatedAddressDelegated
Adds the addressToAdd
to the EIN
of the approvingAddress
. Requires signatures from both the approvingAddress
and the addressToAdd
.
function addAssociatedAddressDelegated(
address approvingAddress, address addressToAdd,
uint8[2] memory v, bytes32[2] memory r, bytes32[2] memory s, uint[2] memory timestamp
)
public
Triggers event: AssociatedAddressAdded
removeAssociatedAddress
Removes the msg.sender
as an Associated Address
from its EIN
.
function removeAssociatedAddress() public;
Triggers event: AssociatedAddressRemoved
removeAssociatedAddressDelegated
Removes the addressToRemove
from its associated EIN
. Requires a signature from the addressToRemove
.
function removeAssociatedAddressDelegated(address addressToRemove, uint8 v, bytes32 r, bytes32 s, uint timestamp)
public;
Triggers event: AssociatedAddressRemoved
addProviders
Adds an array of Providers
to the Identity
of the msg.sender
.
function addProviders(address[] memory providers) public;
Triggers event: ProviderAdded
addProvidersFor
Preforms the same logic as addProviders
, but must be called by a Provider
.
function addProvidersFor(uint ein, address[] memory providers) public;
Triggers event: ProviderAdded
removeProviders
Removes an array of Providers
from the Identity
of the msg.sender
.
function removeProviders(address[] memory providers) public;
Triggers event: ProviderRemoved
removeProvidersFor
Preforms the same logic as removeProviders
, but is called by a Provider
.
function removeProvidersFor(uint ein, address[] memory providers) public;
Triggers event: ProviderRemoved
addResolvers
Adds an array of Resolvers
to the EIN
of the msg.sender
.
function addResolvers(address[] memory resolvers) public;
Triggers event: ResolverAdded
addResolversFor
Preforms the same logic as addResolvers
, but must be called by a Provider
.
function addResolversFor(uint ein, address[] memory resolvers) public;
Triggers event: ResolverAdded
removeResolvers
Removes an array of Resolvers
from the EIN
of the msg.sender
.
function removeResolvers(address[] memory resolvers) public;
Triggers event: ResolverRemoved
removeResolversFor
Preforms the same logic as removeResolvers
, but must be called by a Provider
.
function removeResolversFor(uint ein, address[] memory resolvers) public;
Triggers event: ResolverRemoved
triggerRecoveryAddressChange
Initiates a change in the current recoveryAddress
for the EIN
of the msg.sender
.
function triggerRecoveryAddressChange(address newRecoveryAddress) public;
Triggers event: RecoveryAddressChangeTriggered
triggerRecoveryAddressChangeFor
Initiates a change in the current recoveryAddress
for a given EIN
.
function triggerRecoveryAddressChangeFor(uint ein, address newRecoveryAddress) public;
Triggers event: RecoveryAddressChangeTriggered
triggerRecovery
Triggers EIN
recovery from the current recoveryAddress
, or the old recoveryAddress
if changed within the last 2 weeks.
function triggerRecovery(uint ein, address newAssociatedAddress, uint8 v, bytes32 r, bytes32 s, uint timestamp) public;
Triggers event: RecoveryTriggered
triggerDestruction
Triggers destruction of an EIN
. This renders the Identity
permanently unusable.
function triggerDestruction(uint ein, address[] memory firstChunk, address[] memory lastChunk, bool clearResolvers)
public;
Triggers event: IdentityDestroyed
Events
IdentityCreated
MUST be triggered when an Identity
is created.
event IdentityCreated(
address indexed initiator, uint indexed ein,
address recoveryAddress, address associatedAddress, address[] providers, address[] resolvers, bool delegated
);
AssociatedAddressAdded
MUST be triggered when an address is added to an Identity
.
event AssociatedAddressAdded(
address indexed initiator, uint indexed ein, address approvingAddress, address addedAddress, bool delegated
);
AssociatedAddressRemoved
MUST be triggered when an address is removed from an Identity
.
event AssociatedAddressRemoved(address indexed initiator, uint indexed ein, address removedAddress, bool delegated);
ProviderAdded
MUST be triggered when a provider is added to an Identity
.
event ProviderAdded(address indexed initiator, uint indexed ein, address provider, bool delegated);
ProviderRemoved
MUST be triggered when a provider is removed.
event ProviderRemoved(address indexed initiator, uint indexed ein, address provider, bool delegated);
ResolverAdded
MUST be triggered when a resolver is added.
event ResolverAdded(address indexed initiator, uint indexed ein, address resolvers, bool delegated);
ResolverRemoved
MUST be triggered when a resolver is removed.
event ResolverRemoved(address indexed initiator, uint indexed ein, address resolvers, bool delegated);
RecoveryAddressChangeTriggered
MUST be triggered when a recovery address change is triggered.
event RecoveryAddressChangeTriggered(
address indexed initiator, uint indexed ein,
address oldRecoveryAddress, address newRecoveryAddress, bool delegated
);
RecoveryTriggered
MUST be triggered when recovery is triggered.
event RecoveryTriggered(
address indexed initiator, uint indexed ein, address[] oldAssociatedAddresses, address newAssociatedAddress
);
IdentityDestroyed
MUST be triggered when an Identity
is destroyed.
event IdentityDestroyed(address indexed initiator, uint indexed ein, address recoveryAddress, bool resolversReset);
Solidity Interface
interface IdentityRegistryInterface {
function isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
external pure returns (bool);
// Identity View Functions /////////////////////////////////////////////////////////////////////////////////////////
function identityExists(uint ein) external view returns (bool);
function hasIdentity(address _address) external view returns (bool);
function getEIN(address _address) external view returns (uint ein);
function isAssociatedAddressFor(uint ein, address _address) external view returns (bool);
function isProviderFor(uint ein, address provider) external view returns (bool);
function isResolverFor(uint ein, address resolver) external view returns (bool);
function getIdentity(uint ein) external view returns (
address recoveryAddress,
address[] memory associatedAddresses, address[] memory providers, address[] memory resolvers
);
// Identity Management Functions ///////////////////////////////////////////////////////////////////////////////////
function createIdentity(address recoveryAddress, address[] calldata providers, address[] calldata resolvers)
external returns (uint ein);
function createIdentityDelegated(
address recoveryAddress, address associatedAddress, address[] calldata providers, address[] calldata resolvers,
uint8 v, bytes32 r, bytes32 s, uint timestamp
) external returns (uint ein);
function addAssociatedAddress(
address approvingAddress, address addressToAdd, uint8 v, bytes32 r, bytes32 s, uint timestamp
) external;
function addAssociatedAddressDelegated(
address approvingAddress, address addressToAdd,
uint8[2] calldata v, bytes32[2] calldata r, bytes32[2] calldata s, uint[2] calldata timestamp
) external;
function removeAssociatedAddress() external;
function removeAssociatedAddressDelegated(address addressToRemove, uint8 v, bytes32 r, bytes32 s, uint timestamp)
external;
function addProviders(address[] calldata providers) external;
function addProvidersFor(uint ein, address[] calldata providers) external;
function removeProviders(address[] calldata providers) external;
function removeProvidersFor(uint ein, address[] calldata providers) external;
function addResolvers(address[] calldata resolvers) external;
function addResolversFor(uint ein, address[] calldata resolvers) external;
function removeResolvers(address[] calldata resolvers) external;
function removeResolversFor(uint ein, address[] calldata resolvers) external;
// Recovery Management Functions ///////////////////////////////////////////////////////////////////////////////////
function triggerRecoveryAddressChange(address newRecoveryAddress) external;
function triggerRecoveryAddressChangeFor(uint ein, address newRecoveryAddress) external;
function triggerRecovery(uint ein, address newAssociatedAddress, uint8 v, bytes32 r, bytes32 s, uint timestamp)
external;
function triggerDestruction(
uint ein, address[] calldata firstChunk, address[] calldata lastChunk, bool resetResolvers
) external;
// Events //////////////////////////////////////////////////////////////////////////////////////////////////////////
event IdentityCreated(
address indexed initiator, uint indexed ein,
address recoveryAddress, address associatedAddress, address[] providers, address[] resolvers, bool delegated
);
event AssociatedAddressAdded(
address indexed initiator, uint indexed ein, address approvingAddress, address addedAddress
);
event AssociatedAddressRemoved(address indexed initiator, uint indexed ein, address removedAddress);
event ProviderAdded(address indexed initiator, uint indexed ein, address provider, bool delegated);
event ProviderRemoved(address indexed initiator, uint indexed ein, address provider, bool delegated);
event ResolverAdded(address indexed initiator, uint indexed ein, address resolvers);
event ResolverRemoved(address indexed initiator, uint indexed ein, address resolvers);
event RecoveryAddressChangeTriggered(
address indexed initiator, uint indexed ein, address oldRecoveryAddress, address newRecoveryAddress
);
event RecoveryTriggered(
address indexed initiator, uint indexed ein, address[] oldAssociatedAddresses, address newAssociatedAddress
);
event IdentityDestroyed(address indexed initiator, uint indexed ein, address recoveryAddress, bool resolversReset);
}
Backwards Compatibility
Identities
established under this standard consist of existing Ethereum addresses; accordingly, there are no backwards compatibility issues. Deployed, non-upgradeable smart contracts that wish to become Resolvers
for Identities
will need to write wrapper contracts that resolve addresses to EIN
-denominated Identities
.
Additional References
Copyright
Copyright and related rights waived via CC0.
First of all, I appreciate the spirit of this as I also have written about the shortcomings of existing identity standards.
However, I will make a contention: Ethereum already has identity built in. It's called an address, and it's already fully supported by the entire ecosystem. I just published a medium post explaining this argument.
So we don't need to standardize identity. That said, there may be specific problems related to identity that can benefit from standards. For example, I think that universal login is a problem that could benefit from a standard. (See the blog post above or see my repo exploring a standard around this.) Claims are also a related problem, for which we already have ERC780. Some have criticized 780 for not being quite flexible enough, so I am also exploring a more flexible claims standard that is fully backwards compatible with 780 (again, see my repo if you're interested in this).
@tyleryasaka thanks for the response - reading through your articles, it's great to see a shared mindset of future-proofing the concept of identity management while remaining un-opinionated about its particular execution.
I do think that the challenge around relying on a single user-controlled address is that an address is really optimized for one function, which is governance - signing messages for state changes to the ethereum blockchain. It's not natively optimized to resolve an Identity
as an entity to multiple data structures in a meaningful way.
What we're aiming to do here is to allow user-controlled "first-class citizenship" in application of the essentials you outline in your second article while allowing identity applications flexibility for customized solutions to the challenges mentioned in your first article: namely, implementation-specific coupled or decoupled address management functions, claims approaches, or even broader identification schemes such as reputation-driven ones.
The real purpose of a standardized scheme for Identity interoperability is to bridge the gap between what recognizing an entity by an Identity
provides versus what recognizing an entity by a given address
provides in terms of usability, multiple address linkage, and recovery.
Why did you introduce EINs instead of using DIDs?
@alexandermuehle I believe that current DID proposals treat a single Ethereum address as a single identity, which is what this proposal is attempting to avoid.
@morelazers I'm not quite sure I get your point, while there should be only one authoritative DID Document per DID, that document can include various public keys of different types and purposes, including Ethereum addresses or what do you mean by treating an Ethereum address as a single identity?
@alexandermuehle we are currently working on the DID specification for this ERC and have an initial draft that we plan to publish soon. This implementation still allows for DIDs to exist. We believe that using a persistent, non-address identifier (EIN) as the core of an ERC-1484 DID document makes more sense than an address. The DID is generated through the recovery address
and would look something like did:erc1484:2F2B37C890824242Cb9B0FE5614fA2221B79901E#225
where the address is the checksummed recovery address
and the 225 is the users EIN.
@AndyHydro I do see EINs as a better representation for IDs than addresses, and I can see one or more DID methods could be implemented on top of this protocol. However, I don't quite understand why is the recovery address
a part of the DID. Since recovery addresses can be rotated for a single identity, that would defeat the persistence feature of DIDs... Wouldn't it make more sense to make it dependable only on the EIN? e.g. did:erc1484:225
(or a fixed-size hex representation of the EIN)?
@cbruguera that's a good point - since the EIN is globally unique, I think a hex-encoded EIN is the most straightforward and persistent DID representation. I've updated the DID method to reflect this. Let us know if you've got any further thoughts on this!
@AnuragHydro Another arising thought is that an EIN is "globally" unique in the universe pertaining to the EIN registry contract. This assumes there is only one global ERC1484 implementation up and running on the network, which might be ideal but apparently not enforceable. I can't come up now with a good reason, but what if there are multiple contract instances (or versions), each one with its own EIN counter?... Would it then make sense to have the contract address (or some other distinctive feature) take part in corresponding DID generation?
Examples:
a. A keccak hash of: the contract address concatenated with (a fixed hex representation of the) EIN
b. A composite DID in the form: did:erc1484:<contract_address>:<_EIN>
(At first, it looks like option b would be more practical, since it provides useful info that would be obfuscated in the first option)
...Any thoughts on this?
@cbruguera That's a reasonable concern (although it would certainly be ideal to standardize usage of a single deployment of the IdentityRegistry). I also don't see a reason to hash the contract address, but I do like the idea of using did:erc1484:<network>:<contract_address>:<_EIN>
(option b). I've updated the DID Method again to reflect this convention 👍
For those following the reference implementation, it has now been updated to include best practices for resolvers recognizing EINs, example resolvers under the ERC 725 and 1056 standards, and an example meta-transactions provider
@AnuragHydro I have the question maybe I am wrong but we will see... A universal login idea has one very powerful feature this means user funds are stored on smart contract balance and then owners (multiple - checked via signatures) can sign requests to spent this money (eth, tokens). The idea with relayers is pretty good too - even if do not have any funds on wallet we still can make some transactions.
You know this topic probably best then I but this is very useful (from other hands very trackable). A user can connect many devices to 1 contract and do not have to remember about private key backups etc. A user has access to all my funds assigned to given wallet from any place.
To summarize - what do you think to add one more array of actors like "treasury" to existing "providers" and "resolvers" which have access to spent money from special contracts deployed per user?
We'd like to request some specific feedback on the signature scheme in 1484, specifically the form of requested signatures and the steps taken to prevent replay attacks. This best-practices document is suggested reading.
Format
Right now, signatures are formatted per ERC191 v0. This means that addresses are required to sign the hash of <standard 191 data, an authorization string, authorization-specific variables> to perform various identity-related actions (see the identity creation code for an example). While there are many reasons we prefer this v0 scheme, some community members prefer v1, which is fleshed out in ERC #721. Other alternatives are also possible.
Preventing Replay Attacks
To prevent replay attacks, the implementation requires that all signatures include a timestamp which is enforced to be within a day of the current block timestamp. This ensures that there is a one day timeout for (properly) signed messages to retain their ability to authorize identity-related actions. For more context, see the Signature Timeout section of this comment.
Are there any thoughts or opinions on either of these issues?
@xrn thanks for the suggestion! We discussed this issue, and ultimately decided to remain agnostic about these specific types of issues at the Registry level, for the following reasons.
One specific use of the Associated Addresses data structure might be to treat each as a joint owner of a common repository of ETH/tokens/etc. This way, a Resolver could incorporate the ability for any Associated Address to transact value on behalf of its associated Identity.
We also fully expect more sophisticated delegation/treasury patterns to spring up on a per-Provider level. For example, a Provider that we have been working on includes the ability for 1484 Identities to deposit tokens to their identities, and offers functions to Resolvers that allow them to manipulate these token balances (with the proper authorization).
Since these types of patterns and more may or may not require Resolvers/Providers to store additional per-Identity information, we view the current structure as appropriately balancing a) storing enough useful and generic information centrally in the Registry while b) enabling arbitrarily sophisticated use cases in the future.
Does that address your concerns?
I agree that the identity protocol should remain agnostic with regard to token/ETH dynamics.
The aforementioned functionality can be achieved through new token contract protocols, or via custom Resolver/Provider implementations as pointed out by @NoahZinsmeister. Moreover, my personal take on the matter is that the capability of shared holding of ETH/tokens in this way is not as valuable as being able to associate "claims" to multiple addresses. i.e. if you control multiple addresses, you already control the ETH/tokens held among them, it's a trivial matter to transfer money among addreses, but signed claims about a subject cannot (or shouldn't) be "transferred" in such a way.
In addition to requesting feedback on signatures, we'd also like to solicit opinions on the value of the constants in ERC-1484.
Max Associated Addresses
uint public maxAssociatedAddresses = 50;
This constant controls the maximum number of associatedAddresses
an Identity
can have at any given time. The reason this limit must exist is because when calling triggerRecovery
, the current members of the associatedAddress
set are operated on to facilitate the triggerPoisonPill
process.
- This is because to call
triggerPoisonPill
, a user needs to know the ordered list ofassociatedAddresses
at the time of last recovery. Logging the addresses straightforwardly addresses this problem. Some gas could be saved by omitting this logging, at the expense of usability, since theassociatedAddress
array would then have to be reconstructed from prior event logs.
In order to ensure that triggerRecovery
never fails, we need to ensure that the number of associatedAddresses
is never so high that these operations hit the block gas limit. Based on preliminary calculations, the increased cost per address is ~36k gas, with a fixed cost of ~175k gas. This means that triggering recovery from an Identity
with 50 addresses would cost ~2 million gas, which seems reasonably within expected future gas block limits.
We would love for someone to externally validate these calculations.
Signature Timeout
uint public signatureTimeout = 1 days;
This constant controls the amount of time that a timestamped signature remains valid for. This must be low enough that the probability of replay attacks within the window is acceptably low, and high enough to ensure that the number of blocks for which a signature is valid is high enough such that transactions can be broadcast and confirmed reliably.
We would love feedback on this, specifically around potential replay attacks within the window for each instance in which ERC-1484 requires a signature.
Recovery Timeout
uint public recoveryTimeout = 2 weeks;
This constant controls the amount of time which must elapse between:
- Changes in
recoveryAddress
. This timeout is necessary to give the oldrecoveryAddress
enough time to be able to dispute malicious changes inrecoveryAddress
by callingtriggerRecovery
. - Triggered Recoveries. This timeout is necessary so that if a malicious address ends up calling
triggerRecovery
, any of the removedassociatedAddresses
have enough time to be able to irrevocably dispute this recovery by callingtriggerPoisonPill
.
We would love feedback on these two scenarios.
@AnuragHydro I have a few questions with regard to current work on ERC1484:
- In the reference implementation, what's the purpose of storing recovery address change structs in
RecoveryAddressChangeLogs
(why not rely on emitting events as a method for logging)? - Are existing instances of ERC1056 or ERC725 able to be integrated as Resolvers for ERC1484 identities, or do these specific identity solutions have to be re-implemented with specific logic that allows them to function as ERC1484 resolvers?
- Is there a work being done for implementing a DID resolver for ERC1848?
@NoahZinsmeister I pretty much agree on the constants proposal. Yet I think in order to be as least restrictive as possible, we should maximize the maxAssociatedAddresses
to a point closer to hitting the maximum block gas limit for the involved methods. For example, current maximum block gas limit is about 8 million, if my googling is correct, so there's still significant room for a higher number of addresses.
With regard to recovery timeout, I'm thinking 1 week could be enough, but there's no concrete reasoning behind that number, more than just an intuitive guess. Looking forward to know other opinions on the matter.
In the reference implementation, what's the purpose of storing recovery address change structs in
RecoveryAddressChangeLogs
(why not rely on emitting events as a method for logging)?
The recoveryAddressChangeLog
is to enable recourse if a compromised Associated Address
attempts to change the Recovery Address
. This enables the check within the recovery function to ensure that Recovery can be called within recoveryTimeout
.
Are existing instances of ERC1056 or ERC725 able to be integrated as Resolvers for ERC1484 identities, or do these specific identity solutions have to be re-implemented with specific logic that allows them to function as ERC1484 resolvers?
@AndyHydro - can you elaborate in more detail regarding methods in the 725 and 1056 examples to port existing instances of each respective resolver?
Is there a work being done for implementing a DID resolver for ERC1848?
At the moment, we only have the DID method - we can look into creating a DID resolver to fetch data from the DID method - do you have any specific considerations on this front?
@AnuragHydro With regard to DID methods, I think it'd be more precise to ask what is the role of a DID method for this proposal... Since this is sort of an abstraction layer that can encompass existing Ethereum-based identity schemes such as ERC1056 and ERC725 (as far as I understand), how does ERC1484 integrate or substitute (DID-wise) these other platforms?
There are DID methods for ERC725 and ERC1056. Does enveloping these identities through an ERC1484 EIN make these other DID methods unnecessary? Or is there any reason for these multiple DID methods to coexist or hold any relationship among them?
@cbruguera I don't think that any particular DID method replaces the need for another - they are just used to locate their corresponding on-chain identifiers and construct any associated identity information accordingly. It's true that an EIN
is informative about a 725 or 1056 identity; for instance, using did:erc1484:<contract-address>:<ein>
, you can get the EIN
's corresponding 725 or 1056 public profiles from the respective registry and construct the DID that way, but I think it's better for each identity application to maintain an authoritative DID method independent of ERC 1484 for two main reasons:
-
Static DID Method: If the 1484 DID method were to assume the role of a universal Ethereum DID, it would need to be dynamic, with a mechanism to update nonstandard information to the DID doc with each aggregated identity application. Since these docs are constructed off-chain, the DID method would need to include centralized update procedures for each new aggregated identity application to remain authoritative.
-
Independent Identity Application Services: certain DIDs leverage service endpoints with off-chain customized functionality that may not directly tie to ERC 1484 functionality. Forcing these service endpoints into an ERC 1484 DID method may prove restrictive.
Instead, I'd posit that the 1484 DID method is useful for making non-Ethereum-based DIDs resolvable to the Ethereum blockchain. For instance, an identity application built on non-ethereum structure may have a service endpoint accepting a signature from an Associated Address
in order to authoritatively add the corresponding EIN
into its own DID doc. This would allow an off-chain digital identity structure to remain resolvable to an EIN
insofar as the service endpoint and off-chain infrastructure is trusted.
@AnuragHydro It makes total sense not to try turning the ERC1484 DID method into an "all-encompassing" method, for the reasons provided. However, I'm having a bit of trouble understanding your last example. Can you expand it further?... In this scenario is the identity owner the "controller" of both the ERC1484 EIN and the off-chain service? Does the off-chain service have a DID that is resolvable to an EIN of its own? Or is this about delegating "keys" among different DID methods? What does "adding the corresponding EIN into its own DID doc" mean exactly?
On a different topic, I've been thinking of the potential limitations of having the EIN be a simple and (predictably) incremental counter. Although at this time no specific privacy-threat scenario comes to mind, certainly in the current proposal an EIN by itself reveals a minimum degree of information (i.e. chronological order). I was wondering if it makes sense to "randomize" the generation of EINs, so that there's no explicit order relationship among them. For example: the counter can still be used as a "nonce", and EINs could be generated as a 32-byte hash of that nonce concatenated with some other info (such as the caller's address, etc.)
That would ensure uniqueness of identifiers, plus a bit more of privacy (I guess anyone can still resolve the EINs and obtain public info such as date of creation, yet the identifiers per se reveal nothing). I'd just like to know what is the overall view on this matter, and if it's considered actually relevant or not.
In this scenario is the identity owner the "controller" of both the ERC1484 EIN and the off-chain service?
Yes - the off-chain service would use an Associated Address
signature to prove this.
Does the off-chain service have a DID that is resolvable to an EIN of its own? Or is this about delegating "keys" among different DID methods? What does "adding the corresponding EIN into its own DID doc" mean exactly?
Off-chain service can be as opinionated or unopinionated as it chooses. An example would be building an identity profile on hyperledger indy; with an Associated Address
signature, all of the functionality for the identity would maintain integrity on "non-ethereum" service while remaining resolvable to an Ethereum EIN, proving a persistent user (insofar as the off-chain infrastructure is trusted). I hope that makes more sense!
On a different topic, I've been thinking of the potential limitations of having the EIN be a simple and (predictably) incremental counter. Although at this time no specific privacy-threat scenario comes to mind, certainly in the current proposal an EIN by itself reveals a minimum degree of information (i.e. chronological order). I was wondering if it makes sense to "randomize" the generation of EINs, so that there's no explicit order relationship among them. For example: the counter can still be used as a "nonce", and EINs could be generated as a 32-byte hash of that nonce concatenated with some other info (such as the caller's address, etc.) That would ensure uniqueness of identifiers, plus a bit more of privacy (I guess anyone can still resolve the EINs and obtain public info such as date of creation, yet the identifiers per se reveal nothing). I'd just like to know what is the overall view on this matter, and if it's considered actually relevant or not.
Personally, I do not see this as a big concern; since EINs are generated on-chain anyways, the order in which they were generated is already public regardless of whether uints vs random identifiers are used. Not sure if anyone else feels strongly on this.
Can I suggest considering a little less "allegorical" name for the "poison pill" functionality? Perhaps something more technically accurate such as disable
, destroy
, etc.?
This is great. And alos it's what I have being trid for months. Now I need some time to read the proposal, my English is slow. Anyway, good job!
@cbruguera sure thing! changed to "destroy"
Also, for anyone interested, here's a telegram chat for less formal discussion around this proposal. https://t.me/erc1484
What is the actual, end-user, tell my not-tech-advanced family member use case here?
@fulldecent In my view the real value prop is:
DApp developers will be able to identify users not by address, but by unique 1484 identifier (Ethereum Identification Number/EIN). This is powerful because EINs are natively multi-address, meaning interacting with dApps on mobile, desktop, in dedicated apps, etc. gives users the same exact experience once they’ve linked these accounts to their identity. The best part is that meta-transactions are also fully supported, meaning that applications (Providers in 1484-speak) can send permissioned transactions on behalf of users who might not understand complex blockchain mechanics.
DApp developers will be able to identify users
with respect to "identifying users", since EINs aggregate identity profiles, if two applications want to take the same approach to identifying users (kind of like "log-in with facebook"), they're able to leverage existing identity implementations tied to an EIN.
@fulldecent to be even more simplistic, it's like having a purse and personal assistant. Instead of separately carrying your driver's license, credit card, debit card, passport, etc. you carry it all in the purse - the purse is your EIN
. Instead of you having to sift through your purse to find all the things you need at exactly the right time to give to the store clerk, your assistant does all of that for you and keeps your purse organized. The store clerk really only needs to deal with your assistant, though of course, they're free to deal with you directly if they want. Your assistant is a smart contract that knows how to deal with store clerks on your behalf - the provider
. The store clerk is the resolver
who has his own unique way of recognizing you based on some combination of the items in your purse or maybe even completely unique items they give you, like a rewards card.
Basic question here: So far it seems that associated addresses for ERC1484 identities are "flat", meaning there's no hierarchy or custom permissioning set on these addresses. How would a hierarchical (or any other sort of complex permissioning) scheme be implemented over ERC1484 identities? How would this scheme compare to that of ERC725 for example? or How would you describe the possible integration between ERC1484 and ERC725 (or similar) to achieve this level of "complex identities" (e.g. Identity structure for corporate entities, etc)...?
@cbruguera
Good question! This is a good example of the two ERCs working well in conjunction with one another. You are correct in that ERC 1484 simply links addresses for a given EIN and does not, by itself, define the nature of the relationship between those addresses.
The ERC 734 address-management structure defines the nature of the relationship between keys, which may be useful in some instances while not useful in others. If a user (or a dApp for its users) wants to add informativeness about the nature of the relationship between keys, it would simply set the desired key-management structure as a resolver
for the EIN. In this case, I see that an ERC 734 resolver contract defines the key-management structure for a user of my dApp, so I drive logic in my dApp accordingly. Someone else with a different dApp prefers a different key management structure for their users, so they have the users set a different resolver. The second dApp drives their logic based on information from a different resolver
for the same user which defines key management differently. Here, we'd have two identity applications aggregated for the same end-user, driving their interactions with different platforms. A third dApp could piggyback on one of the existing key-management structures or define its own, per its custom needs.
Ultimately, the objective is always to apply informativeness at the resolver
level.
@AnuragHydro thanks for your reply. I guess my question is more about control than "informativeness". More than depicting the relationships between different addresses, I'm trying to figure out how to implement a hierarchy (or other more complex settings) for EIN/DID permissioning. So, I'm guessing part of the permissioning structure for an identity would be dApp-specific and therefore be represented through the corresponding resolvers as you stated, yet actual control over the identity would be implemented at the Provider layer instead?... On the other hand, all associated addresses at the ERC1484 level seem to have full control, meaning we can regard them all as "management keys" (using the ERC725 terminology), is that correct? I'm still trying to wrap my head around how would a corporate identity look like on ERC1484 (e.g. a single identity comprising of different departments, each one probably with its own EIN, yet some of them authorized or not to perform certain operations, same as keys within each department, etc..)
On another topic, I can't see any info on address-management on the link you provided for ERC734, so I'm not sure what is it exactly. Is it a way to reference both ERC725 and ERC735?
I'm still trying to wrap my head around the concept of a "Resolver" in the context of ERC1484... It was my understanding that these were smart contract addresses that were able to aggregate arbitrary data (or functionality) associated to an EIN, however, in the ERC1484 proposal and reference implementation resolvers
is just an array of addresses. There's no mnemonic indexation or discoverability mechanism tied to these resolvers, so how can relying parties know which of these addresses contain any valuable information about the identity? Wouldn't it make more sense to store resolvers in a mapping structure?
Perhaps there's something I'm missing about the resolver idea, but looking at the ERC725 example, it's just a contract that retrieves an EIN from the ERC1484 instance and associates it internally, yet there seems to be no point in having the ERC725 instance address listed as a "resolver" on the ERC1484 registry side... Can you provide a little more insight into what is the role of resolvers on this protocol?
Hey @cbruguera, great questions. Some comments:
...all associated addresses at the ERC1484 level seem to have full control, meaning we can regard them all as "management keys" (using the ERC725 terminology), is that correct?
That is correct! This is the most neutral position we were able to come up with. From the point of view of 1484, all associated addresses are equal.
...yet actual control over the identity would be implemented at the Provider layer instead?
One way to implement further permissioning on top of the associated addresses would certainly be at the provider layer, as you suggested. This could mean that a provider maintains specific permission structures/delegated call mechanics/etc. You could for example write a provider s.t. any resolver wishing to work in your ecosystem only accepts delegated calls or looks up address permissioning from your provider.
...part of the permissioning structure for an identity would be dApp-specific and therefore be represented through the corresponding resolvers...
Another way to implement permissioning would be at the Resolver level. This could mean that instead of relying on associated addresses, a resolver (or provider) could instead enforce that an EIN has added another resolver which contains ERC-725 data, and use that resolver's data to permission addresses.
There's no mnemonic indexation or discoverability mechanism tied to these resolvers, so how can relying parties know which of these addresses contain any valuable information about the identity?
That is the case, which is both good and bad. It's good in the sense that resolvers are just arbitrary addresses, it's bad in that like you said, there's no other metadata attached to resolvers, so they have to be interpreted on a case-by-case basis.
...there seems to be no point in having the ERC725 instance address listed as a "resolver" on the ERC1484 registry side...
This is definitely mostly the case, and gets to the core issue. The resolvers array is really only a) to help front-end identity aggregators know which identity applications are currently active for a given EIN, and b) to add an element of user-controlled permissioning to their identity. Resolvers are really only useful in so far as there is custom logic on either a smart contract or front-end that utilizes them in specific ways. Users gain some level of control over this process by being able to add/remove resolvers at will.
It's hard for me to comment more specifically without knowing a bit about the potential use cases you're looking to implement, but hopefully this helps, let me know if there's anything else you'd like to discuss!
@NoahHydro Thanks for your reply. I still think there's a functional gap in the idea of resolvers. The way you describe it (and as it's presently implemented) it looks like the assumption is being made that applications will know the resolver addresses beforehand from which they might be able to obtain the corresponding EIN of an identity and handle it internally as desired. The use case I have in mind, though, is quite the opposite: where a dApp knows an entity's EIN and then wishes to obtain associated data (e.g. ERC735 claims). Moreover, the "relying party" in this case could be another smart contract, which would have even more limitations than a user facing application. Yet in the current setup there's no way to traverse that relationship parting from an EIN since there's no meta-data on added resolvers.
If EINs are supposed to work as sort of universal identifiers for Ethereum (being ERC1484 a protocol intended to stand on top of other on-chain identity solutions), it's my view that it'll be quite common (and a desirable feature in fact) that an EIN is the only attribute to be shared and stored among different apps and contracts, from which other relevant attributes should be discoverable. Otherwise, I don't think it's working much as an actual identity aggregator.
Still, there's a huge chance I'm misunderstanding the actual purpose of resolvers in this scheme.
@cbruguera just sent you a message in the ERC 1484 telegram! If we work something out there or in DMs that's of general relevance, I'll post a full recap here and in telegram.
FYI for all:
The latest ERC-1484 implementation received perfect marks on 3 community audits.
Barring the uncovering of any significant security or design flaws, we plan to mark the current deployments as canonical.
Requesting final comments on the implementation :)
P.S. My personal opinion is that the ETH 1.x and the ETH 2.0 Casper/EWASM releases will prompt a broad rethinking of optimal smart contract structure. Specifically, current conversations and proposals around state rent/event logging/monolithic contracts have implications for smart contract developers, and for this ERC. However, I still believe that the current implementation is sound, and support deploying it in its current form, primarily because there's still a fair amount of uncertainty in the Ethereum development roadmap, and because of the relative simplicity/flexibility of ERC-1484. This being an open discussion forum, however, I'd also be happy to hear additional comments/differing opinions!
Awesome!
This EIP feels like an app/contract proposal, not a standard. A lot of the stuff in this could be extracted out into separate independent EIPs, and a number of items in here don't really benefit significantly from being standardized. For example, the recovery stuff both doesn't need to be an EIP (it doesn't benefit from standardization) and it could be extracted out into a separate EIP wholly unrelated to this EIP.
Remember, when someone is authoring a contract, they can implement multiple interfaces. You don't have to create a single monolithic interface that solves all of the problems at the same time. Also keep in mind that you can author a contract that has public methods that are not part of an interface. 😄
Note: The above commentary doesn't mean I don't think the stuff discussed here are good ideas, just that I don't think everything discussed here is a good idea to standardize and that I don't think everything here is a good idea to bundle together in a single standard. In fact, I have a smart wallet I used that I wrote a couple years ago that has a very similar recovery mechanism (and I do have thoughts on how you can improve yours if you are interested)!
Thanks for taking a look @MicahZoltu ! We certainly concede that there's a lot going on in this EIP, and since we made many aspects as modular as possible, some could almost certainly be extracted into their own EIPs.
Your point about interfaces is well taken. Especially in light of upcoming ETH 1.x/2 changes, it might have made more sense to, for example, a) allow multiple implementations of the interface, and b) set it up so that per-entity data is stored in separate contracts (that maybe all reference or are referenced by some stripped-down registry).
My personal opinion is that as it stands, this EIP has some aspects that are perhaps less than ideal, but still solves non-trivial problems in the ETH identity space (especially when compared to alternatives), and can be built on today in a very extensible way (including adding additional methods that are not part of the interface! See Snowflake.).
Looking forward to ETH 2.0 land, my hopes are that it will still continue to exist, but perhaps transform into (or at least inform) an even more robust/extensible/un-opinionated identity framework.
After I read your comments @NoahZinsmeister , I have a question. Don't you have a plan to develop this EIP any more before ETH 2.0?
I guess, if paygas
will be applied to ETH 2.0, existing architectures which includes delegate
concept should be replaced. Was it one of your concern in this step?
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.
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.