Linking an Identity

This document describes how to use the Litentry’s client-sdk to link an identity.

Before proceeding, ensure you have completed all the steps from the Installation section.

Linking an identity is typically a two-step process:

  1. Create a proof of ownership.

  2. Request the identity link to attach the proof of ownership.

The proof varies whether the identity to link is web2 (Twitter, Discord) or web3 (Substrate, Evm, Bitcoin, Solana).

  • Twitter: A challenge code has to be publicly posted. The user has to provide the URL to the post.

  • Discord: The challenge code has to be posted in the designated Discord channel. The user has to provide the URL to the post.

  • Web3 identities: The challenge code has to be signed by the user with the web3 identity to-be link.

For the following examples, you will use a Substrate address as the Prime Identity to hold our linked identities.

const primeIdentityAddress = '5DNx1Kgis2u2SQq7EJrBdnV49PoZCxV3NqER4vV5VqjqZcat';

1. Generate the challenge code

import { createLitentryIdentityType, request } from "@litentry/client-sdk";
import type { LitentryIdentity } from "@litentry/parachain-api";

// Note: `api` instance is explained in the Installation section.

// id-graph holder
const who: LitentryIdentity = createLitentryIdentityType(api.registry, {
  addressOrHandle: primeIdentityAddress,
  type: 'Substrate',
});

// identity to-be-linked
const identity: LitentryIdentity = createLitentryIdentityType(api.registry, {
  addressOrHandle: '0x0AcE67628Bd43213C1C41ca1DAEf47E63923c75c',
  type: 'Evm',
});

const challengeCode = await request.createChallengeCode(api, {
  who,
  identity,
});

2. Proof of identity ownership

The challenge code is a 32-byte hex-encoded string that is uniquely generated for the given identities and salted with the Litentry Enclave’s nonce.

Here is what it looks like:

0x9f7077941185730ef3f28e6fca6ce010d3063a633b23e451ce8214e437645ecb

For Web3 identities, the challenge code needs to be signed by the identity to be linked. Following our example, it should be signed by the Evm account: 0x0AcE67628Bd43213C1C41ca1DAEf47E63923c75c.

The signature should be a hex-encoded string. Optionally accepted formats are: base58-encoded string for Solana and base64-encoded for Bitcoin identities.

For Web2 accounts, the challenge code needs to be posted, and the user has to provide the URL to it.

Given the user signature or post’s URL, we can build a LitentryValidationData struct to hold the proof

import { createLitentryValidationDataType } from "@litentry/client-sdk";

const validationData = createLitentryValidationDataType(
  api.registry,
  {
    addressOrHandle: '0x0AcE67628Bd43213C1C41ca1DAEf47E63923c75c',
    type: 'Evm',
  },
  {
	  signature: '0x123....908',
	  message: '0x9f70...5ecb',
  },
);

For Twitter, the proof would look like:

import { createLitentryValidationDataType } from "@litentry/client-sdk";

const validationData = createLitentryValidationDataType(
  api.registry,
  {
    addressOrHandle: 'twitter-handle',
    type: 'Twitter',
  },
  {
	  tweetId: 'link-to-post',
  },
);

For Discord,

import { createLitentryValidationDataType } from "@litentry/client-sdk";

const validationData = createLitentryValidationDataType(
  api.registry,
  {
    addressOrHandle: 'discord-handle',
    type: 'Discord',
  },
  {
	  channelId: '123...'
	  guildId: '123...',
	  messageId: '123...'
  },
);

Those Discords values can be extracted from the provided Discord URL to the user’s post. For instance:

const givenUserUrl = "https://discord.com/channels/919848390156767232/919848392035794945/1125906893789995098"

const [, , guildId, channelId, messageId] = new URL(givenUserUrl).pathname.split('/');

3. Linking request

Build a secure trusted request

import { request } from "@litentry/client-sdk";

const call = await request.linkIdentity(api, {
  who,
  identity,
  validation: validationData,
  networks: [], // safe to ignore.
});

The call object has the following properties:

  • call.payloadToSign: The hex-encoded trusted call.

  • call.txHash: The hash that will identify the request.

  • call.send: A callback function to send the request to the Litentry Enclave.

The trusted call needs to be signed by the prime identity. This ensures the mutation operation is legit. The message to sign is found in call.payloadToSign.

The signature should be a hex-encoded string. Optionally accepted formats are: base58-encoded string for Solana and base64-encoded for Bitcoin identities.

Once the call.payloadToSign the message is signed by the prime identity, we can send the transaction.

const result = await send({
  signedPayload,
});

console.log(`✨ success.`);
// following the same Evm example
const [addedIdentity] = result.mutatedIdentities[0];
console.log(`New added Evm identity: ${addedIdentity.asEvm.toHex()}`);

// tip, use toHuman() to explore the struct
// console.log(result.mutatedIdentities[0].toHuman());

The result object has the following properties:

  • result.response: The raw Enclave’s response. a WorkerRpcReturnValue struct.

  • request.idGraphHash: The resulting hash of the new id graph.

  • result.mutatedIdentities: An array containing the new linking identities.

Last updated