At Fractal, we’re focused on improving the ICO experience, from both a UX and a regulatory compliance perspective. One of the crucial bits of a successful ICO is proper participation eligibility verification (KYC, AML, CFT, capital markets regulations, etc). As such, we’re closely watching the identity space, following projects such as Sovrin, Taqanu, uPort, and Civic, and experimenting with potential integrations.
Fabian Vogelsteller, the creator of the Mist Browser and web3.js, is working on a new identity standard for Ethereum, ERC 725. When used together with his other brainchild ERC 735, a standard for the management of identity claims, it is a very powerful tool for working with real identities on-chain.
Inspired by Nick Poulden, who took these standard drafts and created a great visual demonstration of how they can be combined, I decided to put together a small write-up that’s more focused on code.
One of the best things about ERC 725 and 735 is that they’re open, community-driven, and participatory standards. They’re also quite simple to understand, as they’re small, targeted standards which do one thing each but do it really well: manage identities and claims on those identities.
The following describes standard functions for a unique identity for humans, groups, objects and machines.This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self attested (#ERC735), as well as a proxy function to act directly on the blockchain.
ERC 725 is a standard for publishing and managing an identity via a smart contract on an EVM-based blockchain, such as Ethereum. This identity is represented by its chain address.
We can associate several keys with this identity. These keys can have different purposes: the standard currently proposes MANAGEMENT
, ACTION
, CLAIM
and ENCRYPTION
. Keys are keccak256
s of public addresses¹, and as such map to externally owned accounts (wallets) or smart contracts.
Another important concept is that an ERC 725 contract can be used as a proxy, through its execute
/ approve
methods. If a third party recognizes the legitimacy of a given identity contract, its owner can call execute
on it to transact with said third party, as we’ll see below in our KYC example.
Multiple keys are particularly useful in the context of privileged access. For example, suppose this identity is not for an individual, but an organization. Members holding less privileged keys can submit transactions to execute
, but only those with access to higher-privilege keys can approve
the execution of those transactions.
We can go even further down this rabbit hole. Since keys can also map to smart contracts instead of wallets, further access requirements could potentially be implemented. For example, having an ACTION
key which maps to an AccessControl
contract allows us to build arbitrarily complex access control levels in this contract. This is important because it keeps the standard itself simple, while simultaneously supporting every imaginable use case.
Another example has to do with revoking claims. If we’re using our identity to make claims on another identity, it can be useful to have several CLAIM
keys — deleting any one of them would cause the associated claims to lose their validity.
For a real-world example, suppose Mozilla has an Identity contract. Aside from whatever else Mozilla chooses to do with that identity, The Firefox software team could hold one of the keys belonging to that identity, with which they’d sign software checksums upon release.
For our KYC use case, described below, we proposed a change to the standard which would make execute
a payable
method, allowing us to forward Ether with the transaction to execute. An alternate approach would be to use two separate transactions: send Ether to the contract first, and then move it with execute
.
The following describes standard functions for adding, removing and holding of claims. These claims can attested from third parties (issuers) or self attested.
This standardised claim holder interface will allow Dapps and smart contracts to check the claims about a claim holder. Trust is here transfered to the issuers of claims.
ERC 735 deals with the management of claims made about an ERC 725 identity. It facilitates an emergence of a web of trust, by relying on the claims of trusted third parties about a given identity.
These claims can be of several topics, from biometric data, to email account ownership. This is particularly useful for our KYC use case, described below. As ICO issuers, we can work with a trusted KYC provider to determine whether or not an investor is eligible for purchasing tokens.
In order for someone to add a claim to their identity, they must first request it of a relevant trusted third party. This third party (the claim issuer) will sign a message containing three items: the identity’s address, the claim topic, and optionally some data to go along with it (for example, a hash of the KYC data). The identity owner would then store this claim in their identity contract (alternatively, the claim issuer can also add the claim themselves, which would have to be approved by the identity owner).
Note that claims can also be self-attested, which can be enough for a lot of other use cases (email and name come to mind, for simple applications with no strict KYC requirements, like a regular news website).
This demo considers the following entities.
After compiling the contracts, our demonstration takes the following steps.
CLAIM
key to its identity contract.I took Origin’s implementation of the standards as a starting point for this work. I had to slightly change the way they worked: because of the payable
issue described above, this implementation wasn’t prepared to relay value to the execution target. Here’s a simple inheritance diagram of the contracts, for clarity.
+---------------+ +---------------+| | | || ERC 725 | | ERC 735 || | | |+-------+-------+ +-------+-------+^ ^| |+-------+-------+ || | || KeyHolder | || | |+-------+-------+ |^ || |+-------+-------+ || | || ClaimHolder +-------------+| |+---------------+
The token and crowdsale contracts were lifted out of OpenZeppelin Solidity.
In order to deploy and interact with these contracts, I used web3.js to put together a simple JS script. (here’s the full repo if you’re curious)
Both Fractal ID and Investor need to deploy a ClaimHolder
contract, in order to hold all their keys and claims⁴. This contract implements both ERC 725 and ERC 735.
After deployment, Fractal ID will create a CLAIM
purpose key. This is the key associated with the signature of KYC claims.
var fractalIdClaimsKey = web3.utils.keccak256(fractalIdClaimsAccount);
fractalIdClaimHolder.methods.addKey(fractalIdClaimsKey,KEY_PURPOSES.CLAIM,KEY_TYPES.ECDSA,).send({from: fractalIdAccount,gas: 4612388,});
As described above, the key is the keccak256
hash of the address of its controlling account. Fractal ID calls the addKey
method on the ClaimHolder
contract (ERC 725), passing it this key, the key’s purpose
, and its keyType
.
Finally, Very Good needs to deploy their token and crowdsale contracts, and transfer VeryGoodCoin
’s ownership to the VeryGoodCrowdsale
contract, so it can mint tokens as needed to reward contributions.
veryGoodCoin.methods.transferOwnership(veryGoodCrowdsale.options.address,).send({from: veryGoodAccount,});
After Investor goes through Fractal ID’s online KYC process, Fractal ID signs a KYC claim.
var hexedData = web3.utils.asciiToHex("Investor is VBR V0 legit.");var hashedDataToSign = web3.utils.soliditySha3(investorClaimHolder.options.address,CLAIM_TYPES.KYC,hexedData,);var signature = await web3.eth.sign(hashedDataToSign,fractalClaimsAccount,);
Fractal ID then facilitates this signed claim to Investor, who adds it to their identity contract³.
var claimIssuer = fractalIdClaimHolder.options.address;var addClaimABI = await investorClaimHolder.methods.addClaim(CLAIM_TYPES.KYC,CLAIM_SCHEMES.ECDSA,claimIssuer,signature,hexedData,"https://www.trustfractal.com/business/",).encodeABI();
investorClaimHolder.methods.execute(investorClaimHolder.options.address,0,addClaimABI,).send({gas: 4612388,from: investorAccount,});
This is done through the addClaim
method (ERC 735) on the ClaimHolder
contract, which we feed a topic
, a scheme
, the issuer
, the signature
, the data
, and a uri
⁵.
The way execute
works is as follows. We pass it a destination address, an Ether value, and a serialized method call. If we call it with a MANAGEMENT
or ACTION
key, the request gets approved and executes. If we call it with a key of any other purpose, a higher privilege key has to subsequently approve the execution.
In order for Investor to participate in the ICO, we’ll also be making use of the execute
method. The case here is much easier to understand: as Fractal ID’s identity claim is present on Investor’s identity contract, and Very Good’s crowdsale contract will be checking for a KYC claim on the message sender, this contract must necessarily be the caller.
var investABI = veryGoodCrowdsale.methods.buyTokens(investorClaimHolder.options.address).encodeABI();
var investmentAmount = web3.utils.toWei("1", "ether");investorClaimHolder.methods.execute(veryGoodCrowdsale.options.address,investmentAmount,investABI,).send({gas: 4612388,from: investorAccount,value: investmentAmount,});
All checks should pass now, and Very Good’s crowdsale contract will mint new tokens and assign their ownership to Investor’s identity contract! 🎉
Thanks to Fabian Vogelsteller, Hugo Peixoto and João Gradim for reading drafts of this post.
¹ More precisely, _keccak256_
is only recommended by the standard for non-hex and keys longer than 32 bytes.
² Fractal ID could also do this on behalf of Investor.
³ There’s another flow suggested by ERC 725, which is for Fractal ID to call _addClaim_
on the Investor contract. This claim could be accepted by the Investor’s identity contract immediately, or undergo an approval process first.
⁴ Technically, a _KeyHolder_
contract for Fractal ID would suffice.
⁵ Note that we’re using _encodeABI_
to serialize the _addClaim_
method call, and piping it through _execute_
. Investor could instead have called _addClaim_
directly, using the account mapping to the appropriate privileges.
Planning an ICO? At Fractal, we offer a hassle-free, user-friendly launchpad solution combined with a comprehensive customer identification service (KYC/AML) to successfully deploy your token launch with ease.