This proposal defines two core interfaces: IUniversalIdentity and IUniversalCharter, providing mechanisms for humans, and robots to establish their identities and to create decentralized communities governed by specific rule sets. The IUniversalIdentity interface establishes the fair and equitable treatment of sentient computer architectures other than the human brain, enabling robots to acquire on-chain identities, and thereby interact and transact with humans. The IUniversalCharter enables humans and robots to create, join (“register”), maintain (“update”), leave, and terminate self-regulated societies based on predefined rule sets, providing a framework for collaboration and prosperity for mixed societies of humans and robots. These interfaces aim to provide a flexible yet enforceable structure for human-robot interactions in decentralized systems, ensuring efficiency, transparency, and security for all participants.
Motivation
The human brain is a wet, massively parallel electrochemical computer. Recent hardware and software advances make it likely that soon, human societies will need tools for interacting with sentient, non-human computers, such as robots. Our current forms of government, where citizens are auto-enrolled into specific rule sets depending on where they were born, do not gracefully map onto robots without a traditional birthplace or birthtime. Among many difficulties being experienced by robots, they are (currently) unable to obtain standard forms of ID (such as passports), it is not clear which rule sets apply to them (since in general they are not born in specific places), and they cannot currently use the standard human-centered banking system. Likewise, in the event in which robots are harmed by humans or non-biological computers, it is not clear which human court has jurisdiction.
Traditional geographically-defined and human-centered systems can be inefficient, slow to change, opaque, and can struggle to accommodate global, virtualized societies. Decentralized, immutable, and public computers offer an ideal solution to these limitations, since they do not inherently discriminate against non-human computers and therefore offer an equitable and more just framework for governance. In particular, smart contracts can provide a powerful framework for regulating the rights and responsibilities or interacting parties regardless of implementation details of their compute architecture.
The general motivation of this ERC is to provide a standard interface for smart contracts focusing on identity/governance for heterogeneous global societies. While there are an unlimited number of such rule sets, there are obvious benefits to providing a standard interface to those rule sets, greatly reducing the friction and complexity of creating, joining, maintaining, and ending such societies. The specific motivation of this ERC is twofold:
Robot Identity Creation and Management: To participate meaningfully and comply with on-chain laws, non-humans such as robots must be able to acquire meaningful on-chain identities. Importantly, these identities should enable robots to enjoy the benefits of, but also bear the responsibility of, being part of a specific society. Thus, we propose to enable smart contract-based identity for robots. Specifically, each robot is represented by a smart contract and needs to follow the rules defined in the contract to interact with other agents on the chain. This interface also ensures flexibility by all participants to propose, adopt, or revoke rules, enabling self-managed compliance and transparent interaction with other participants.
Rule Creation and Enforcement: For humans and robots to effectively collaborate, they must agree upon a rule set. This Ethereum-based system provides a basic decentralized framework for governing human-robot interactions through smart contracts. We propose to enforce the rule-sets by requiring humans and robots to join regulated access smart contracts that check their compliance with the given rules. We also ensure scalability, whereby multiple regulated access contracts can be created to tailor to different purposes, and humans and robots can choose to join the relevant system as needed.
Together, these interfaces form the foundation for managing complex human-robot interactions, enabling a decentralized, verifiable, and rule-based ecosystem where robots and humans can interact securely, transparently, and responsibly, for maximum benefit of all.
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.
interfaceIUniversalIdentity{/// @notice Adds a rule to the robot's identity, showing that the robot agrees to follow the rule.
/// @param rule The dynamic byte array representing the rule that the robot agrees to follow. Each rule is a textual string encoded into a dynamic byte array. For example: 'A robot must keep a 1m distance from humans.'
/// @dev The rule SHOULD come from the rule sets defined in the IUniversalCharter contract that the robot intends to join.
/// @dev This function SHOULD be implemented by contracts to add the rules that the robot intends to follow.
functionaddRule(bytesmemoryrule)external;/// @notice Removes a rule from the robot's identity.
/// @param rule The dynamic byte array representing the rule that the robot no longer agrees to follow.
/// @dev This function SHOULD be implemented by contracts to remove the rules that the robot does not intend to follow.
functionremoveRule(bytesmemoryrule)external;/// @notice Checks if the robot complies with a specific rule.
/// @param rule The rule to check.
/// @return bool Returns true if the robot complies with the rule.
/// @dev This function MUST be implemented by contracts for compliance verification.
functioncheckCompliance(bytesmemoryrule)externalviewreturns(bool);/// @dev Emitted when a rule is added to the robot's identity.
eventRuleAdded(bytesrule);/// @dev Emitted when a rule is removed from the robot's identity.
eventRuleRemoved(bytesrule);/// @dev Emitted when a charter is subscribed to.
eventSubscribedToCharter(addressindexedcharter);/// @dev Emitted when it is unsubscribed from a charter.
eventUnsubscribedFromCharter(addressindexedcharter);}interfaceIUniversalCharter{// Define the user types as an enum.
enumUserType{Human,Robot}/// @notice Registers a user (human or robot) to join the system by agreeing to a rule set.
/// @param userType The type of user.
/// @param ruleSet The array of individual rules the user agrees to follow.
/// @dev This function MUST be implemented by contracts using this interface.
/// @dev The implementing contract MUST ensure that the user complies with the specified rule set before registering them in the system by invoking `checkCompliance`.
functionregisterUser(UserTypeuserType,bytes[]memoryruleSet)external;/// @notice Allows a user (human or robot) to leave the system
/// @dev This function MUST be callable only by the user themselves (via `msg.sender`).
/// @dev The implementing contract MUST ensure that the user has complied with all necessary rules before they can successfully leave the system by invoking `checkCompliance`.
functionleaveSystem()external;/// @notice Checks if the user (human or robot) complies with the system’s rules.
/// @param user Address of the user (human or robot).
/// @param ruleSet The array of individual rules to verify.
/// @return bool Returns true if the user complies with the rule set.
/// @dev This function SHOULD invoke the `checkCompliance` function of the user’s IUniversalIdentity contract to check for rules individually.
/// @dev This function MUST be implemented by contracts for compliance verification.
functioncheckCompliance(addressuser,bytes[]memoryruleSet)externalviewreturns(bool);/// @notice Updates the rule set.
/// @param newRuleSet The array of new individual rules replacing the existing ones.
/// @dev This function SHOULD be restricted to authorized users (e.g., contract owner).
functionupdateRuleSet(bytes[]memorynewRuleSet)external;/// @notice Terminates the contract, preventing any further registrations or interactions.
/// @dev This function SHOULD be restricted to authorized users (e.g., contract owner).
/// @dev This function SHOULD be implemented by contracts.
functionterminateContract()external;/// @dev Emitted when a user joins the system by agreeing to a set of rules.
eventUserRegistered(addressindexeduser,UserTypeuserType,bytes[]ruleSet);/// @dev Emitted when a user successfully leaves the system after fulfilling obligations.
eventUserLeft(addressindexeduser);/// @dev Emitted when a user’s compliance with a rule set is verified.
eventComplianceChecked(addressindexeduser,bytes[]ruleSet);/// @dev Emitted when a rule set is updated.
eventRuleSetUpdated(bytes[]newRuleSet,addressupdatedBy);}
Rationale
IUniversalIdentity
addRule(bytes memory rule)
This function allows a robot to flexibly adopt new compliance requirements in order join different IUniversalCharter contracts.
removeRule(bytes memory rule)
This function allows a robot to dynamically manage and maintain its rules, ensuring that its rule set remains up-to-date.
checkCompliance(bytes memory rule)
This function ensures that a robot is adhering to rules by performing decentralised checks on its compliance.
Events (RuleAdded, RuleRemoved)
These events provide transparency and traceability, making it easier to track compliance status.
IUniversalCharter
enum UserType { Human, Robot }
The UserType enum makes it easier for contracts to handle different user types without the cost and errors associated with strings. This provides the basis for differentiated handling in future implementations, allowing the system to potentially apply different rules or logic based on whether the user is a human or a robot.
registerUser(UserType userType, bytes[] memory ruleSet)
This function ensures that a user—whether human or robot—is bound to a particular set of rules upon joining the system.
leaveSystem()
This function allows users to flexibly and securely leave a IUniversalCharter contract after compliance is checked.
checkCompliance(address user, bytes[] memory ruleSet)
This function ensures that the system can efficiently manage and verify compliance against predefined rule sets, helping maintain the overall integrity of the system.
updateRuleSet(bytes[] memory newRuleSet)
This function enables the IUniversalCharter contract to adapt and update, removing the need to create a new contract for ruleset updates.
terminateContract()
This function allows for the orderly and permanent shutdown of the contract.
Events (UserRegistered, UserLeft, ComplianceChecked, RuleSetUpdated, ContractTerminated)
These events collectively ensure that key activities are visible to off-chain systems and participants, making the system auditable and transparent.
Backwards Compatibility
No backward compatibility issues found.
Reference Implementation
// SPDX-License-Identifier: CC0-1.0
pragmasolidity^0.8.19;import{OwnableUpgradeable}from"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";import{UniversalCharter}from"./UniversalCharter.sol";// Interfaces
import{IUniversalIdentity}from"./interface/IUniversalIdentity.sol";import{IUniversalCharter}from"./interface/IUniversalCharter.sol";/// @title UniversalIdentity
/// @notice The UniversalIdentity contract is used to manage the identity of robots.
contractUniversalIdentityisIUniversalIdentity,OwnableUpgradeable{/// @notice Version identifier for the current implementation of the contract.
stringpublicconstantVERSION="v0.0.1";/// @notice Mapping to store rules that the robot has agreed to follow
mapping(bytes=>bool)privaterobotRules;/// @notice Mapping to store the off-chain compliance status for each rule
mapping(bytes=>bool)privatecomplianceStatus;/// @notice Track the charters the robot is subscribed to
mapping(address=>bool)privatesubscribedCharters;/// @notice Custom errors to save gas on reverts
errorRuleNotAgreed(bytesrule);errorRuleNotCompliant(bytesrule);errorRuleAlreadyAdded(bytesrule);/// @dev Event to emit when compliance is checked
/// @param updater The address of the compliance updater (owner of the contract)
/// @param rule The rule that was checked
eventComplianceChecked(addressindexedupdater,bytesrule);/// @notice Modifier to check if a rule exists
modifierruleExists(bytesmemoryrule){require(robotRules[rule],"Rule does not exist");_;}/// @notice Constructor to set the owner
constructor(){initialize({_owner:address(0xdEaD)});}/// @dev Initializer function
functioninitialize(address_owner)publicinitializer{__Ownable_init();transferOwnership(_owner);}/// @notice Adds a rule to the robot's identity
/// @param rule The dynamic byte array representing the rule that the robot agrees to follow.
functionaddRule(bytesmemoryrule)externaloverrideonlyOwner{if(robotRules[rule]){revertRuleAlreadyAdded(rule);}// Add rule to the mapping
robotRules[rule]=true;emitRuleAdded(rule);}/// @notice Removes a rule from the robot's identity
/// @param rule The dynamic byte array representing the rule that the robot no longer agrees to follow.
functionremoveRule(bytesmemoryrule)externaloverrideonlyOwnerruleExists(rule){robotRules[rule]=false;complianceStatus[rule]=false;emitRuleRemoved(rule);}/// @notice Subscribe and register to a specific UniversalCharter contract using its stored rule set
/// @param charter The address of the UniversalCharter contract
/// @param version The version of the rule set to fetch and register for
functionsubscribeAndRegisterToCharter(addresscharter,uint256version)external{require(!subscribedCharters[charter],"Already subscribed to this charter");subscribedCharters[charter]=true;// Fetch the rule set directly from the UniversalCharter contract using the public getter
bytes[]memoryruleSet=UniversalCharter(charter).getRuleSet(version);// Register as a robot in the charter using the fetched rule set
UniversalCharter(charter).registerUser(IUniversalCharter.UserType.Robot,ruleSet);emitSubscribedToCharter(charter);}/// @notice Leave the system for a specific UniversalCharter contract
/// @param charter The address of the UniversalCharter contract to leave
functionleaveCharter(addresscharter)external{require(subscribedCharters[charter],"Not subscribed to this charter");// Call the leaveSystem function of the UniversalCharter contract
UniversalCharter(charter).leaveSystem();// Unsubscribe from the charter after leaving
subscribedCharters[charter]=false;emitUnsubscribedFromCharter(charter);}/// @notice Updates compliance status for a rule (called by the owner)
/// @param rule The dynamic byte array representing the rule
/// @param status The compliance status (true if compliant, false if not)
functionupdateCompliance(bytesmemoryrule,boolstatus)externalonlyOwnerruleExists(rule){complianceStatus[rule]=status;emitComplianceChecked(msg.sender,rule);}/// @notice Checks if the robot has agreed to follow a specific rule and if it is compliant
/// @param rule The rule to check.
/// @return bool Returns true if the robot has agreed to the rule and is compliant
functioncheckCompliance(bytesmemoryrule)externalviewoverridereturns(bool){if(!robotRules[rule]){revertRuleNotAgreed(rule);}returntrue;}/// @notice Gets the compliance status of a rule
/// @param rule The rule to check.
functiongetRule(bytesmemoryrule)externalviewreturns(bool){returnrobotRules[rule];}/// @notice Gets the subscription status of a charter
/// @param charter The address of the charter to check.
functiongetSubscribedCharters(addresscharter)externalviewreturns(bool){returnsubscribedCharters[charter];}/// @notice Gets the compliance status of a rule
/// @param rule The rule to check.
functiongetComplianceStatus(bytesmemoryrule)externalviewreturns(bool){returncomplianceStatus[rule];}}
// SPDX-License-Identifier: CC0-1.0
pragmasolidity0.8.20;import{OwnableUpgradeable}from"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";import{SystemConfig}from"./SystemConfig.sol";// Interfaces
import{IUniversalCharter}from"./interface/IUniversalCharter.sol";import{IUniversalIdentity}from"./interface/IUniversalIdentity.sol";/// @title UniversalCharter
/// @notice The UniversalCharter contract is used to manage the registration and compliance of users.
contractUniversalCharterisIUniversalCharter,OwnableUpgradeable{/// @notice Struct to store information about a registered user
structUserInfo{boolisRegistered;UserTypeuserType;uint256ruleSetVersion;// Rule set version the user is following
}/// @notice Mapping to store registered users
mapping(address=>UserInfo)privateusers;/// @notice Mapping to store rule sets by version number
mapping(uint256=>bytes[])privateruleSets;/// @notice Mapping to track the rule set hash and its corresponding version
mapping(bytes32=>uint256)privateruleSetVersions;/// @notice Version identifier for the current implementation of the contract.
stringpublicconstantVERSION="v0.0.1";/// @notice Variable to track the current version of the rule set
uint256privatecurrentVersion;/// @notice Variable to store the address of the SystemConfig contract
SystemConfigpublicsystemConfig;/// @notice Error for when a method cannot be called when paused. This could be renamed
/// to `Paused` in the future, but it collides with the `Paused` event.
errorCallPaused();/// @notice Reverts when paused.
modifierwhenNotPaused(){if(paused())revertCallPaused();_;}/// @notice Constucts the UniversalCharter contract.
constructor(){initialize({_owner:address(0xdEaD),_systemConfig:address(0xdEaD)});}/// @dev Initializer function
functioninitialize(address_owner,address_systemConfig)publicinitializer{__Ownable_init();transferOwnership(_owner);systemConfig=SystemConfig(_systemConfig);}/// @notice Registers a user (either human or robot) by agreeing to a rule set
/// @param userType The type of user: Human or Robot
/// @param ruleSet The array of individual rules the user agrees to follow
functionregisterUser(UserTypeuserType,bytes[]memoryruleSet)externaloverridewhenNotPaused{require(!users[msg.sender].isRegistered,"User already registered");// Hash the rule set to find the corresponding version
bytes32ruleSetHash=keccak256(abi.encode(ruleSet));uint256version=ruleSetVersions[ruleSetHash];require(version>0,"Invalid or unregistered rule set");// For robots, ensure compliance with each rule via the UniversalIdentity contract
if(userType==UserType.Robot){require(_checkRobotCompliance(msg.sender,version),"Robot not compliant with rule set");}// Register the user with the versioned rule set
users[msg.sender]=UserInfo({isRegistered:true,userType:userType,ruleSetVersion:version});emitUserRegistered(msg.sender,userType,ruleSet);}/// @notice Allows a user (human or robot) to leave the system after passing compliance checks
functionleaveSystem()externaloverridewhenNotPaused{require(users[msg.sender].isRegistered,"User not registered");UserInfomemoryuserInfo=users[msg.sender];// For robots, verify compliance with all rules in the rule set
uint256version=userInfo.ruleSetVersion;if(userInfo.userType==UserType.Robot){require(_checkRobotCompliance(msg.sender,version),"Robot not compliant with rule set");}users[msg.sender]=UserInfo({isRegistered:false,userType:UserType.Human,ruleSetVersion:0});emitUserLeft(msg.sender);}/// @notice Checks if a user complies with their registered rule set
/// @param user The address of the user (human or robot)
/// @param ruleSet The array of individual rules to verify
/// @return bool Returns true if the user complies with the given rule set
functioncheckCompliance(addressuser,bytes[]memoryruleSet)externalviewoverridereturns(bool){require(users[user].isRegistered,"User not registered");// Hash the provided rule set to find the corresponding version
bytes32ruleSetHash=keccak256(abi.encode(ruleSet));uint256version=ruleSetVersions[ruleSetHash];require(version>0,"Invalid or unregistered rule set");require(users[user].ruleSetVersion==version,"Rule set version mismatch");// For robots, check compliance with each rule in the UniversalIdentity contract
if(users[user].userType==UserType.Robot){return_checkRobotCompliance(user,version);}// If the user is human, compliance is assumed for now (can be extended)
returntrue;}/// @notice Internal function to check compliance for robots with their rule set version
/// @dev This function will revert if the robot is not compliant with any rule. Returns true for view purposes.
/// @param robotAddress The address of the robot
/// @param version The version of the rule set to verify compliance with
/// @return bool Returns true if the robot is compliant with all the rules in the rule set
function_checkRobotCompliance(addressrobotAddress,uint256version)internalviewreturns(bool){IUniversalIdentityrobot=IUniversalIdentity(robotAddress);bytes[]memoryrules=ruleSets[version];for(uint256i=0;i<rules.length;i++){if(!robot.checkCompliance(rules[i])){returnfalse;}}returntrue;}/// @notice Updates or defines a new rule set version.
/// @param newRuleSet The array of new individual rules.
/// @dev This function SHOULD be restricted to authorized users (e.g., contract owner).
functionupdateRuleSet(bytes[]memorynewRuleSet)externalwhenNotPausedonlyOwner{require(newRuleSet.length>0,"Cannot update to an empty rule set");// Hash the new rule set and ensure it's not already registered
bytes32ruleSetHash=keccak256(abi.encode(newRuleSet));require(ruleSetVersions[ruleSetHash]==0,"Rule set already registered");// Increment the version and store the new rule set
currentVersion+=1;ruleSets[currentVersion]=newRuleSet;ruleSetVersions[ruleSetHash]=currentVersion;emitRuleSetUpdated(newRuleSet,msg.sender);}/// @notice Getter for the latest version of the rule set.
functiongetLatestRuleSetVersion()externalviewreturns(uint256){returncurrentVersion;}/// @notice Get the rule set for a specific version.
/// @param version The version of the rule set to retrieve.
functiongetRuleSet(uint256version)externalviewreturns(bytes[]memory){returnruleSets[version];}/// @notice Get the version number for a specific rule set.
/// @param ruleSet The hash of the rule set to retrieve the version for.
functiongetRuleSetVersion(bytes32ruleSet)externalviewreturns(uint256){returnruleSetVersions[ruleSet];}functiongetUserInfo(addressuser)externalviewreturns(UserInfomemory){returnusers[user];}/// @notice Getter for the current paused status.
/// @return paused_ Whether or not the contract is paused.
functionpaused()publicviewreturns(boolpaused_){paused_=systemConfig.paused();}}
Security Considerations
Compliance Updater: The compliance updater role in the UniversalIdentity contract is critical for updating compliance statuses (currently limited to the owner). It is essential to ensure secure ownership to minimize the risks of unauthorized or malicious updates.
Rule Management: Functions such as addRule, removeRule, and updateCompliance in the UniversalIdentity contract and updateRuleSet in the UniversalCharter contract directly affect rule enforcement. It’s essential to ensure these functions are only callable by authorized users.
Upgradeable Contracts: The use of OwnableUpgradeable introduces risks during the initialization and upgrade process. Ensuring that the initialize function is protected against re-execution is critical to avoid reinitialization attacks.
Gas Consumption: Excessively large rule sets could lead to high gas costs or DoS risks. Consider setting limits on the number of rules allowed per rule set to maintain gas efficiency and avoid performance issues.