Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

trustfractal/did_registry_demo

Repository files navigation

DID Registry demo

A guide on how to interact with Fractal's DID Registry.

See something wrong? Open up a pull request!

See something that's confusing or just not immediately obvious? Open up an issue!

⚠️ Work in Progress ⚠️

We're still building this guide. If you need help today, get in touch through [email protected].

Overview

To get our hands dirty with some mock data, we will go through:

  • Deploy our own copy of Fractal's DID Registry
  • Operation of the contract
  • Usage examples
    • One person, one vote
    • Require KYC approval for buying tokens

Deploy our own copy of Fractal's DID Registry

For these demonstrations, we'll deploy our own copy of Fractal's DID Registry. We'll be using Remix IDE, which includes an in-browser Ethereum implementation. This way we don't spend real money or have to chase down testnet faucets. Don't worry, real-world operation is effectively identical, everything you'll see here can also be done with Hardhat or any other EVM toolchain you prefer.

👁 Step-by-step demonstration

Let's get started! First off, let's start by deploying our own copy of a FractalRegistry.

  • Go to Remix IDE and clone this git repo as a workspace.

  • Compile and deploy the contracts/1_FractalRegistry.sol contract. Use your own address as the root constructor argument.

Operation of the contract

So, what does Fractal do with the contract? And, more importantly, what can we do with it?

On user KYC approval

When a user submits their documents and our identity specialist verify their identity, our servers call addUserAddress with two arguments:

  • the user's EVM address
  • a personally unique identifier, called fractalId

In order to be sure we're not duplicating users and we know their wallet address, a user needs to be onboarded with one of the following level combinations, with optionally more add-ons:

  • uniqueness+wallet
  • basic+uniq+wallet
  • plus+uniq+wallet
👁 Step-by-step demonstration

Let's use ourselves as an example. Let's pretend Fractal assigned us the fractalId of 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF.

  • Make a addUserAddress call with:

    • addr: our own address
    • fractalId: 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

Fractal's servers also make a few addUserToList calls with the relevant lists. Let's take a look at lists currently in use, and what it means for a user to be present in each of them.

listId Meaning
basic The user has passed the basic KYC level.
plus The user has passed the plus KYC level.
fatf_grey Resident of a country that's present in the FATF's list of jurisdictions under increased monitoring.
fatf_black Resident of a country that's present in the FATF's list of high-risk jurisdictions.
👁 Step-by-step demonstration

Let's pretend we've passed the Plus KYC level (plus).

  • Make a addUserToList call with:

    • userId: 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
    • listId: plus

Consulting state

With this data on the contract, we're now able to preform two operations: check if an address belongs to a unique user, and check which lists the users belongs to.

User uniqueness

By calling getFractalId with an address, you get back its controlling user's fractalId. If two addresses return the same identifier, you can be sure they belong to the same person. Conversely, if two addresses return different identifiers, you can be sure they belong to different people.

If getFractalId returns 0, that means the address isn't associated with any user known to Fractal. Be sure to check its return value!

👁 Step-by-step demonstration

Let's see how to contract responds to querying for own address, and an arbitrary address that's not in the contract.

  • Make a getFractalId call with:

    • addr: your own address
  • Verify that you get our fractalId back.

    0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

  • Make a getFractalId call with:

    • addr: some arbitrary valid address. Here's an example: 0x05a56E2D52c817161883f50c441c3228CFe54d9f
  • Verify that you get back zero:

    0x0000000000000000000000000000000000000000000000000000000000000000

KYC levels

After you get the user's fractalId, you can then check their presence on the Registry's lists with isUserInList, which enables you to effectively check their KYC status and/or FATF list presence.

Here are a few examples:

// Passed Basic KYC level
registry.isUserInList(fractalId, "basic")

// Passed Plus KYC level
registry.isUserInList(fractalId, "plus")

// Passed Basic or Plus KYC level
registry.isUserInList(fractalId, "basic") ||
    registry.isUserInList(fractalId, "plus")

// Passed Plus KYC level and is not in either FATF lists
registry.isUserInList(fractalId, "plus") &&
    !registry.isUserInList(fractalId, "fatf_grey") &&
    !registry.isUserInList(fractalId, "fatf_black")
👁 Step-by-step demonstration

Let's see how to contract responds to querying for own lists, and an some other arbitrary ones.

  • Make a isUserInList call with:

    • userId: 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
    • listId: plus
  • Verify that you get back true.

  • Make a isUserInList call with:

    • userId: 0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
    • listId: basic
  • Verify that you get back false.

On user change or document expiration

There's two other relevant public functions on the contract. Going over them briefly:

  • When a user removes (or changes) their associated EVM address, Fractal's servers call removeUserAddress appropriately (and, on change, also call addUserAddress).
  • When a user submits new information that changes their KYC status, Fractal's servers will make the appropriate removeUserFromList (and possibly addUserToList) calls to keep the user's on-chain information up-to-date.

Usage examples

One person, one vote

An example use case of fractalId's pre-person uniqueness is having a voting contract where you require the voter to be in the Registry and for a person to only be able to cast one vote, effectively requiring unique personhood and achieving Sybil-resistance.

Here's a simplified example:

function vote(uint8 option) external {
    bytes32 fractalId = FractalRegistry(OXADDRESS).getFractalId(msg.sender);
    require(fractalId != 0, "User must be present in FractalRegistry.");
    require(!hasVoted[fractalId], "Same person can't vote twice.");

    hasVoted[fractalId] = true;
    votes[option] += 1;
}
👁 Step-by-step demonstration

The Voting contract, which can be found at contracts/2_Voting.sol, only has 3 relevant operations:

  • Being deployed. Its constructor requires two arguments: the number of options we're voting for (i.e., how different choices are in our ballot) and the address for the FractalRegistry contract.
  • Vote. It takes a single argument, the option you're voting for.
  • Tallying the results. This returns the current vote count for each option.

Let's try it out and see how it behaves!

  • Compile and deploy the contracts/2_Voting.sol contract. For constructor arguments, use:

    • options: 4. Nothing special about this choice.
    • registryAddress: the address of the FractalRegistry we've been using.
  • Let's call currentTally. It should show that all four options have zero votes.

  • Let's call vote with option 1. It should succeed.

  • Let's call currentTally again. It should show that option 1 has one vote, and that options 0, 2, and 3 have all zero votes.

  • Let's try calling vote again. This time, it should fail, with the reason "Already voted: the same person can't vote twice."

  • Let's try calling vote with a different address, one that's not registered in our FractalRegistry contract. It should fail, with the reason "Unregistered user: user must be present in FractalRegistry."

  • Let's call currentTally again. Even though we tried to execute a bunch of invalid votes, it should return the same results as before.

Require KYC approval for buying tokens

An example use case of fractalId presence in specific lists is, in order to buy some ERC20 token, check that a user has passed KYC.

Here's a simplified example:

function buy() external payable {
  FractalRegistry registry = FractalRegistry(OXADDRESS);
  bytes32 fractalId = registry.getFractalId(msg.sender);
  require(
      fractalId != 0 && registry.isUserInList(fractalId, "plus"),
      "Non KYC-compliant sender: must have cleared `plus` level."
  );

  _mint(msg.sender, msg.value);
}
👁 Step-by-step demonstration

The DemoToken contract, which can be found at contracts/3_DemoToken.sol, is a toy ERC20 token with a buy function that, when it receives funds from a KYC-approved account with the plus level, mints (i.e. creates) new tokens.

In order to make things simpler, we're going to be reusing the OpenZeppelin's ERC20 implementation. It brings along a lot of standard ERC20 functions but, for this demo, we only care about balance, which will let us check our balance.

Let's try it out and see it working!

  • Compile and deploy the contracts/3_DemoToken.sol contract. For constructor arguments, use:

    • registryAddress: the address of the FractalRegistry we've been using.
  • Let's call balance for our own address. Since we didn't buy any tokens yet, it should be zero.

  • Let's call buy with 42 Wei. Since we're in the plus list, we should be successful!

  • Let's call balance again. It should now return 42.

  • In order to see an example of a non-compliant person trying to buy tokens, let's pretend our documents expired and Fractal's server took us off the plus list.

  • Let's try calling buy again. Since we're not in the plus list anymore, which is marked as required, the contract now refuses the transaction.

Using client-side JavaScript

Since the main goal of the DID Registry is to be a readable resource, you can also use it off chain directly from your dApp's code!

⚠️ TODO Add a brief web3.js example.

⚠️ TODO Add contract addresses (for the various networks) and ABI. They're now at https://github.com/trustfractal/registry-deployer/tree/master/deployments

⚠️ TODO Point people at https://github.com/trustfractal/did-registry-demo-dapp

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published