SDK Use Case Example

This page will show examples of some of the previously explained Client-SDK use cases. Using ClienSDK to Send Requests and Generate Verifiable Credential

This guide will walk you through the process of using the @litentry/enclave SDK to send requests and generate Verifiable Credentials (VC) with a remote parachain server. We will use a demo code snippet as an example to illustrate each step.

Prerequisites

  • Basic knowledge of JavaScript and React

  • Familiarity with the Polkadot ecosystem

  • Installed Node.js and npm

  • Installed Polkadot.js extension

Step 1

Set up a new web project and install the necessary dependencies.

```bash
npx create-next-app litentry-demo
cd litentry-demo
npm install a@litentry/chain-types @litentry/enclave @litentry/vc-sdk @litentry/credential-definitions @polkadot/api @polkadot/api-base @polkadot/extension-dapp @polkadot/rpc-provider @polkadot/types @polkadot/types-codec @polkadot/util @polkadot/util-crypto
```

Step 2

Import the Required Modules and hooks in your component file:

```javascript
'use client';
import { useState } from 'react';
import { NextSeo } from 'next-seo';
import { u8aToHex, u8aToString } from '@polkadot/util';
import { Button, Text } from '@chakra-ui/react';
import { useSubstrateApi } from '@/services/useSubstrateAPI';
import { getAllCredentialDefinitions } from '@/services/useUserVerifiableCredentials';
import { ApiPromise } from "@polkadot/api";
import type { Codec } from '@polkadot/types-codec/types';
import type { U8aLike } from '@polkadot/util/types';
import type { CorePrimitivesAssertion } from '@polkadot/types/lookup';
import { request } from '@litentry/enclave';
import { getWalletBySource } from "@talismn/connect-wallets";
import { decodeAddress } from "@polkadot/util-crypto';
import { substrateSign } from "@/services/util";

Step 3

Initialize Credential Definitions and map them to the necessary assertions.

```javascript
const allCredentialDefinitions = getAllCredentialDefinitions().slice(0, 10);
const assertions: Record<string, any>[] = allCredentialDefinitions.map(
    (credentialDefinition) => {
        return {
            [credentialDefinition.assertion.id]: credentialDefinition.assertion.params,
        };
    }
);
const assertionsVcIdMap: Array<string> = allCredentialDefinitions.map(
    (credentialDefinition) => credentialDefinition.id
);
```

Step 4

Create the Request Function

Create an async function to handle the request for batch verifiable credentials.

```javascript
const request = async (): Promise<void> => {
    setStatus('loading');
    setProgress([]);
    // Litentry supports: Substrate, Ethereum, Bitcoin and Solana
    const walletName = `polkadot-js`
    const wallet = getWalletBySource(walletName);
    if (!wallet) {
        alert(`Polkadot-js not installed`);
        return;
    }
    await wallet.enable(`LitentryClientDemo`);
    const accounts = await wallet.getAccounts();
    const curAccount = accounts[0];
    const signer = wallet.signer;
    const account = decodeAddress(curAccount.address);

    const signMessage = async ({ rawMessage }: { rawMessage: string }) =>
        substrateSign(u8aToHex(account), rawMessage, {
            signer,
            type: 'bytes',
        });

    const { payloadToSign, sendAndWatch } = await requestBatchVerifiableCredentials(
        { assertions },
        {
            api,
            assertionsVcIdMap,
            address: curAccount.address,
        }
    );

    const signature = await signMessage({
        rawMessage: payloadToSign,
    });

    await sendAndWatch(
        {
            signedPayload: signature,
        },
        (error, { vcPayload, index, partialResult }) => {
            setProgress((prev) => [
                ...prev,
                `${partialResult.length}/${assertions.length} Received response for Assertion #${index + 1}`,
            ]);

            console.log({ error, vc: u8aToString(vcPayload), index });
        }
    );

    setStatus('success');
};

```

Step 5

Create UI Component

Create the main component that will render the UI and handle user interactions.

```javascript
export default function TestRequestBatchVCPlayground(): JSX.Element | null {
    const { data: api, status: apiStatus } = useSubstrateApi();
    const [status, setStatus] = useState<'idle' | 'loading' | 'success'>('idle');
    const [progress, setProgress] = useState<Array<string>>([]);

    if (apiStatus !== 'success' || !api) {
        return <h1>Loading rpc API</h1>;
    }

    return (
        <div>
            <NextSeo title="Test: Request a batch of VCs" nofollow noindex />
            <Text variant="body1bold" mb={1}>
                Test: Request a batch of VCs
            </Text>
            <Text mb={1}>
                Open DevTools to see the console log for the results of the request.
            </Text>
            <Button onClick={request} isDisabled={status === 'loading'}>
                Request {assertions.length} VCs
            </Button>
            {progress.map((p, i) => (
                <Text mt={1} key={i}>
                    {p}
                </Text>
            ))}
        </div>
    );
}

```

Step 6

Define the requestBatchVerifiableCredentials Function

Define the function to handle the payload signing and sending the request to the Enclave.

```javascript
async function requestBatchVerifiableCredentials(
    credentialDescriptor: {
        assertions: Record<
            string,
            | string
            | Array<string | number | Codec | U8aLike>
            | Record<string, unknown>
        >[];
    },
    context: {
        address: string;
        assertionsVcIdMap: Array<string>;
        api: ApiPromise;
    }
): Promise<{
    payloadToSign: string;
    sendAndWatch: (
        args: { signedPayload: string },
        subscribe: (
            error: Error | null,
            data: {
                vcPayload: Uint8Array;
                index: number;
                partialResult: Array<unknown>;
            }
        ) => void
    ) => Promise<void>;
}> {
    const assertions: Array<CorePrimitivesAssertion> =
        credentialDescriptor.assertions.map((assertionLike) => {
            return context.api.createType('CorePrimitivesAssertion', assertionLike);
        });

    const { payloadToSign, send, txHash } = await request.requestBatchVC(
        context.api,
        {
            who: context.address,
            assertions,
        }
    );

    const sendAndWatch = async (
        {
            signedPayload,
        }: {
            signedPayload: string;
        },
        subscribe: (
            error: Error | null,
            data: {
                vcPayload: Uint8Array;
                index: number;
                partialResult: Array<unknown>;
            }
        ) => void
    ) => {
        console.log(`Sending request to the Enclave with transaction hash: ${txHash}`);

        send({ signedPayload }, (error, data) => {
            const { vcPayload } = data;

            if (vcPayload.length > 0) {
                console.log(`[requestBatchVerifiableCredentials]: Received response from the Enclave:`, u8aToString(vcPayload))
            }

            subscribe(error, data);
        });
    };

    return {
        payloadToSign,
        sendAndWatch,
    };
}
```

Conclusion

By following these steps, you can successfully integrate the @litentry/enclave SDK to send requests and generate Verifiable Credentials with a remote parachain server. This guide provides a clear example of how to use the SDK, making it easier for developers to adopt and implement similar functionality in their dApps.

To try a live demo, visit https://github.com/litentry/client-demo-app/;

Last updated