diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/CHANGELOG.md b/tee-worker/identity/client-sdk/packages/client-sdk/CHANGELOG.md index e2db89cd2f..f03653f56f 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/CHANGELOG.md +++ b/tee-worker/identity/client-sdk/packages/client-sdk/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - Add OmniAccount requestors for `createAccountStore`, `remark`, `transferNative`, `transferEthereum`, and `callEthereum`. +- Add `requestVerificationCode` requestor. ## 2024-10-14 diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/package.json b/tee-worker/identity/client-sdk/packages/client-sdk/package.json index 71c491f364..7b05eb3aae 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/package.json +++ b/tee-worker/identity/client-sdk/packages/client-sdk/package.json @@ -1,7 +1,7 @@ { "name": "@litentry/client-sdk", "description": "This package provides helpers for dApps to interact with the Litentry Protocol.", - "version": "1.0.0-next.3", + "version": "1.0.0-next.4", "license": "GPL-3.0-or-later", "dependencies": {}, "devDependencies": { diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/index.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/index.ts index dc81833719..2861211cb1 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/index.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/index.ts @@ -12,6 +12,7 @@ export * from './lib/type-creators/litentry-identity'; export * from './lib/type-creators/request'; export * from './lib/type-creators/trusted-call'; export * from './lib/type-creators/validation-data'; +export * from './lib/type-creators/tc-authentication'; export type { IdGraph } from './lib/type-creators/id-graph'; export { ID_GRAPH_STRUCT } from './lib/type-creators/id-graph'; diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/call-ethereum.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/call-ethereum.request.ts index aa045b9456..686991bbb0 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/call-ethereum.request.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/call-ethereum.request.ts @@ -18,6 +18,15 @@ import type { U8aLike } from '@polkadot/util/types'; /** * OmniAccount: Call an Ethereum contract. + * + * @returns {Promise} - A promise that resolves to an object containing the payload to signature + * (if applicable) and a send function. + * @returns {string} [payloadToSign] - The payload to sign if who is not an email identity. + * @returns {Function} send - A function to send the request to the Enclave. + * @returns {Promise} send.args - The arguments required to send the request. + * @returns {string} send.args.authorization - The authentication string. If who is an + * email identity, this is the email verification code. If the who is not an email identity, this + * is the signed payload. */ export async function callEthereum( /** Litentry Parachain API instance from Polkadot.js */ @@ -33,8 +42,8 @@ export async function callEthereum( input: U8aLike; } ): Promise<{ - payloadToSign: string; - send: (args: { signedPayload: string }) => Promise<{ + payloadToSign?: string; + send: (args: { authorization: string }) => Promise<{ response: WorkerRpcReturnValue; blockHash: string; extrinsicHash: string; @@ -62,15 +71,8 @@ export async function callEthereum( const nonce = await api.rpc.system.accountNextIndex(omniAccount.asSubstrate); - const payloadToSign = createPayloadToSign({ - who, - call, - nonce, - shard: shardU8, - }); - const send = async (args: { - signedPayload: string; + authorization: string; }): Promise<{ response: WorkerRpcReturnValue; blockHash: string; @@ -80,7 +82,7 @@ export async function callEthereum( const request = await createRequestType(api, { signer: who, - signature: args.signedPayload, + signature: args.authorization, call, nonce, shard: shardU8, @@ -113,6 +115,19 @@ export async function callEthereum( }; }; + if (who.isEmail) { + return { + send, + }; + } + + const payloadToSign = createPayloadToSign({ + who, + call, + nonce, + shard: shardU8, + }); + return { payloadToSign, send, diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/create-account-store.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/create-account-store.request.ts index ab997dbaab..8584888923 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/create-account-store.request.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/create-account-store.request.ts @@ -16,7 +16,15 @@ import { createRequestType } from '../type-creators/request'; import type { JsonRpcRequest } from '../util/types'; /** - * OmniAccount: Create the OmniAccount for the given Identity + * Creates an account store on the Litentry Parachain. + * + * @returns {Promise} - A promise that resolves to an object containing the payload to sign (if applicable) and a send function. + * @returns {string} [payloadToSign] - The payload to sign if who is not an email identity. + * @returns {Function} send - A function to send the request to the Enclave. + * @returns {Promise} send.args - The arguments required to send the request. + * @returns {string} send.args.authentication - The authentication string. If who is + * an email identity, this is the email verification code. If the who is not an email identity, this is the + * signed payload. */ export async function createAccountStore( /** Litentry Parachain API instance from Polkadot.js */ @@ -28,8 +36,8 @@ export async function createAccountStore( who: LitentryIdentity; } ): Promise<{ - payloadToSign: string; - send: (args: { signedPayload: string }) => Promise<{ + payloadToSign?: string; + send: (args: { authentication: string }) => Promise<{ response: WorkerRpcReturnValue; blockHash: string; extrinsicHash: string; @@ -51,15 +59,8 @@ export async function createAccountStore( omniAccount.asSubstrate.toHex() ); - const payloadToSign = createPayloadToSign({ - who, - call, - nonce, - shard: shardU8, - }); - const send = async (args: { - signedPayload: string; + authentication: string; }): Promise<{ response: WorkerRpcReturnValue; blockHash: string; @@ -69,7 +70,7 @@ export async function createAccountStore( const request = await createRequestType(api, { signer: who, - signature: args.signedPayload, + signature: args.authentication, call, nonce, shard: shardU8, @@ -102,6 +103,17 @@ export async function createAccountStore( }; }; + if (who.isEmail) { + return { send }; + } + + const payloadToSign = createPayloadToSign({ + who, + call, + nonce, + shard: shardU8, + }); + return { payloadToSign, send, diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/index.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/index.ts index 3d08758f77..ef180cc077 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/index.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/index.ts @@ -11,3 +11,4 @@ export { createAccountStore } from './create-account-store.request'; export { getIdGraph } from './get-id-graph.request'; export { getIdGraphHash } from './get-id-graph-hash'; export { getLastRegisteredEnclave } from './get-last-registered-enclave'; +export { requestVerificationCode } from './request-verification-code.request'; diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/remark.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/remark.request.ts index ef9807cc4e..f30b1b118e 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/remark.request.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/remark.request.ts @@ -16,7 +16,16 @@ import { createRequestType } from '../type-creators/request'; import type { JsonRpcRequest } from '../util/types'; /** - * OmniAccount: Make a remark + * Sends a remark to the Litentry Parachain. + * + * @returns {Promise} - A promise that resolves to an object containing the payload to sign + * (if applicable) and a send function. + * @returns {string} [payloadToSign] - The payload to sign if who is not an email identity. + * @returns {Function} send - A function to send the request to the Enclave. + * @returns {Promise} send.args - The arguments required to send the request. + * @returns {string} send.args.authentication - The authentication string. If who is + * an email identity, this is the email verification code. If the who is not an email identity, + * this is the signed payload. */ export async function remark( /** Litentry Parachain API instance from Polkadot.js */ @@ -30,8 +39,8 @@ export async function remark( message: string; } ): Promise<{ - payloadToSign: string; - send: (args: { signedPayload: string }) => Promise<{ + payloadToSign?: string; + send: (args: { authentication: string }) => Promise<{ response: WorkerRpcReturnValue; blockHash: string; extrinsicHash: string; @@ -58,15 +67,8 @@ export async function remark( omniAccount.asSubstrate.toHex() ); - const payloadToSign = createPayloadToSign({ - who, - call, - nonce, - shard: shardU8, - }); - const send = async (args: { - signedPayload: string; + authentication: string; }): Promise<{ response: WorkerRpcReturnValue; blockHash: string; @@ -76,7 +78,7 @@ export async function remark( const request = await createRequestType(api, { signer: who, - signature: args.signedPayload, + signature: args.authentication, call, nonce, shard: shardU8, @@ -109,6 +111,17 @@ export async function remark( }; }; + if (who.isEmail) { + return { send }; + } + + const payloadToSign = createPayloadToSign({ + who, + call, + nonce, + shard: shardU8, + }); + return { payloadToSign, send, diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/request-verification-code.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/request-verification-code.request.ts new file mode 100644 index 0000000000..b259c9c0dc --- /dev/null +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/request-verification-code.request.ts @@ -0,0 +1,22 @@ +import { enclave } from '../enclave'; + +import type { ApiPromise } from '@polkadot/api'; +import type { JsonRpcRequest } from '../util/types'; + +/** + * Request email verification code. + */ +export async function requestVerificationCode( + api: ApiPromise, + { omniAccount, email }: { omniAccount: `0x${string}`; email: string } +): Promise<{ success: boolean }> { + const payload: JsonRpcRequest = { + jsonrpc: '2.0', + method: 'omni_requestEmailVerificationCode', + params: [omniAccount, email], + }; + + const [workerResponse] = await enclave.send(api, payload); + + return { success: workerResponse.status.isOk }; +} diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-ethereum.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-ethereum.request.ts index 818fd4dd00..15218a1e73 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-ethereum.request.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-ethereum.request.ts @@ -16,7 +16,16 @@ import { createRequestType } from '../type-creators/request'; import type { JsonRpcRequest } from '../util/types'; /** - * OmniAccount: Transfer funds to Ethereum Network. + * Transfers Ethereum to another account on the Litentry Parachain. + * + * @returns {Promise} - A promise that resolves to an object containing the payload to signature + * (if applicable) and a send function. + * @returns {string} [payloadToSign] - The payload to sign if who is not an email identity. + * @returns {Function} send - A function to send the request to the Enclave. + * @returns {Promise} send.args - The arguments required to send the request. + * @returns {string} send.args.authentication - The authentication string. If who is + * an email identity, this is the email verification code. If the who is not an email identity, + * this is the signed payload. */ export async function transferEthereum( /** Litentry Parachain API instance from Polkadot.js */ @@ -32,8 +41,8 @@ export async function transferEthereum( amount: bigint; } ): Promise<{ - payloadToSign: string; - send: (args: { signedPayload: string }) => Promise<{ + payloadToSign?: string; + send: (args: { authentication: string }) => Promise<{ response: WorkerRpcReturnValue; blockHash: string; extrinsicHash: string; @@ -61,15 +70,8 @@ export async function transferEthereum( const nonce = await api.rpc.system.accountNextIndex(omniAccount.asSubstrate); - const payloadToSign = createPayloadToSign({ - who, - call, - nonce, - shard: shardU8, - }); - const send = async (args: { - signedPayload: string; + authentication: string; }): Promise<{ response: WorkerRpcReturnValue; blockHash: string; @@ -79,7 +81,7 @@ export async function transferEthereum( const request = await createRequestType(api, { signer: who, - signature: args.signedPayload, + signature: args.authentication, call, nonce, shard: shardU8, @@ -112,6 +114,17 @@ export async function transferEthereum( }; }; + if (who.isEmail) { + return { send }; + } + + const payloadToSign = createPayloadToSign({ + who, + call, + nonce, + shard: shardU8, + }); + return { payloadToSign, send, diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-native.request.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-native.request.ts index 52cfa8b22f..02cfdbe5e4 100644 --- a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-native.request.ts +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/requests/transfer-native.request.ts @@ -16,7 +16,16 @@ import { createRequestType } from '../type-creators/request'; import type { JsonRpcRequest } from '../util/types'; /** - * OmniAccount: Transfer funds within the Litentry Network. + * Transfers native tokens to another account on the Litentry Parachain. + * + * @returns {Promise} - A promise that resolves to an object containing the payload to sign + * (if applicable) and a send function. + * @returns {string} [payloadToSign] - The payload to sign if who is not an email identity. + * @returns {Function} send - A function to send the request to the Enclave. + * @returns {Promise} send.args - The arguments required to send the request. + * @returns {string} send.args.authentication - The authentication string. If who is + * an email identity, this is the email verification code. If the who is not an email identity, + * this is the signed payload. */ export async function transferNative( /** Litentry Parachain API instance from Polkadot.js */ @@ -32,8 +41,8 @@ export async function transferNative( amount: bigint; } ): Promise<{ - payloadToSign: string; - send: (args: { signedPayload: string }) => Promise<{ + payloadToSign?: string; + send: (args: { authentication: string }) => Promise<{ response: WorkerRpcReturnValue; blockHash: string; extrinsicHash: string; @@ -61,15 +70,8 @@ export async function transferNative( const nonce = await api.rpc.system.accountNextIndex(omniAccount.asSubstrate); - const payloadToSign = createPayloadToSign({ - who, - call, - nonce, - shard: shardU8, - }); - const send = async (args: { - signedPayload: string; + authentication: string; }): Promise<{ response: WorkerRpcReturnValue; blockHash: string; @@ -79,7 +81,7 @@ export async function transferNative( const request = await createRequestType(api, { signer: who, - signature: args.signedPayload, + signature: args.authentication, call, nonce, shard: shardU8, @@ -112,6 +114,17 @@ export async function transferNative( }; }; + if (who.isEmail) { + return { send }; + } + + const payloadToSign = createPayloadToSign({ + who, + call, + nonce, + shard: shardU8, + }); + return { payloadToSign, send, diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.test.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.test.ts new file mode 100644 index 0000000000..ef291030c4 --- /dev/null +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.test.ts @@ -0,0 +1,55 @@ +import { cryptoWaitReady } from '@polkadot/util-crypto'; +import { TypeRegistry } from '@polkadot/types'; +import { trusted_operations, identity } from '@litentry/parachain-api'; +import { createTCAuthenticationType } from './tc-authentication'; +import { createLitentryIdentityType } from './litentry-identity'; +import { createLitentryMultiSignature } from './litentry-multi-signature'; + +describe('createTCAuthenticationType', () => { + const types = { + ...trusted_operations.types, + ...identity.types, + }; + let registry: TypeRegistry; + + beforeAll(async () => { + await cryptoWaitReady(); + + registry = new TypeRegistry(); + registry.register(types); + }); + + it('creates Email authentication', () => { + const emailTCAuthentication = createTCAuthenticationType(registry, { + type: 'Email', + verificationCode: '123456', + }); + + expect(emailTCAuthentication).toBeDefined(); + expect(emailTCAuthentication.isEmail).toEqual(true); + expect(emailTCAuthentication.asEmail.toHuman()).toEqual('123456'); + }); + + it('creates Web3 authentication', () => { + const who = createLitentryIdentityType(registry, { + type: 'Substrate', + addressOrHandle: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', + }); + const signatureString = '0x' + '12'.repeat(64); + const signature = createLitentryMultiSignature(registry, { + who, + signature: signatureString, + }); + + const web3TCAuthentication = createTCAuthenticationType(registry, { + type: 'Web3', + signature: signature.toHex(), + }); + + expect(web3TCAuthentication).toBeDefined(); + expect(web3TCAuthentication.isWeb3).toEqual(true); + expect(web3TCAuthentication.asWeb3.toHuman()).toEqual({ + Sr25519: signatureString, + }); + }); +}); diff --git a/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.ts b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.ts new file mode 100644 index 0000000000..2fbfe9d646 --- /dev/null +++ b/tee-worker/identity/client-sdk/packages/client-sdk/src/lib/type-creators/tc-authentication.ts @@ -0,0 +1,21 @@ +import { TCAuthentication } from '@litentry/parachain-api'; +import { Registry } from '@polkadot/types-codec/types'; + +type AuthenticationData = + | { + type: 'Email'; + verificationCode: string; + } + | { + type: 'Web3'; + signature: string; + }; + +export function createTCAuthenticationType( + registry: Registry, + data: AuthenticationData +): TCAuthentication { + return registry.createType('TCAuthentication', { + [data.type]: data.type === 'Email' ? data.verificationCode : data.signature, + }); +}