Brainstorming: This might be stupid but what if we assert and store on-chain that a name is valid? The equivalent of a “blue” checkmark?
Imagine a master contract, with the following pseudocode:
interface IValidator {
function validate(uint24[] cps);
}
mapping (uint256 => address) validated;
mapping (address => uint256) ranks;
address[] validators;
address emoji;
function setEmojiFilter(address) onlyDAO; // upgradable emoji
function setValidator(address, uint256 rank) onlyDAO; // set 0 to invalidate
function hasEmoji(string name) returns (bool);
function getValidatorRank(address) returns (uint256);
function getNameRank(string name) returns (uint256);
function getNodeRank(uint256 node) returns (uint256);
function getBatchRank(string[] names) returns (uint256[]);
// return true if name is validated by validator
// return false is name is already validated by a better validator
// revert if name is invalid
function validate(address validator, string name, bool hasEmoji) returns (bool) {
uint256 rank = getValidatorRank(validator);
require(rank > 0, "not a validator");
uint256 node = namehash(name);
address validator0 = validated[node];
if (validator0 != address(0x0)) { // prior validation exists
uint256 rank0 = getValidatorRank(validator0);
if (rank0 > 0 && rank0 <= rank) return false; // prior rank is better
}
uint24[] cps = UTF8.decode(name);
if (hasEmoji) cps = Emoji(emoji).filter(cps);
IValidator(validator).validate(cps);
validated[node] = validator;
return true; // valid
}
function willValidate(address validator, string name, bool hasEmoji) view {
uint256 rank = getValidatorRank(validator);
require(rank > 0, "not a validator");
uint24[] cps = UTF8.decode(name);
if (hasEmoji) cps = Emoji(emoji).filter(cps);
IValidator(validator).validate(cps);
}
To check if a name is valid: getNameRank("raffy.eth") > 0
To validate a name (this could be one-button on a website or part of the registration/renew process):
- You normalize your name.
- You eth_call
hasEmojito see if your name has emoji. - You eth_call
validators()to get a list of validator contracts. - You loop through the validators and find the most efficient one/best rank that
willValidate() - You submit a tx for
validate()with that contract, if your name has emoji, and the name. On success, it associates the node of the name with the address of contract that validated it.
Validations never expire. However, the underlying validator can get revoked by the master contract. Anyone can validate any name. Validator ranking can be used for filtering/trust and preventing someone from “downgrading” a strongly-validated name to more complex validator.
Validator ranking can also be used client-side: simply error if the name isn’t validated or if it has a rank above some threshold. Ranks could be associated with a color.
0 = Invalid
100 = Basic /^[a-z0-9-_]+/
200 = Valid ASCII
200 = Just Arab Digits
300 = Latin (single-script)
300 = Greek (single-script, no overlapping confusables)
Validators only need to implement codepoint validation on non-emoji output characters.
Validators only need to validate a subset of the valid name space.
A separate contract will be needed to efficiently perform NFC QuickCheck (to ensure a name is in NFC) for complex charsets.
The DAO could vote to approve new validation contracts. Each language could have a separate/multiple validator contracts. You could even have a non-algorithmic validator contract that simply has an append-only list of approved names. The ranks of each validator can be adjusted by the DAO if a problem is found.
If the ENS registrar was provided a hint of what validator to use (possibly through the commitment), it could call validate during registration.