Verifiably safe ENS registrations.
🚨 Everything in this repo is highly experimental software.
It is not secure to use any of this code in production (mainnet) until proper security audits have been conducted. It can result in irreversible loss of funds.
Aragon users, as well as most blockchain users in general, are plagued by Zooko's Triangle— addresses are secure and decentralized, but not human-friendly. Aside from being the most important of the three for wide-adoption, it should also be noted that human-friendliness may be considered an aspect of security: cryptographic addresses have been shown to be easy for users to innocently mistake and attackers to maliciously spoof.
Although several projects are building services to address this problem, such as uPort
and Civic, none are yet mature or readily available for mass-market
adoption. In light of this, Aragon ID is a simple identity system to bridge the gap until such
projects are ready. It leverages the existing ENS infrastructure to securely
provide two-way, first-in-first-served mappings of addresses to
Afterwards, users will be able to resolve and reverse-resolve any
<name>.aragonid.eth to an
address and trust that their name registrations are safely in their own control.
As summarized by Dan Finlay
and Nick Johnson
as part of the first ENS workshop, ENS subnode registrations are, by default, liable to be changed
by the owner of the node at any time. The node owner has the power to change the details of any
subnodes and can even transfer ownership of the node back to themselves by calling the auction
at any time. This problem persists all the down way to TLDs, as the ENS root is controlled by the
At its heart, Aragon ID is a collection of contracts that mitigate this lack of security for registrants of a subnode. It is heavily influenced by prior work from Nick Johnson.
In an Aragon Client
New users of Aragon should be recommended to register a human-friendly name under
<name>.aragonid.eth if they don't already have an ENS identifier associated with their address.
While the registration process is initially free and first-in-first-served, in the event of bad
actors or high demand, Aragon may require users to burn a number of Aragon Network Tokens
or another token as a cost of registration.
To fully register a name, two transactions from the user are required; unfortunately, there is no
secure way to to create a two-way registration (both address-to-name and name-to-address resolvable)
for a user in one transaction. As such, registration should first occur in the "forward" direction,
through the deployed FIFSBurnableRegistrar for
aragonid.eth, to secure a name. On its success, the "reverse" registration should be then be sent
to the existing ENS Reverse Registrar.
Note that users have full control of their
<name>.aragonid.eth subnode, and their registration may
be altered in the event of a transfer. Before using an identifier, Aragon clients should first check
that the address it resolves to has not changed.
Although Aragon previously integrated with Keybase, the existence of ENS now allows us to build an identity system that avoids relying on a centralized 3rd party. In doing so, we lost a number of features that were previously provided by Keybase, such as off-chain storage (e.g. profile photos or other service identitifers). In the future, we plan to integrate Aragon ID with decentralized off-chain storage services, such as Swarm or IPFS, to provide such functionality.
Finally, in the wake of upcoming identity services like uPort and Civic, it should be noted that Aragon ID works at the most basic level of Ethereum identities: account addresses. This means that users in the future will be able to associate their Aragon ID identifier to any identity that would be provided through a service, and vice-versa. Future users who come to Aragon with an existing identity may even opt to skip the Aragon ID registration process altogether.
As an example, in the case of the ongoing standardization of Ethereum identities,
a user of Aragon could be represented by an ERC725 identity contract that is registered to an Aragon
ID identifier. This identity contract would have a resolvable name and address, be allowed to
interact with an Aragon organization via its
ACTION keys, and be able to prove various details
about itself to an organization via its held claims.
In the future, an Aragon organization, possibly through a future Aragon app,
could also be a claims issuer for identities—the most basic of which could be claims about
membership or administration (e.g. "Brett Sun is the general director of Aradentity Inc.").
Slightly modified version of Nick Johnson's
DeedHolder acts as a holding repository for deeds (created by the auction registrar for each
registration). Once transferred, deeds, and their corresponding ENS nodes, are locked to the
DeedHolder until the original registrar is replaced. This prevents the node owner from being able
to control the ENS node directly and also disables their ability to call the registrar's
transfer() to re-gain full control of the node.
Given that the migration process to the new registrar is unknown at this time and may require multiple operations, ownership of the deed will need to be transferred to a contract whose logic is likewise unknown. This new owner in charge of the migration would ideally be decided via some governance mechanism, such as a community multisig. Once the migration is complete, the deed should again be locked to ensure that the node cannot be tampered with.
claim(bytes32 node): Re-claim the deed from the
DeedHolderwhen the original registrar has been replaced by a new registrar
owner(bytes32 node) returns(address): Returns the current owner of the deed
transfer(bytes32 node, address newOwner): Transfer ownership of the deed (note that the new "owner" still has no access to the deed until it becomes claimable)
DelegatingDeedHolder (is DeedHolder)
DeedHolder that allows the owner of the deed to set a "manager" for the node (i.e. become the
owner of the ENS node) to allow an external party or contract to manage subnode registrations.
DeedHolder by itself makes it impossible for any future changes to be made to the held
ENS node, as the process of transferring the deed also sets the
DeedHolder as the owner of the
setManager(bytes32 node, address manager): Set the manager for the ENS node tied to the deed. Preferrably a registrar contract (see below).
implementation that also sets the resolver (and the corresponding address mapping, if the registry
supports the address interface) when a subnode is claimed.
register(bytes32 subnode, address owner): Register the subnode with the default resolver, if not already claimed
registerWithResolver(bytes32 subnode, address owner, AbstractPublicResolver resolver): Register the subnode with the given resolver, which must conform to the Resolver spec
FIFSBurnableRegistrar (is FIFSResolvingRegistrar)
FIFSResolvingRegistrar that allows the owner to set a price (in a token) for registering
subnodes. Tokens used in this way will be burned by being sent to
0xdead. Supports the
register(bytes32 subnode, address owner): Register the subnode with the default resolver, if the
ownerhas pre-approved the contract for at least the registration cost. This operation will fail if burning the token through `token.transferFrom(owner, "0xdead") fails.
registerWithResolver(bytes32 subnode, address owner, AbstractPublicResolver resolver): Register the subnode with the given resolver, which must conform to the Resolver spec, if the
ownerhas pre-approved the contract for at least the registration cost
setBurningToken(ERC20 burningToken): Set the token to be burned when there is a registration cost
setRegistrationCost(uint256 cost): Set the cost of registering a subnode
receiveApproval(address from, uint256 amount, address token, bytes data):
ApproveAndCallReceiverimplementation, for tokens that support the
DelegatingDeedHolder contracts are meant to be used for the initially
deployed set of ENS contracts (specifically, the auction registrar).
Assuming those are available, your flow will probably be something like (in pseudo-JS):
// Contract instancesconst ens = '...'const publicResolver = '...'const auctionRegistrar = '...'const token = '...'// Deploy contractsconst deedHolder = DelegatingDeedHolderconst nodeRegistrar = FIFSBurnableRegistrar// Transfer deed ownership to the deed holder and set up the nodeRegistrar as the managerauctionRegistrardeedHolder// Register via token.approve()tokennodeRegistrar// Register via token.approveAndCall()token// Eventually reclaim ownership of deed, when the registrar has been updateddeedHolder
Installing (for Web3 projects)
You can pull exported ABIs via the
/abi folder, e.g.
const DeedHolderAbi = require('@aragon/id/abi/DeedHolder.json).abi
npm installnpm test