-
Notifications
You must be signed in to change notification settings - Fork 830
Add ERC: Associated Accounts #1377
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
Open
stevieraykatz
wants to merge
7
commits into
ethereum:master
Choose a base branch
from
stevieraykatz:erc-associated-accounts
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+205
−0
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
caad567
Add draft spec
stevieraykatz 289960f
spelling and spacing fixes
stevieraykatz e9574ca
grammar and formatting pass
stevieraykatz bb4ca46
one more logic/formatting pass
stevieraykatz 90a8a46
addressed comments from reviewers
stevieraykatz 188e653
fix must caps
stevieraykatz c8bb2d7
address review comments
stevieraykatz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| --- | ||
| title: Associated Accounts | ||
| description: A way to publicly associate two accounts with arbitrary contextual data | ||
| authors: Steve Katzman (@stevieraykatz), Amie Corso (@amiecorso), Stephan Cilliers (@stephancill) | ||
| discussions-to: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please create discussions topic in Eth Magicians with a link to this PR |
||
| status: Draft | ||
| type: Standards Track | ||
| category: ERC | ||
| created: 2025-11-25 | ||
| requires: EIP-712, ERC-1271, ERC-5267, ERC-6492, ERC-7930 | ||
| --- | ||
|
|
||
| ## Abstract | ||
| This specification defines a standard for establishing and verifying associations between blockchain accounts. This allows addresses to publicly declare, prove and revoke a relationship with other addresses by sharing a standardized payload. For onchain applications, this payload may be signed by both parties for third-party authentication. This enables use cases like sub-account identity inheritance, authorization delegation, and reputation collation. | ||
|
|
||
| ## Motivation | ||
| A key motivation is the simplification of multi-address resolution, which is essential for managing complex digital identities across multiple platforms and accounts. This simplification aims to streamline the process of locating and verifying individuals or entities by efficiently handling multiple addresses linked by Associations. | ||
| By providing a standard mechanism for signaling an association between two accounts, this standard unlocks the capability to link the activities or details of these accounts. | ||
|
|
||
| The inclusion of arbitrary data into the specified payload ensures flexibility for various use cases such as delegation, hierarchical relationships, and authentication. By maintaining a flexible architecture that accepts an interface identifier paired with arbitrary data bytes, accounts that associate can do so with application-specific context. | ||
|
|
||
| ## Overview | ||
| The system outlined in this document describes a way for two accounts to be linked by a specified data struct which describes the relationship between them. It offers the mechanism by which these parties can sign over the contents to prove validity. It focuses on the structure and process for generating, validating and revoking such records while maintaining an implementation agnostic approach. | ||
|
|
||
| ## Specification | ||
| The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174. | ||
|
|
||
| ### Core Concepts | ||
| Each Association between two accounts denotes the participating addresses as `initiator` and `approver`. These accounts can be on disparate chains with different architectures made possible by a combination of [ERC-7930 Interoperable Addresses](https://eips.ethereum.org/EIPS/eip-7930) and an enumeration of signature key types. To accommodate non-EVM account types, addresses are recorded in the association as raw bytes. | ||
|
|
||
| The specification outlines a nested structure for recording Associations: | ||
| 1. An underlying Associated Account Record (AAR) for storing accounts, timestamps and association context | ||
| 2. A wrapper Signed Association Record (SAR) structure for storing signature and validation data | ||
|
|
||
| ### Associated Account Record | ||
| The following is a Solidity implementation of an `AssociatedAccountRecord` which contains the shared payload describing the association. | ||
|
|
||
| ```solidity | ||
| /// @notice Represents an association between two accounts. | ||
| struct AssociatedAccountRecord { | ||
| /// @dev The ERC-7930 binary representation of the initiating account's address. | ||
| bytes initiator; | ||
| /// @dev The ERC-7930 binary representation of the approving account's address. | ||
| bytes approver; | ||
| /// @dev The timestamp from which the association is valid. | ||
| uint40 validAt; | ||
| /// @dev The timestamp when the association expires. | ||
| uint40 validUntil; | ||
| /// @dev Optional 4-byte selector for interfacing with the `data` field. | ||
| bytes4 interfaceId; | ||
| /// @dev Optional additional data. | ||
| bytes data; | ||
| } | ||
| ``` | ||
| Where the AssociatedAccountRecord contains: | ||
| - `initiator` is the binary representation of an ERC-7930 address for the initiating account. | ||
| - `approver` is the binary representation of an ERC-7930 address for the approving account. | ||
| - `validAt` is the timestamp from which the association is valid. | ||
| - `validUntil` is the timestamp at which the association expires (optional). | ||
| - `interfaceId` is the 4-byte interface or method selector for the `data` field (optional). | ||
| - `data` is the arbitrary context data payload (optional). | ||
|
|
||
| ### Signed Association Record | ||
| When `AssociatedAccountRecord`s will be consumed in a trustless context, integrators SHOULD require that both paries sign over the EIP-712 hash of the `AssociatedAccountRecord` (see Support for EIP-712 below). The resulting signatures MUST be included in a `SignedAssociationRecord`. | ||
|
|
||
| ```solidity | ||
| /// @notice Complete payload containing a finalized association. | ||
| struct SignedAssociationRecord { | ||
| /// @dev The timestamp the association was revoked. | ||
| uint40 revokedAt; | ||
| /// @dev The initiator key type specifier. | ||
| bytes2 initiatorKeyType; | ||
| /// @dev The approver key type specifier. | ||
| bytes2 approverKeyType; | ||
| /// @dev The signature of the initiator. | ||
| bytes initiatorSignature; | ||
| /// @dev The signature of the approver. | ||
| bytes approverSignature; | ||
| /// @dev The underlying AssociatedAccountRecord. | ||
| AssociatedAccountRecord record; | ||
| } | ||
| ``` | ||
| Where the SignedAssociationRecord contains: | ||
| - `revokedAt` is the timestamp when the association was revoked, which is `0` unless the association has been revoked by either party. | ||
| - `initiatorSignature` is the signature bytes generated by the `initiator` by signing the EIP-712 compliant hash of the AssociatedAccountRecord. | ||
| - `initiatorKeyType` is the key type designator for the initiator's signature (see Key Types below). | ||
| - `approverSignature` is the signature bytes generated by the `approver` by signing the EIP-712 compliant hash of the AssociatedAccountRecord. | ||
| - `approverKeyType` is the key type designator for the approver's signature (see Key Types below). | ||
| - `record` is the AssociatedAccountRecord that was signed by both parties. | ||
|
|
||
| ### Key Types | ||
| To accommodate known curves and signing protocols while providing future extensibility, this specification relies on the enumeration of cryptographic curves and signing protocols. Each signature MUST be paired with a valid "Key ID" designator. | ||
|
|
||
| The Key IDs SHALL be identified as a 2-byte integer according to the following extensible table. We accommodate two types of keys: | ||
| 1. Applied cryptographic curves (i.e. secp256k1) | ||
| 2. Protocol integrations (i.e. WebAuthn, contract validation) | ||
|
|
||
| To distinguish these key types, the most significant bit in the 2-byte identifier SHALL be used as a bit flag. As such, key type protocols are constructed by bitwise OR: | ||
| `0x8000 | PROTOCOL_ID`. | ||
|
|
||
| The resulting table enumerates the known keys and distinguishes between the two types: | ||
|
|
||
| | Key ID | Type | Curve/Standard | | ||
| | -------- | -------- | -------- | | ||
| | 0x0000 | Delegated | Delegated auth | | ||
| | 0x0001 | K1 | secp256k1 | | ||
| | 0x0002 | R1 | secp256r1 | | ||
| | 0x0003 | BLS | BLS12-381 | | ||
| | 0x0004 | EdDSA | Ed25519 | | ||
| | 0x8001 | WebAuthn | WebAuthn/Passkey | | ||
| | 0x8002 | ERC-1271 | Contract validation | | ||
| | 0x8003 | ERC-6492 | Predeploy contract validation | | ||
|
|
||
| #### Delegated Auth | ||
| In some contexts it might be ergonomic to delegate authorization to another account, access control mechanism, or external protocol. Implementers leveraging the `Delegated` key type MUST also publish how consumers can parse the application-specific delegation schema. | ||
|
|
||
| ### Support for EIP-712 | ||
| All signatures contained in this specification MUST comply with EIP-712 wherein the signature pre-image can be generated from: | ||
|
|
||
| ```solidity | ||
| keccak256(abi.encodePacked( | ||
| hex"1901", | ||
| DOMAIN_SEPARATOR, | ||
| keccak256(abi.encode( | ||
| keccak256("AssociatedAccountRecord(bytes initiator,bytes approver,uint40 validAt,uint40 validUntil,bytes4 interfaceId,bytes data)"), | ||
| keccak256(initiator), | ||
| keccak256(approver), | ||
| validAt, | ||
| validUntil, | ||
| interfaceId, | ||
| keccak256(data) | ||
| )) | ||
| )) | ||
| ``` | ||
|
|
||
| Where `DOMAIN_SEPARATOR` is defined according to EIP-712. The `DOMAIN_SEPARATOR` for this ERC SHALL be defined as: | ||
| ```solidity | ||
| keccak256(abi.encode( | ||
| keccak256("EIP712Domain(string name,string version)"), | ||
| keccak256(bytes("AssociatedAccounts")), | ||
| keccak256(bytes("1")) | ||
| )) | ||
| ``` | ||
|
|
||
| ### Onchain Storage | ||
| If desired, a `SignedAssociationRecord` MAY be stored onchain in a context-specific storage contract. | ||
|
|
||
| An onchain storage contract SHALL comply with the following steps: | ||
| 1. The SAR MUST be validated according to the steps detailed in the Validation section. | ||
| 2. The contract MUST emit the `AssociationCreated` event: | ||
|
|
||
| ```solidity | ||
| event AssociationCreated( | ||
| bytes32 indexed hash, bytes32 indexed initiator, bytes32 indexed approver, SignedAssociationRecord sar | ||
| ); | ||
| ``` | ||
| where: | ||
| - `hash` is the indexed hash for the SignedAssociationRecord, equivalent to the EIP-712 hash of the underlying AAR. | ||
| - `initiator` is the keccak256 hash of the ERC-7930 address of the account that initiated the association. | ||
| - `approver` is the keccak256 hash of the ERC-7930 address of the account that accepted and completed the association. | ||
| - `sar` is the completed SignedAssociationRecord. | ||
|
|
||
| If a SignedAssociationRecord is stored onchain, it MUST also be revokable onchain (see Revocation) below. | ||
|
|
||
| ### Offchain Storage | ||
| In some contexts, it might be desirable for Signed Association Records to be stored in an offchain store. While the implementation will differ from application-to-application, the following considerations SHOULD be taken into account: | ||
| - Access to this data store MUST be made available to all expected consumers through publicly accessible endpoints | ||
| - The store MUST perform validation on incoming Associations before storage | ||
| - The location of this offchain store SHOULD be searchable by some standard fetching mechanism, e.g. a text record on an ENS name | ||
|
|
||
| ### Validation | ||
| Clients or contracts determining whether a SignedAssociationRecord is valid at the time of consumption MUST check all of the following validation steps: | ||
| 1. The current timestamp MUST be greater than or equal to the `validAt` timestamp. | ||
| 2. If the `validUntil` timestamp is nonzero, the current timestamp MUST be less than the `validUntil` timestamp. | ||
| 3. If the `revokedAt` timestamp is nonzero, the current timestamp MUST be less than the `revokedAt` timestamp. | ||
| 4. If the `initiatorSignature` field is populated, the signature MUST be valid for the EIP-712 preimage of the underlying `AssociatedAccountRecord` using an appropriate `initiatorKeyType` validation mechanism. | ||
| 5. If the `approverSignature` field is populated, the signature MUST be valid for the EIP-712 preimage of the underlying `AssociatedAccountRecord` using an appropriate `approverKeyType` validation mechanism. | ||
|
|
||
| Onchain validation is possible as long as there are sufficient validation mechanisms for the various key types used by the two accounts. In the case that validation occurs onchain, implementations MUST replace "current timestamp" with `block.timestamp`. | ||
|
|
||
| ### Revocation | ||
| Onchain Association stores MUST implement a revocation method. This method MUST allow either party of an Association to revoke a valid, active association by submitting a revocation request. | ||
|
|
||
| In such contexts, storage contracts MUST update the `revokedAt` field of the SAR to `block.timestamp` OR the account-specified revocation timestamp, whichever is greater. Then the implementation contract MUST emit the following event upon accepting a valid revocation request: | ||
| ```solidity | ||
| event AssociationRevoked(bytes32 indexed hash, bytes32 indexed revokedBy, uint256 revokedAt); | ||
| ``` | ||
| where: | ||
| - `hash` is the indexed unique identifier for the association, equivalent to the EIP-712 hash of the underlying AAR. | ||
| - `revokedBy` is the indexed keccak256 hash of the ERC-7930 address of the revoking account. | ||
| - `revokedAt` is the timestamp at which the association is revoked. | ||
|
|
||
| Offchain stores MUST allow either account to revoke a stored association and MUST update the `revokedAt` timestamp accordingly. | ||
|
|
||
| If a previously revoked association is revoked again with an earlier timestamp, the earlier timestamp MUST take precedence. | ||
|
|
||
| ## Security Considerations | ||
| For onchain applications, the validation mechanisms for some key types might be gas-cost prohibitive or entirely unavailable. It is the responsibility of the integrator to ensure that unsupported key types are appropriately handled given these constraints. | ||
|
|
||
| Offchain stores expose a trust vector to consumers. Integrators and consumers MUST take into account this centralization vector and expose the risk to users or offer mechanisms for minimizing the trust assumptions (i.e. storing some state onchain). | ||
|
|
||
| Associations SHOULD have a canonical storage location given an application. However, in the event that the same Association data is stored both on and offchain, precedence SHOULD be given to the onchain data. | ||
|
|
||
| ## Copyright | ||
| Copyright and related rights waived via [CC0](https://eips.ethereum.org/LICENSE). | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assigning next sequential EIP/ERC/RIP number.
Numbers are assigned by editors & associates.
Please also update the filename.