Usernames is a important feature for Status, as it will help users find each other, replacing the need of passing pub-keys or qr codes. Also might be useful for users that want to identify themselves in public chats.
The security concerns with Usernames are the same we have in web2, with characters that are similar but a different bytecode were used in past very creatively by scammers.
Not just this, there’s also some special words, that shouldn’t be held by anyone, such as support
.
The main approach to safeguard users is not displaying those names, however is also possible to introduce another protection in the smart contract itself.
The way ENS is designed makes not possible for the contract actually know what names are being registered, instead it works with hashes of those names, so it should never be possible to prevent someone to register anything not registered yet.
However, is possible to be revealed for the smart contract the username, proving it’s against the defined rules, like a slashing mechanism to punish whoever tries to use a illegal username and reward the first reporter.
Currently I’m working on a smart contract for ENS Usernames that have 4 slashing conditions, which I described below.
Slashing conditions
Non alphanumeric characters.
We want to make usernames simple. Why someone would want a username with a complicated character? Probably to scam people or abuse a system.
So the allowed characters are a
to z
and 0
to 9
, everything else, including minus, underline, uppercase characters will produce a username able to be slashed by anyone knowing the offending username.
/**
* @notice Slash username that contains a non alphanumeric character.
* @param _username Raw value of offending username.
* @param _offendingPos Position of non alphanumeric character.
*/
function slashInvalidUsername(
bytes _username,
uint256 _offendingPos
)
external
{
require(_username.length > _offendingPos, "Invalid position.");
byte b = _username[_offendingPos];
require(!((b >= 48 && b <= 57) || (b >= 97 && b <= 122)), "Not invalid character.");
slashUsername(_username);
}
Less then 5 characters
(carl.stateofus.eth = invalid, alice.stateofus.eth = valid)
Too small usernames are too rare and may cause competition in registering them. Maybe could be less then 4, but I don’t think anyone needs usernames that small.
/**
* @notice Slash username smaller then `usernameMinLenght`.
* @param _username Raw value of offending username.
*/
function slashSmallUsername(
bytes _username
)
external
{
require(_username.length < usernameMinLenght, "Not a small username.");
slashUsername(_username);
}
Reserved words
Some common words, specially used in the ecossytem, should be prevented from being registered to avoid scams, such as support
, ethnotice
, and statusnetwork
, and also others that might be potentially interesting for future uses, such as teller
or openbounty
. Personally I think that status should have its own domain for pointing its services, an leave stateofus.eth
just for usernames, however, to still avoid this confusions, we should reserve all words we can think of.
The list can be heavy, as the contents can stored in the smart contract as merkle tree.
The current list of reserved words is available here: https://github.com/status-im/ens-usernames/blob/master/config/ens-usernames/reservedNames.js
/**
* @notice Slash usernmae that is exactly a reserved name.
* @param _username Raw value of offending username.
* @param _proof Merkle proof that name is listed on merkle tree.
*/
function slashReservedUsername(
bytes _username,
bytes32[] _proof
)
external
{
require(
MerkleProof.verifyProof(
_proof,
reservedUsernamesMerkleRoot,
keccak256(_username)
),
"Invalid Proof."
);
slashUsername(_username);
}
Start with 0x
and the 5 following chars are hex
To avoid users registering usernames that look like an address, the contract read if the first part of any supplied username start looking like an address, if so, it can be slashed.
/**
* @notice Slash username starting with "0x" and with lenght greater than 12.
* @param _username Raw value of offending username.
*/
function slashAddressLikeUsername(
string _username
)
external
{
bytes memory username = bytes(_username);
require(username.length > 12, "Too small to look like an address.");
require(username[0] == byte("0"), "First character need to be 0");
require(username[1] == byte("x"), "Second character need to be x");
slashUsername(username);
}
Slashing Consequences
When a username is slashed, it gets the resolver and ownership unset (set to zero) and the funds held by that name are send to the slasher.
/**
* @dev Removes account hash of `_username` and send account.balance to msg.sender.
* @param _username Username being slashed.
*/
function slashUsername(bytes _username) internal {
bytes32 label = keccak256(_username);
bytes32 namehash = keccak256(abi.encodePacked(ensNode, label));
uint256 amountToTransfer;
if(accounts[label].creationTime == 0) {
require(
ensRegistry.owner(namehash) != address(0) ||
ensRegistry.resolver(namehash) != address(0),
"Nothing to slash."
);
} else {
amountToTransfer = accounts[label].balance;
delete accounts[label];
}
ensRegistry.setSubnodeOwner(ensNode, label, address(this));
ensRegistry.setResolver(namehash, address(0));
ensRegistry.setOwner(namehash, address(0));
if (amountToTransfer > 0) {
reserveAmount -= amountToTransfer;
require(token.transfer(msg.sender, amountToTransfer), "Error in transfer.");
}
emit UsernameOwner(namehash, address(0));
}
(note this function is internal, called when a slashing condition is met)
Automatic Slashing
The idea is that Status Wallet client and Status Nodes automatically suggest slashing a username when they are revealed to it.
Status Mobile, when a user chats in public chat and reveal their username, or when a user receives a message from a user that reveals it invalid username, a message box will be prompted to user asking them to slash username or broadcast its name to network (for other slashing it).
Status Node, when a user reveals invalid name in public chat or when Status Mobile broadcast a privately revealed invalid username.
We are reserving usernames for people?
No, this is not intended to reserve usernames for people. The contract could be extended to support a feature like this, but that’s not the original reason of introducing this changes.
We could also modify the contract to allow controller to register a reserved username for an address, which then would not be slashable.
What happen to squatted usernames of celebrities?
My personal opinion is “nothing”, but if this starts hurting ecossystem is possible to fix squatted usernames through contract upgrade,
The new contract would be able to clear ENS entries but not take the funds, because they are in the older contract, where anyone then would be able to release their funds (but they wouldn’t need to).
The reserved usernames then would be able to be repurposed by Status Network Democracy.
This
Why not just ignoring those illegal usernames?
The advantage of having the slashing in the smart contract is that interoperable systems that use ENS will also use that rules, would be not just a “cosmetic change”, but ideally the contract don’t allow such registers to exist.
Also, instead of ignoring the invalid usernames, user is alerted and can take an action which will lead to this user profit and attacker loss.
Slashing conditions can change?
Note that Slashing conditions will not be changeable by contract Controller, but an upgrade of the contract could change it, and users that accept that change would be able to migrate their funds and keep the name, or withdraw and release the name, just like in any UsernameRegistrar
contract upgrade. The users also have the option to do nothing and keep using their usernames, specially if they don’t hurt the “new agreement”.
This was important to ensure safety of funds of community at any circumstance, therefore the way is designed it would be impossible to offend the proposed terms, even if is the will of the Controller, and also don’t become a trouble to normal users.
I want the opinion of the community about the slashing conditions and what else we can make to make usernames safer to everyone.
Also a help in reviewing the reserved usernames, specially the part with crypto community related names.