Because of the open-ended nature of resolvers, it can be daunting to begin writing one. Below are some hints to get you started.
While not strictly necessary, resolvers are strongly recommended to enforce that calling EINs
have set your Resolver
via code that looks something like the following:
require(identityRegistry.isResolverFor(ein, address(this)), "The EIN has not set this resolver.");
While Resolvers are of course free to let anyone they wish interact with their smart contract, they should, in most cases, restrict use to Identities
who currently have their address set as a Resolver
. This is helpful so that front-ends can know which Resolvers a given entity has set, and can also facilitate inter-Resolver
logic.
There are several routes a Resolver
could take when choosing how to let Identities
interact with their smart contracts. Resolvers
are recommended to implement one or more of the best practices outlined below.
Before diving in, let's first sketch out an updateInformation
function that we want to call. Say it modifies data associated with an Identity
.
// perform the desired operations on the EIN's Identity
function updateInformation(...) ... {
...
}
Obviously, we have to be careful about who can call this function, and how calls are permissioned to affect the data of Identities
.
The first and simplest option is to allow any associatedAddress
of an identity to call updateInformation
by simply looking up their EIN
from the 1484 registry via getEIN
. All further operations can now use that EIN
.
function updateInformation(...) public {
uint ein = identityRegistry.getEIN(msg.sender);
...
}
Some users, though, might not want to interact with our Resolver
directly. They might instead prefer to do so through a Provider
. In this case, we want to allow a Provider
to call updateInformation
on behalf of an EIN. For this not to be an anti-pattern, we must:
- Ensure that any time we receive a call from a
Provider
on behalf of anEIN
, theEIN
in question has actually set thisProvider
. This is easily achieved by code that looks something like the following:
function updateInformation(uint ein, ...) public {
require(identityRegistry.isProviderFor(ein, msg.sender));
...;
}
- Be convinced that
Providers
have appropriately permissioned their smart contracts so that we can trust that the calls we receive actually represent the intent of theEIN
. (For example, apublic
function that triggersEIN
-specific logic on yourResolver
will probably be abused!) To this point, it is often enough to trust thatProviders
are treating permissions appropriately (see BuildingProviders.md forProvider
best practices around this issue). Cases whereProviders
may not be operating as securely as possibly can be chalked up to user error, and plausibly don't have to be handled by individualResolvers
. However, if aResolver
wishes to use only a trusted subset ofProviders
, or utilize the functionality of one particularProvider
, they are of course free to do so with code that looks something like the following:
function updateInformation(uint ein, ...) public {
require(msg.sender == 0x...); // ensure that the calling address is e.g. a pre-determined whitelisted Provider
require(identityRegistry.isProviderFor(ein, msg.sender));
...;
}
This is an anti-pattern for a Resolver
, and is not recommended. For cases in which it's absolutely necessary, refer to the BuildingProviders.md best practices.
This is an anti-pattern for a Resolver
. For cases in which it's absolutely necessary, onlyOwner
calls may be made like so:
function updateInformation(uint ein, ...) public onlyOwner() {
...;
}