-
Notifications
You must be signed in to change notification settings - Fork 574
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
346 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,346 @@ | ||
--- | ||
eip: 7866 | ||
title: Decentralised User Profiles | ||
description: Decentralised Interoperable User Identity with segmented Avatars per DApp Profile | ||
author: Kumar Anirudha (@anistark) | ||
discussions-to: https://ethereum-magicians.org/t/add-erc-decentralised-profile-standard/22610 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2025-01-22 | ||
--- | ||
|
||
## Abstract | ||
|
||
This EIP proposes a standard for decentralised, interoperable user profiles known as Decentralised Profiles. Profiles are implemented as **Soul Bound Tokens (SBTs)** that are immutable, non-transferable, and tied to unique identifiers across multiple blockchain networks. The standard provides a unified structure for user metadata, including dApp-specific customisation, default profiles, and seamless cross-chain compatibility. Profiles can be leveraged for identity management, reputation systems, and personalised dApp experiences. | ||
|
||
## Motivation | ||
|
||
Existing solutions for decentralised identity and user profiles lack cross-chain compatibility, dApp-specific customisation, and standardisation. A unified approach is essential to: | ||
1. Facilitate interoperable profiles across all chains. | ||
2. Leverage the immutability and non-transferability of SBTs for secure identities. | ||
3. Enable dApp-specific customisations, such as unique avatars. | ||
4. Provide a robust, standards-based alternative to centralised solutions like Gravatar. | ||
5. Ensure user control and decentralisation with profiles stored on IPFS/Arweave. | ||
6. A common standard for Decentralised Identity that can be used across all chains. | ||
7. Act as a Digital Passport for users, enabling seamless decentralised verification and authentication. | ||
|
||
## Specification | ||
|
||
### Unique Profile Identifiers | ||
|
||
#### Decentralised Profile | ||
Each profile is identified by: | ||
|
||
``` | ||
<username>@<network_slug>.soul | ||
``` | ||
|
||
- `username`: User-defined, chain-unique string. | ||
- `network_slug`: Short identifier for the chain (e.g., `eth`, `polygon`, `xion`). | ||
- `soul`: Fixed suffix indicating soul bound token. | ||
|
||
Example: | ||
`[email protected]` | ||
`[email protected]` | ||
|
||
#### Decentralised Identifier (DID) | ||
Each profile is tied to a DID: | ||
|
||
``` | ||
did:<chain>:<address> | ||
``` | ||
|
||
Example: | ||
`did:ethereum:0x123...` | ||
`did:xion:xion1abc...` | ||
|
||
### Metadata Structure | ||
The profile metadata structure is designed to balance extensibility, usability, and compatibility with decentralized storage systems like IPFS. Metadata will adhere to the following schema: | ||
|
||
```json | ||
{ | ||
"username": "batman", | ||
"avatar": "ipfs://<CID>", | ||
"bio": "Blockchain enthusiast and builder.", | ||
"website": "https://anirudha.dev", | ||
"socials": { | ||
"twitter": "https://twitter.com/kranirudha", | ||
"github": "https://github.com/anistark" | ||
}, | ||
"default_avatar_visibility": "public", | ||
"dapp_avatars": { | ||
"0xDAppAddress1": { | ||
"avatar": "ipfs://<CID>", | ||
"visibility": "private" | ||
}, | ||
"0xDAppAddress2": { | ||
"avatar": "ipfs://<CID>", | ||
"visibility": "public" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Access Control | ||
|
||
1. **Default Avatar Visibility**: Users can set their default avatar visibility as public or private. | ||
2. **dApp-Specific Avatar Visibility**: Each dApp-specific avatar can also have its visibility set to public or private. | ||
|
||
**Visibility Logic**: | ||
- If an avatar is public, it is retrievable by any external caller. | ||
- If an avatar is private, only the user can retrieve it. Other callers will get an encoded response alongwith error message. | ||
|
||
### dApp-Specific Avatar Customisation | ||
- Users can assign dApp-specific avatars or metadata. | ||
- If no dApp-specific customisation exists, the default avatar applies. | ||
|
||
## Rationale | ||
|
||
The design of the Decentralised Profile Standard was guided by the need for a unified, interoperable user profile system that can operate seamlessly across all blockchain networks. Current solutions, such as ENS profiles or Gravatar, either lack cross-chain functionality, are centralised, or do not allow users to customise profiles for specific dApps. This standard addresses these shortcomings while ensuring simplicity, security, and scalability. | ||
|
||
### Design Decisions | ||
|
||
1. **Decentralised Identifiers (DIDs)** | ||
- Using the `did:<chain>:<address>` format provides a globally unique identifier for profiles. This aligns with the decentralised identity movement and ensures compatibility with broader DID frameworks. | ||
|
||
2. **Decentralised Profile** | ||
- The profile format (`[email protected]`) makes profiles human-readable and chain-specific while maintaining a universal structure. The `.soul` suffix clearly identifies profiles compliant with this standard. | ||
|
||
3. **dApp-Specific Avatars** | ||
- Allowing users to assign dApp-specific avatars caters to personalisation and enhances the user experience. It supports scenarios where users may want different representations or metadata for different applications. | ||
|
||
4. **Soul Bound Tokens (SBTs)** | ||
- Leveraging SBTs ensures that profiles are non-transferable, reinforcing the concept of identity ownership. SBTs prevent profiles from being sold or hijacked, making them ideal for reputation-based systems. | ||
|
||
5. **Registry and Resolver Architecture** | ||
- This architecture was chosen for its extensibility and proven track record, as seen in ENS. It separates the management of profile identifiers (Registry) from the resolution of metadata (Resolver), making upgrades and integrations straightforward. | ||
|
||
6. **Compatibility with Existing Standards** | ||
- The profile standard integrates with [ERC-165](./erc-165) for interface detection and can complement ENS or other naming systems, fostering interoperability rather than competition. | ||
|
||
7. **Default and dApp-Specific Metadata** | ||
- The inclusion of both default and dApp-specific metadata ensures flexibility. If dApp-specific metadata is not set, the default profile seamlessly applies, reducing friction for developers and users. | ||
|
||
8. **On-Chain Data Minimisation** | ||
- Metadata is stored off-chain (e.g., IPFS or Arweave) to minimise gas costs and support scalable operations. Only URIs and pointers are stored on-chain. | ||
|
||
9. **Access Control** | ||
|
||
- Users have complete control over avatar visibility, catering to privacy preferences. | ||
- Specific dApp-based customizations ensure fine-grained control. | ||
|
||
10. **dApp Identification** | ||
|
||
- Requiring dApps to be identified by an address ensures traceability and security. | ||
|
||
11. **Extensibility** | ||
|
||
- Adding metadata fields or new visibility levels does not disrupt the standard. | ||
- Profiles can remain lightweight while supporting future scalability. | ||
|
||
12. **Security** | ||
|
||
- Access control minimizes the risk of sensitive data exposure. | ||
- Metadata stored off-chain ensures minimal gas usage and flexibility. | ||
|
||
#### Alternative Designs Considered | ||
|
||
1. **Pure On-Chain Metadata** | ||
- Storing all metadata on-chain was considered but discarded due to high gas costs, limited storage capacity, and challenges in supporting complex or large datasets such as high-resolution avatars. | ||
|
||
2. **Direct Integration with ENS** | ||
- While integrating with ENS was explored, it was deemed limiting for cross-chain functionality, as ENS is predominantly tied to Ethereum. Decentralised profile takes inspiration from ENS while ensuring a truly multichain approach. | ||
|
||
3. **Fully Centralised System** | ||
- A centralised system would simplify implementation but contradict the core principles of decentralisation and user sovereignty. | ||
|
||
4. **Non-SBT-Based Implementation** | ||
- Using standard [ERC-721](./erc-721) tokens for profiles was considered but rejected since transferability is unsuitable for identity management. SBTs enforce the immutability of identity ownership. | ||
|
||
### Comparison with Related Work | ||
|
||
- **ENS**: Provides a robust naming service but lacks dApp-specific metadata and cross-chain functionality. | ||
- **Gravatar**: Centralised and cannot leverage blockchain-specific advantages like immutability, decentralisation, and SBT integration. | ||
- **DID Standards**: Profile must aligns with DID specifications, ensuring it fits into the broader decentralised identity ecosystem while offering features tailored to blockchain-based applications. | ||
|
||
### Scalability and Extensibility | ||
|
||
The Registry and Resolver architecture, combined with off-chain metadata storage, ensures that profile can scale with the growth of the blockchain ecosystem. New chains, metadata types, and customisations can be added without disrupting the core functionality or introducing breaking changes. | ||
|
||
The design balances simplicity, extensibility, and user control, making it well-suited for adoption across a wide range of dApps, wallets, and blockchains. | ||
|
||
### Contract Interface | ||
|
||
The standard includes the following interface: | ||
|
||
#### ISoulProfile | ||
|
||
```solidity | ||
// SPDX-License-Identifier: CC0-1.0 | ||
pragma solidity ^0.8.19; | ||
interface ISoulProfile { | ||
struct Metadata { | ||
string username; | ||
string avatar; | ||
string bio; | ||
string website; | ||
mapping(string => string) socials; | ||
string defaultAvatarVisibility; | ||
mapping(address => DappAvatar) dappAvatars; | ||
} | ||
struct DappAvatar { | ||
string avatarURI; | ||
string visibility; // "public" or "private" | ||
} | ||
event ProfileCreated(address indexed user, string did, string username); | ||
event AvatarUpdated(address indexed user, string avatarURI, string visibility); | ||
event DappAvatarUpdated( | ||
address indexed user, | ||
address indexed dApp, | ||
string avatarURI, | ||
string visibility | ||
); | ||
function createProfile(string calldata username) external; | ||
function setDefaultAvatar(string calldata avatarURI, string calldata visibility) external; | ||
function setDappAvatar( | ||
address dApp, | ||
string calldata avatarURI, | ||
string calldata visibility | ||
) external; | ||
function getDefaultAvatar(address user) external view returns (string memory, string memory); | ||
function getDappAvatar(address user, address dApp) external view returns (string memory, string memory); | ||
} | ||
``` | ||
|
||
### Reference Implementation | ||
|
||
#### SoulProfile | ||
|
||
```solidity | ||
// SPDX-License-Identifier: CC0-1.0 | ||
pragma solidity ^0.8.19; | ||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
import "@openzeppelin/contracts/utils/Strings.sol"; | ||
import "./ISoulProfile.sol"; | ||
contract SoulProfile is Ownable, ISoulProfile { | ||
mapping(address => Metadata) private profiles; | ||
modifier onlyProfileOwner(address user) { | ||
require(msg.sender == user, "Not authorized"); | ||
_; | ||
} | ||
function createProfile(string calldata username) external override { | ||
require(bytes(username).length > 0, "Username cannot be empty"); | ||
require(profiles[msg.sender].username == "", "Profile already exists"); | ||
profiles[msg.sender].username = username; | ||
profiles[msg.sender].defaultAvatarVisibility = "public"; // Default to public | ||
emit ProfileCreated(msg.sender, generateDID(msg.sender), username); | ||
} | ||
function setDefaultAvatar(string calldata avatarURI, string calldata visibility) external override { | ||
require(bytes(visibility).length > 0, "Visibility must be set"); | ||
profiles[msg.sender].avatar = avatarURI; | ||
profiles[msg.sender].defaultAvatarVisibility = visibility; | ||
emit AvatarUpdated(msg.sender, avatarURI, visibility); | ||
} | ||
function setDappAvatar( | ||
address dApp, | ||
string calldata avatarURI, | ||
string calldata visibility | ||
) external override { | ||
require(dApp != address(0), "Invalid dApp address"); | ||
require(bytes(visibility).length > 0, "Visibility must be set"); | ||
profiles[msg.sender].dappAvatars[dApp] = DappAvatar(avatarURI, visibility); | ||
emit DappAvatarUpdated(msg.sender, dApp, avatarURI, visibility); | ||
} | ||
function getDefaultAvatar(address user) | ||
external | ||
view | ||
override | ||
returns (string memory avatarURI, string memory visibility) | ||
{ | ||
Metadata storage profile = profiles[user]; | ||
return (profile.avatar, profile.defaultAvatarVisibility); | ||
} | ||
function getDappAvatar(address user, address dApp) | ||
external | ||
view | ||
override | ||
returns (string memory avatarURI, string memory visibility) | ||
{ | ||
Metadata storage profile = profiles[user]; | ||
DappAvatar storage dappAvatar = profile.dappAvatars[dApp]; | ||
return (dappAvatar.avatarURI, dappAvatar.visibility); | ||
} | ||
function generateDID(address user) internal pure returns (string memory) { | ||
return string(abi.encodePacked("did:ethereum:", Strings.toHexString(user))); | ||
} | ||
} | ||
``` | ||
|
||
Of course, this can be extended to prepare a full registry and resolver according to ENS or similar standards. Refer to Rationale above for more information about the same. | ||
|
||
## Backwards Compatibility | ||
|
||
The Decentralised Profile system is designed to ensure smooth integration with existing decentralized applications (dApps) and platforms, while offering an upgrade path for future enhancements. Below are key considerations for backwards compatibility: | ||
|
||
- **ENS Compatibility**: The system adheres to the naming conventions and standards specified in [EIP-137](./erc-137) (Ethereum Name Service). This ensures that any dApps or tools already using ENS-compatible names can easily integrate profiles without additional changes. | ||
|
||
- **Flexible dApp Identification**: By using wallet addresses to identify dApps, the system avoids the need for centralized registration of dApps. Any existing or new dApp that interacts with Ethereum or compatible chains can use the standard by simply passing its address as a parameter. | ||
|
||
- **Default Avatar Fallback**: If no specific avatar is set for a dApp, the system gracefully falls back to the default avatar. This ensures that even older dApps that do not implement the latest features can continue to work seamlessly. | ||
|
||
- **Upgradeable Contracts**: By implementing a proxy-based architecture for all major contracts (resolver, registry, profile), the system ensures that future upgrades or changes in functionality can be deployed without disrupting existing data or workflows. Upgrades are conducted through secure proxy mechanisms like TransparentUpgradeableProxy. | ||
|
||
- **Chain Agnosticism**: The use of decentralized identifiers (DIDs) and chain-specific network slugs ensures interoperability across chains. This allows profiles to maintain consistency regardless of which chain they originate from, ensuring compatibility with multi-chain ecosystems. | ||
|
||
## Security Considerations | ||
|
||
Profile system should prioritise robust security to protect user data and prevent unauthorized access. | ||
|
||
1. **Access Control**: Users can set visibility for their avatars (public or private). This is enforced at both the resolver and registry levels to ensure unauthorized entities cannot access private avatars. Functions that modify state (e.g., setDefaultAvatar, setDappAvatar) are protected with access controls, ensuring only the profile owner can make changes. | ||
|
||
2. **Data Privacy**: Sensitive metadata is encrypted before storage on decentralized storage systems like IPFS or Arweave. Visibility flags ensure users can control who can view specific profile elements. | ||
|
||
3. **Reentrancy Protection**: Functions modifying state implement the checks-effects-interactions pattern or leverage ReentrancyGuard to prevent reentrancy attacks. For example, setDappAvatar ensures that all validations are performed before updating the state. | ||
|
||
4. **Input Validation**: All user inputs (e.g., username, visibility, dApp) are validated to ensure they meet specified criteria. Invalid or malicious inputs are rejected to prevent injection attacks or other exploits. Visibility is restricted to predefined values ("public" or "private"). | ||
|
||
5. **Immutable DIDs**: Decentralized identifiers (DIDs) for users are immutable once created. This prevents spoofing or unauthorized changes to user identities. | ||
|
||
6. **Fallback Mechanisms**: The system provides fallback mechanisms for fetching avatars. If a dApp-specific avatar is not found, the default avatar is returned, ensuring smooth operation without errors. | ||
|
||
7. **Upgradeable Contracts**: Proxy contracts are used to allow for upgrades while preserving state. Upgrades are performed securely via a multi-signature governance process to minimize risks. | ||
|
||
8. **Rate Limiting**: Rate-limiting mechanisms can be implemented to prevent spam or abuse of profile creation and update functions. | ||
|
||
9. **Audits and Best Practices**: The contracts are designed following best practices and are to be audited regularly by independent security firms. Dependencies (e.g., OpenZeppelin contracts) are reviewed and kept up to date to mitigate vulnerabilities. | ||
|
||
10. **dApp Address Verification**: All dApps interacting with the system must be identified by a valid address. This ensures that unauthorized or spoofed entities cannot manipulate profiles or fetch restricted data. | ||
|
||
11. **Phishing Mitigation**: User-facing dApps are encouraged to clearly display information about interactions on-chain. Users should be warned about potential phishing attacks and advised to interact only with verified dApps. | ||
|
||
12. **Gas Optimization**: Operations are optimized to prevent gas exhaustion during execution, which could lead to incomplete transactions. This ensures that even on congested networks, the system remains functional. | ||
|
||
13. **Secure Fallback Functions**: Fallback functions are implemented securely to prevent accidental Ether transfers or denial-of-service attacks. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |