From a91ca886b06e1cbb5b2b9747751075c3c901b161 Mon Sep 17 00:00:00 2001
From: Berend Sliedrecht <berend@animo.id>
Date: Tue, 30 Jan 2024 11:56:10 +0100
Subject: [PATCH] feat: added transaction endorsement

Signed-off-by: Berend Sliedrecht <berend@animo.id>
---
 apps/shared/src/events/didEvents.ts           |  15 ++
 apps/ssi-abstraction/package.json             |   3 +-
 .../src/agent/agent.service.ts                |  23 ++-
 .../credentialDefinitions.service.ts          |  46 +++++-
 .../src/agent/dids/dids.controller.ts         |  10 ++
 .../src/agent/dids/dids.service.ts            | 138 ++++++++++++++----
 .../agent/revocation/revocation.controller.ts |   4 +-
 .../agent/revocation/revocation.service.ts    |  68 +++++++--
 .../src/agent/schemas/schemas.service.ts      |  39 ++++-
 .../src/agent/withTenantService.ts            |  19 +--
 apps/ssi-abstraction/src/app.module.ts        |   4 +
 apps/ssi-abstraction/src/common/utils.ts      |   8 +
 apps/ssi-abstraction/src/config/ledger.ts     |   2 +-
 .../test/anoncredsCredentials.e2e-spec.ts     |   8 +-
 .../test/credentialDefinitions.e2e-spec.ts    |   8 +-
 apps/ssi-abstraction/test/dids.e2e-spec.ts    |  33 ++++-
 apps/ssi-abstraction/test/jest.config.js      |   2 +-
 .../test/revocation.e2e-spec.ts               | 129 ++++++++++++++++
 apps/ssi-abstraction/test/schemas.e2e-spec.ts |   5 +-
 pnpm-lock.yaml                                |  89 ++++++-----
 20 files changed, 539 insertions(+), 114 deletions(-)
 create mode 100644 apps/ssi-abstraction/src/common/utils.ts
 create mode 100644 apps/ssi-abstraction/test/revocation.e2e-spec.ts

diff --git a/apps/shared/src/events/didEvents.ts b/apps/shared/src/events/didEvents.ts
index 5b39c61..fff58aa 100644
--- a/apps/shared/src/events/didEvents.ts
+++ b/apps/shared/src/events/didEvents.ts
@@ -17,6 +17,21 @@ export class EventDidsResolve extends BaseEvent<DidDocument> {
   }
 }
 
+export type EventDidsRegisterEndorserDidInput = never;
+export class EventDidsRegisterEndorserDid extends BaseEvent {
+  public static token = 'dids.register.indy.endorser';
+
+  public static fromEvent(e: EventDidsRegisterEndorserDid) {
+    return new EventDidsRegisterEndorserDid(
+      e.data,
+      e.tenantId,
+      e.id,
+      e.type,
+      e.timestamp,
+    );
+  }
+}
+
 export type EventDidsRegisterIndyFromSeedInput = BaseEventInput<{
   seed: string;
   services?: Array<{
diff --git a/apps/ssi-abstraction/package.json b/apps/ssi-abstraction/package.json
index a6e86e3..95d5088 100644
--- a/apps/ssi-abstraction/package.json
+++ b/apps/ssi-abstraction/package.json
@@ -11,7 +11,8 @@
     "prebuild": "rimraf dist",
     "build": "nest build -p tsconfig.production.json",
     "start": "nest start --watch --preserveWatchOutput",
-    "test": "jest"
+    "test": "jest",
+    "test:e2e": "pnpm test -- -c=test/jest.config.js --runInBand"
   },
   "dependencies": {
     "@credo-ts/anoncreds": "0.5.0-alpha.116",
diff --git a/apps/ssi-abstraction/src/agent/agent.service.ts b/apps/ssi-abstraction/src/agent/agent.service.ts
index a0db4d9..315eef3 100644
--- a/apps/ssi-abstraction/src/agent/agent.service.ts
+++ b/apps/ssi-abstraction/src/agent/agent.service.ts
@@ -45,6 +45,7 @@ import { Injectable } from '@nestjs/common';
 import { ConfigService } from '@nestjs/config';
 import { logger } from '@ocm/shared';
 
+import { parseDid } from '../common/utils.js';
 import { LEDGERS } from '../config/ledger.js';
 
 import { AgentLogger } from './logger.js';
@@ -182,6 +183,27 @@ export class AgentService implements OnApplicationShutdown {
     });
   }
 
+  public async getEndorserDid(issuerDid: string) {
+    const { method, namespaceAndNetwork } = parseDid(issuerDid);
+    const dids = await this.agent.dids.getCreatedDids({ method });
+
+    const did = dids
+      .map(({ did }) => did)
+      .find((did) => did.includes(namespaceAndNetwork));
+
+    if (!did) {
+      throw new Error(
+        `Could not find endorser did for method: '${method}' on network: '${namespaceAndNetwork}'`,
+      );
+    }
+
+    return did;
+  }
+
+  public async endorseTransaction(txn: string, endorserDid: string) {
+    return this.agent.modules.indyVdr.endorseTransaction(txn, endorserDid);
+  }
+
   public async onModuleInit() {
     await this.agent.initialize();
     logger.info('Agent initialized');
@@ -194,7 +216,6 @@ export class AgentService implements OnApplicationShutdown {
     // This is done because the Askar shutdown procedure is a bit buggy
     try {
       await this.agent.shutdown();
-      // eslint-disable-next-line no-empty
     } catch (e) {
       logger.warn(`Agent shutdown issue occurred. Cause: ${e}`);
     }
diff --git a/apps/ssi-abstraction/src/agent/credentialDefinitions/credentialDefinitions.service.ts b/apps/ssi-abstraction/src/agent/credentialDefinitions/credentialDefinitions.service.ts
index ac212a4..e80c188 100644
--- a/apps/ssi-abstraction/src/agent/credentialDefinitions/credentialDefinitions.service.ts
+++ b/apps/ssi-abstraction/src/agent/credentialDefinitions/credentialDefinitions.service.ts
@@ -10,11 +10,15 @@ import type {
 
 import { Injectable } from '@nestjs/common';
 
+import { AgentService } from '../agent.service.js';
 import { WithTenantService } from '../withTenantService.js';
 
 @Injectable()
 export class CredentialDefinitionsService {
-  public constructor(private withTenantService: WithTenantService) {}
+  public constructor(
+    private withTenantService: WithTenantService,
+    private agentService: AgentService,
+  ) {}
 
   public async getAll({
     tenantId,
@@ -57,6 +61,7 @@ export class CredentialDefinitionsService {
   }: EventAnonCredsCredentialDefinitionsRegisterInput): Promise<
     EventAnonCredsCredentialDefinitionsRegister['data']
   > {
+    const endorserDid = await this.agentService.getEndorserDid(issuerDid);
     return this.withTenantService.invoke(tenantId, async (t) => {
       const { credentialDefinitionState } =
         await t.modules.anoncreds.registerCredentialDefinition<IndyVdrRegisterCredentialDefinitionOptions>(
@@ -67,14 +72,17 @@ export class CredentialDefinitionsService {
               tag,
             },
             options: {
-              endorserMode: 'internal',
-              endorserDid: issuerDid,
+              endorserMode: 'external',
+              endorserDid,
               supportRevocation: supportsRevocation,
             },
           },
         );
 
-      if (credentialDefinitionState.state !== 'finished') {
+      if (
+        credentialDefinitionState.state !== 'action' ||
+        credentialDefinitionState.action !== 'endorseIndyTransaction'
+      ) {
         throw new Error(
           `Error registering credentialDefinition: ${
             credentialDefinitionState.state === 'failed'
@@ -84,6 +92,36 @@ export class CredentialDefinitionsService {
         );
       }
 
+      const signedcredentialDefinitionRequest =
+        await this.agentService.endorseTransaction(
+          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+          // @ts-expect-error
+          credentialDefinitionState.credentialDefinitionRequest,
+          endorserDid,
+        );
+
+      const credentialDefinitionSubmitResult =
+        await t.modules.anoncreds.registerCredentialDefinition<IndyVdrRegisterCredentialDefinitionOptions>(
+          {
+            options: {
+              endorsedTransaction: signedcredentialDefinitionRequest,
+              endorserMode: 'external',
+              supportRevocation: supportsRevocation,
+            },
+            credentialDefinition:
+              credentialDefinitionState.credentialDefinition,
+          },
+        );
+
+      if (
+        credentialDefinitionSubmitResult.credentialDefinitionState.state !==
+        'finished'
+      ) {
+        throw Error(
+          `Error while registering credentialDefinition. Cause: ${JSON.stringify(credentialDefinitionSubmitResult)}`,
+        );
+      }
+
       return {
         credentialDefinitionId:
           credentialDefinitionState.credentialDefinitionId,
diff --git a/apps/ssi-abstraction/src/agent/dids/dids.controller.ts b/apps/ssi-abstraction/src/agent/dids/dids.controller.ts
index 2556483..de2f26e 100644
--- a/apps/ssi-abstraction/src/agent/dids/dids.controller.ts
+++ b/apps/ssi-abstraction/src/agent/dids/dids.controller.ts
@@ -3,6 +3,8 @@ import { MessagePattern } from '@nestjs/microservices';
 import {
   EventDidsDidConfiguration,
   EventDidsDidConfigurationInput,
+  EventDidsRegisterEndorserDid,
+  EventDidsRegisterEndorserDidInput,
   EventDidsRegisterIndyFromSeed,
   EventDidsRegisterIndyFromSeedInput,
   EventDidsResolve,
@@ -23,6 +25,14 @@ export class DidsController {
     );
   }
 
+  @MessagePattern(EventDidsRegisterEndorserDid.token)
+  public async registerEndorserDid(options: EventDidsRegisterEndorserDidInput) {
+    return new EventDidsRegisterEndorserDid(
+      await this.didsService.registerEndorserDids(options),
+      options.tenantId,
+    );
+  }
+
   @MessagePattern(EventDidsDidConfiguration.token)
   public async getDidConfiguration(options: EventDidsDidConfigurationInput) {
     return new EventDidsDidConfiguration(
diff --git a/apps/ssi-abstraction/src/agent/dids/dids.service.ts b/apps/ssi-abstraction/src/agent/dids/dids.service.ts
index 7a2cb50..a1888d5 100644
--- a/apps/ssi-abstraction/src/agent/dids/dids.service.ts
+++ b/apps/ssi-abstraction/src/agent/dids/dids.service.ts
@@ -1,4 +1,3 @@
-import type { LEDGERS } from '../../config/ledger.js';
 import type {
   IndyVdrDidCreateOptions,
   IndyVdrDidCreateResult,
@@ -11,6 +10,8 @@ import type {
   EventDidsRegisterIndyFromSeed,
   EventDidsResolve,
   EventDidsResolveInput,
+  EventDidsRegisterEndorserDidInput,
+  EventDidsRegisterEndorserDid,
 } from '@ocm/shared';
 
 import {
@@ -26,12 +27,15 @@ import {
 import { Injectable } from '@nestjs/common';
 import { ConfigService } from '@nestjs/config';
 
+import { LEDGERS } from '../../config/ledger.js';
+import { AgentService } from '../agent.service.js';
 import { registerPublicDids } from '../ledger/register.js';
 import { WithTenantService } from '../withTenantService.js';
 
 @Injectable()
 export class DidsService {
   public constructor(
+    private agentService: AgentService,
     private withTenantService: WithTenantService,
     private configService: ConfigService,
   ) {}
@@ -66,12 +70,10 @@ export class DidsService {
     EventDidsDidConfiguration['data']
   > {
     return this.withTenantService.invoke(tenantId, async (t) => {
-      const indyDids = t.dids.getCreatedDids({ method: 'indy' });
-      const sovDids = t.dids.getCreatedDids({ method: 'sov' });
-      const webDids = t.dids.getCreatedDids({ method: 'web' });
-      const dids = (await Promise.all([indyDids, sovDids, webDids])).flatMap(
-        (d) => d,
-      );
+      const indyDids = await t.dids.getCreatedDids({ method: 'indy' });
+      const sovDids = await t.dids.getCreatedDids({ method: 'sov' });
+      const webDids = await t.dids.getCreatedDids({ method: 'web' });
+      const dids = [...indyDids, ...sovDids, ...webDids];
 
       const jwtEntries: DidConfiguration['entries'] = [];
       const jwsService = t.dependencyManager.resolve(JwsService);
@@ -115,15 +117,10 @@ export class DidsService {
     });
   }
 
-  public async registerDidIndyFromSeed({
-    tenantId,
-    seed,
-    services,
-  }: EventDidsRegisterIndyFromSeedInput): Promise<
-    EventDidsRegisterIndyFromSeed['data']
-  > {
-    const dids: Array<string> = [];
-
+  public async registerEndorserDids(
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    _?: EventDidsRegisterEndorserDidInput,
+  ): Promise<EventDidsRegisterEndorserDid['data']> {
     const ledgerIds = this.configService.get('agent.ledgerIds') as Array<
       keyof typeof LEDGERS
     >;
@@ -137,6 +134,32 @@ export class DidsService {
       seed: publicDidSeed,
     });
 
+    const privKey = {
+      privateKey: TypedArrayEncoder.fromString(publicDidSeed),
+      keyType: KeyType.Ed25519,
+    };
+
+    await this.agentService.agent.wallet.createKey(privKey);
+
+    for (const publicDid of publicDids) {
+      await this.agentService.agent.dids.import({
+        did: publicDid.did,
+        privateKeys: [privKey],
+      });
+    }
+
+    return {};
+  }
+
+  public async registerDidIndyFromSeed({
+    tenantId,
+    seed,
+    services,
+  }: EventDidsRegisterIndyFromSeedInput): Promise<
+    EventDidsRegisterIndyFromSeed['data']
+  > {
+    const dids: Array<string> = [];
+
     const { publicKey, publicKeyBase58 } = await this.withTenantService.invoke(
       tenantId,
       async (t) =>
@@ -146,19 +169,32 @@ export class DidsService {
         }),
     );
 
-    await this.withTenantService.invoke(tenantId, async (t) =>
-      t.wallet.createKey({
-        privateKey: TypedArrayEncoder.fromString(publicDidSeed),
-        keyType: KeyType.Ed25519,
-      }),
-    );
-
     const buffer = Hasher.hash(publicKey, 'sha2-256');
     const id = TypedArrayEncoder.toBase58(buffer.slice(0, 16));
     const verkey = publicKeyBase58;
 
-    for (const publicDid of publicDids) {
-      const did = `did:indy:${publicDid.namespace}:${id}`;
+    const ledgerIds = this.configService.get('agent.ledgerIds') as Array<
+      keyof typeof LEDGERS
+    >;
+
+    for (const ledgerId of ledgerIds) {
+      const ledger = LEDGERS[ledgerId as keyof typeof LEDGERS];
+
+      const endorserDids = await this.agentService.agent.dids.getCreatedDids({
+        method: 'indy',
+      });
+
+      const endorserDid = endorserDids
+        .map(({ did }) => did)
+        .find((did) => did.includes(ledger.namespace));
+
+      if (!endorserDid) {
+        throw new Error(
+          `Endorser did could not be found for ${ledger.namespace}`,
+        );
+      }
+
+      const did = `did:indy:${ledger.namespace}:${id}`;
       const didDocumentServices: Array<DidDocumentService> | undefined =
         services?.map(
           (s) =>
@@ -170,24 +206,64 @@ export class DidsService {
         );
 
       await this.withTenantService.invoke(tenantId, async (t) => {
-        const result = (await t.dids.create<IndyVdrDidCreateOptions>({
+        const { didState } = (await t.dids.create<IndyVdrDidCreateOptions>({
           did,
           options: {
             verkey,
-            endorserMode: 'internal',
-            endorserDid: publicDid.did,
+            endorserMode: 'external',
+            endorserDid,
             services: didDocumentServices,
             useEndpointAttrib: true,
           },
         })) as IndyVdrDidCreateResult;
 
-        if (result.didState.state !== 'finished') {
+        if (
+          didState.state !== 'action' ||
+          didState.action !== 'endorseIndyTransaction'
+        ) {
           throw Error(
-            `An error occurred while trying to register the did: '${did}'. Result: ${JSON.stringify(result)}`,
+            `An error occurred while trying to register the did: '${did}'. Result: ${JSON.stringify(didState)}`,
+          );
+        }
+
+        const signedNymRequest = await this.agentService.endorseTransaction(
+          didState.nymRequest,
+          didState.endorserDid,
+        );
+
+        const didCreateSubmitResult =
+          await t.dids.create<IndyVdrDidCreateOptions>({
+            did: didState.did,
+            options: {
+              endorserMode: 'external',
+              endorsedTransaction: {
+                nymRequest: signedNymRequest,
+              },
+            },
+            secret: didState.secret,
+          });
+
+        if (didCreateSubmitResult.didState.state !== 'finished') {
+          throw new Error(
+            didCreateSubmitResult.didState.state === 'failed'
+              ? `Did registration for network ${ledger.namespace} failed due to '${didCreateSubmitResult.didState.reason}'`
+              : `Did registration for network ${ledger.namespace} failed with state '${didCreateSubmitResult.didState.state}' due to an unknown reason`,
           );
         }
 
-        dids.push(result.didState.did);
+        await t.dids.import({
+          did: didState.did,
+          didDocument: didState.didDocument,
+          overwrite: true,
+          privateKeys: [
+            {
+              keyType: KeyType.Ed25519,
+              privateKey: TypedArrayEncoder.fromString(seed),
+            },
+          ],
+        });
+
+        dids.push(didState.did);
       });
     }
 
diff --git a/apps/ssi-abstraction/src/agent/revocation/revocation.controller.ts b/apps/ssi-abstraction/src/agent/revocation/revocation.controller.ts
index 87c1624..8267524 100644
--- a/apps/ssi-abstraction/src/agent/revocation/revocation.controller.ts
+++ b/apps/ssi-abstraction/src/agent/revocation/revocation.controller.ts
@@ -39,9 +39,7 @@ export class RevocationController {
     );
   }
 
-  @MessagePattern(
-    EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token,
-  )
+  @MessagePattern(EventAnonCredsRevocationRegisterRevocationStatusList.token)
   public async registerRevocationStatusList(
     options: EventAnonCredsRevocationRegisterRevocationStatusListInput,
   ): Promise<EventAnonCredsRevocationRegisterRevocationStatusList> {
diff --git a/apps/ssi-abstraction/src/agent/revocation/revocation.service.ts b/apps/ssi-abstraction/src/agent/revocation/revocation.service.ts
index df4dedf..8ecff40 100644
--- a/apps/ssi-abstraction/src/agent/revocation/revocation.service.ts
+++ b/apps/ssi-abstraction/src/agent/revocation/revocation.service.ts
@@ -9,6 +9,7 @@ import type {
 
 import { Injectable } from '@nestjs/common';
 
+import { AgentService } from '../agent.service.js';
 import { WithTenantService } from '../withTenantService.js';
 
 export interface AnonCredsCredentialMetadata {
@@ -20,7 +21,10 @@ export interface AnonCredsCredentialMetadata {
 
 @Injectable()
 export class RevocationService {
-  public constructor(private withTenantService: WithTenantService) {}
+  public constructor(
+    private withTenantService: WithTenantService,
+    private agentService: AgentService,
+  ) {}
 
   // Get the credential from storage
   // Get the revocation registry definition id
@@ -111,10 +115,14 @@ export class RevocationService {
   }: EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput): Promise<
     EventAnonCredsRevocationRegisterRevocationRegistryDefinition['data']
   > {
+    const endorserDid = await this.agentService.getEndorserDid(issuerDid);
     return this.withTenantService.invoke(tenantId, async (t) => {
-      const result =
+      const { revocationRegistryDefinitionState } =
         await t.modules.anoncreds.registerRevocationRegistryDefinition({
-          options: {},
+          options: {
+            endorserMode: 'external',
+            endorserDid,
+          },
           revocationRegistryDefinition: {
             maximumCredentialNumber,
             credentialDefinitionId,
@@ -123,18 +131,60 @@ export class RevocationService {
           },
         });
 
-      if (result.revocationRegistryDefinitionState.state !== 'finished') {
+      if (
+        revocationRegistryDefinitionState.state !== 'action' ||
+        revocationRegistryDefinitionState.action !== 'endorseIndyTransaction'
+      ) {
         throw new Error(
-          `Error registering the revocation registry definition. Error: ${JSON.stringify(
-            result,
-          )}`,
+          `Error registering revocation registry definition: ${
+            revocationRegistryDefinitionState.state === 'failed'
+              ? revocationRegistryDefinitionState.reason
+              : 'Not Finished'
+          }`,
+        );
+      }
+
+      const signedRevocationRegistryDefinitionRequest =
+        await this.agentService.endorseTransaction(
+          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+          // @ts-expect-error
+          revocationRegistryDefinitionState.revocationRegistryDefinitionRequest,
+          endorserDid,
+        );
+
+      const revocationRegisryDefinitionSubmitResult =
+        await t.modules.anoncreds.registerRevocationRegistryDefinition({
+          options: {
+            endorsedTransaction: signedRevocationRegistryDefinitionRequest,
+            endorserMode: 'external',
+          },
+          revocationRegistryDefinition: {
+            maximumCredentialNumber:
+              revocationRegistryDefinitionState.revocationRegistryDefinition
+                .value.maxCredNum,
+            credentialDefinitionId:
+              revocationRegistryDefinitionState.revocationRegistryDefinition
+                .credDefId,
+            tag: revocationRegistryDefinitionState.revocationRegistryDefinition
+              .tag,
+            issuerId:
+              revocationRegistryDefinitionState.revocationRegistryDefinition
+                .issuerId,
+          },
+        });
+
+      if (
+        revocationRegisryDefinitionSubmitResult
+          .revocationRegistryDefinitionState.state !== 'finished'
+      ) {
+        throw Error(
+          `Error while registering revocation registry definition Cause: ${JSON.stringify(revocationRegisryDefinitionSubmitResult)}`,
         );
       }
 
       return {
         revocationRegistryDefinitionId:
-          result.revocationRegistryDefinitionState
-            .revocationRegistryDefinitionId,
+          revocationRegistryDefinitionState.revocationRegistryDefinitionId,
       };
     });
   }
diff --git a/apps/ssi-abstraction/src/agent/schemas/schemas.service.ts b/apps/ssi-abstraction/src/agent/schemas/schemas.service.ts
index 135f28c..2bca51a 100644
--- a/apps/ssi-abstraction/src/agent/schemas/schemas.service.ts
+++ b/apps/ssi-abstraction/src/agent/schemas/schemas.service.ts
@@ -11,11 +11,15 @@ import type {
 
 import { Injectable } from '@nestjs/common';
 
+import { AgentService } from '../agent.service.js';
 import { WithTenantService } from '../withTenantService.js';
 
 @Injectable()
 export class SchemasService {
-  public constructor(private withTenantService: WithTenantService) {}
+  public constructor(
+    private withTenantService: WithTenantService,
+    private agentService: AgentService,
+  ) {}
 
   public async getAll({
     tenantId,
@@ -49,6 +53,8 @@ export class SchemasService {
     EventAnonCredsSchemasRegister['data']
   > {
     return this.withTenantService.invoke(tenantId, async (t) => {
+      const endorserDid = await this.agentService.getEndorserDid(issuerDid);
+
       const { schemaState } =
         await t.modules.anoncreds.registerSchema<IndyVdrRegisterSchemaOptions>({
           schema: {
@@ -58,12 +64,15 @@ export class SchemasService {
             attrNames: attributeNames,
           },
           options: {
-            endorserMode: 'internal',
-            endorserDid: issuerDid,
+            endorserMode: 'external',
+            endorserDid,
           },
         });
 
-      if (schemaState.state !== 'finished' && schemaState.state !== 'action') {
+      if (
+        schemaState.state !== 'action' ||
+        schemaState.action !== 'endorseIndyTransaction'
+      ) {
         throw new Error(
           `Error registering schema: ${
             schemaState.state === 'failed' ? schemaState.reason : 'Not Finished'
@@ -71,6 +80,28 @@ export class SchemasService {
         );
       }
 
+      const signedschemaRequest = await this.agentService.endorseTransaction(
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-expect-error
+        schemaState.schemaRequest,
+        endorserDid,
+      );
+
+      const schemaSubmitResult =
+        await t.modules.anoncreds.registerSchema<IndyVdrRegisterSchemaOptions>({
+          options: {
+            endorsedTransaction: signedschemaRequest,
+            endorserMode: 'external',
+          },
+          schema: schemaState.schema,
+        });
+
+      if (schemaSubmitResult.schemaState.state !== 'finished') {
+        throw Error(
+          `Error while registering schema. Cause: ${JSON.stringify(schemaSubmitResult)}`,
+        );
+      }
+
       return { schemaId: schemaState.schemaId, ...schemaState.schema };
     });
   }
diff --git a/apps/ssi-abstraction/src/agent/withTenantService.ts b/apps/ssi-abstraction/src/agent/withTenantService.ts
index 15b806a..7a7d565 100644
--- a/apps/ssi-abstraction/src/agent/withTenantService.ts
+++ b/apps/ssi-abstraction/src/agent/withTenantService.ts
@@ -12,23 +12,14 @@ export class WithTenantService {
     this.agent = agentService.agent;
   }
 
-  public invoke<T>(
+  public async invoke<T>(
     tenantId: string,
     cb: (tenant: TenantAgent) => Promise<T>,
   ): Promise<T> {
-    // eslint-disable-next-line no-async-promise-executor
-    return new Promise<T>(async (resolve, reject) => {
-      await this.agent.modules.tenants.withTenantAgent(
-        { tenantId },
-        async (tenant) => {
-          try {
-            const ret = await cb(tenant as unknown as TenantAgent);
-            resolve(ret);
-          } catch (e) {
-            reject(e);
-          }
-        },
-      );
+    const tenant = await this.agent.modules.tenants.getTenantAgent({
+      tenantId,
     });
+
+    return cb(tenant as unknown as TenantAgent);
   }
 }
diff --git a/apps/ssi-abstraction/src/app.module.ts b/apps/ssi-abstraction/src/app.module.ts
index 0ff88a6..0f1a47d 100644
--- a/apps/ssi-abstraction/src/app.module.ts
+++ b/apps/ssi-abstraction/src/app.module.ts
@@ -6,8 +6,10 @@ import { HealthController } from '@ocm/shared';
 
 import { AgentModule } from './agent/agent.module.js';
 import { AnonCredsCredentialsModule } from './agent/anoncredsCredentials/anoncredsCredentials.module.js';
+import { AnonCredsProofsModule } from './agent/anoncredsProofs/anoncredsProofs.module.js';
 import { ConnectionsModule } from './agent/connections/connections.module.js';
 import { CredentialDefinitionsModule } from './agent/credentialDefinitions/credentialDefinitions.module.js';
+import { RevocationModule } from './agent/revocation/revocation.module.js';
 import { SchemasModule } from './agent/schemas/schemas.module.js';
 import { TenantsModule } from './agent/tenants/tenants.module.js';
 import { config } from './config/config.js';
@@ -28,7 +30,9 @@ import { validationSchema } from './config/validation.js';
     DidsModule,
     SchemasModule,
     AnonCredsCredentialsModule,
+    AnonCredsProofsModule,
     TenantsModule,
+    RevocationModule,
   ],
   controllers: [HealthController],
 })
diff --git a/apps/ssi-abstraction/src/common/utils.ts b/apps/ssi-abstraction/src/common/utils.ts
new file mode 100644
index 0000000..b47ebbe
--- /dev/null
+++ b/apps/ssi-abstraction/src/common/utils.ts
@@ -0,0 +1,8 @@
+export const parseDid = (did: string) => {
+  const [, method, ...namespaceAndNetwork] = did.split(':');
+
+  return {
+    method,
+    namespaceAndNetwork: namespaceAndNetwork.slice(0, -1).join(':'),
+  };
+};
diff --git a/apps/ssi-abstraction/src/config/ledger.ts b/apps/ssi-abstraction/src/config/ledger.ts
index eea8e8c..c23776d 100644
--- a/apps/ssi-abstraction/src/config/ledger.ts
+++ b/apps/ssi-abstraction/src/config/ledger.ts
@@ -28,6 +28,6 @@ export const LEDGERS = {
   {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"138.197.161.221","client_port":9706,"node_ip":"138.197.161.221","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"},"metadata":{"from":"4cU41vWW82ArfxJxHkzXPG"},"type":"0"},"txnMetadata":{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"},"ver":"1"}
   {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"138.197.161.221","client_port":9708,"node_ip":"138.197.161.221","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"},"metadata":{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"},"type":"0"},"txnMetadata":{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"},"ver":"1"}`,
   },
-} as const;
+};
 
 export type LedgerIds = keyof typeof LEDGERS;
diff --git a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
index 0a9a071..672778b 100644
--- a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
@@ -25,6 +25,7 @@ import {
   EventAnonCredsProofsDeleteById,
   EventDidcommAnonCredsCredentialsOfferToSelf,
 } from '@ocm/shared';
+import { randomBytes } from 'crypto';
 import { firstValueFrom } from 'rxjs';
 
 import { AgentModule } from '../src/agent/agent.module.js';
@@ -82,10 +83,11 @@ describe('Credentials', () => {
     const connectionsService = app.get(ConnectionsService);
     await connectionsService.createConnectionWithSelf({ tenantId });
 
-    const didsService = app.get(DidsService);
-    const [did] = await didsService.registerDidIndyFromSeed({
+    const ds = app.get(DidsService);
+    await ds.registerEndorserDids();
+    const [did] = await ds.registerDidIndyFromSeed({
       tenantId,
-      seed: '12312367897123300000000000000000',
+      seed: randomBytes(16).toString('hex'),
     });
     issuerDid = did;
 
diff --git a/apps/ssi-abstraction/test/credentialDefinitions.e2e-spec.ts b/apps/ssi-abstraction/test/credentialDefinitions.e2e-spec.ts
index 2fd3591..5e95231 100644
--- a/apps/ssi-abstraction/test/credentialDefinitions.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/credentialDefinitions.e2e-spec.ts
@@ -13,6 +13,7 @@ import {
   EventAnonCredsCredentialDefinitionsGetAll,
   EventAnonCredsCredentialDefinitionsRegister,
 } from '@ocm/shared';
+import { randomBytes } from 'crypto';
 import { firstValueFrom } from 'rxjs';
 
 import { AgentModule } from '../src/agent/agent.module.js';
@@ -61,10 +62,11 @@ describe('CredentialDefinitions', () => {
     const { id } = await tenantsService.create({ label: TOKEN });
     tenantId = id;
 
-    const didsService = app.get(DidsService);
-    const [did] = await didsService.registerDidIndyFromSeed({
+    const ds = app.get(DidsService);
+    await ds.registerEndorserDids();
+    const [did] = await ds.registerDidIndyFromSeed({
       tenantId,
-      seed: '12312367897123300000000000000000',
+      seed: randomBytes(16).toString('hex'),
     });
     issuerDid = did;
 
diff --git a/apps/ssi-abstraction/test/dids.e2e-spec.ts b/apps/ssi-abstraction/test/dids.e2e-spec.ts
index 785a8e7..1d0750a 100644
--- a/apps/ssi-abstraction/test/dids.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/dids.e2e-spec.ts
@@ -2,6 +2,7 @@ import type { INestApplication } from '@nestjs/common';
 import type { ClientProxy } from '@nestjs/microservices';
 import type {
   EventDidsDidConfigurationInput,
+  EventDidsRegisterEndorserDidInput,
   EventDidsRegisterIndyFromSeedInput,
   EventDidsResolveInput,
 } from '@ocm/shared';
@@ -10,6 +11,7 @@ import { ClientsModule, Transport } from '@nestjs/microservices';
 import { Test } from '@nestjs/testing';
 import {
   EventDidsDidConfiguration,
+  EventDidsRegisterEndorserDid,
   EventDidsRegisterIndyFromSeed,
   EventDidsResolve,
 } from '@ocm/shared';
@@ -59,6 +61,18 @@ describe('Dids', () => {
     client.close();
   });
 
+  it(EventDidsRegisterEndorserDid.token, async () => {
+    const response$ = client.send<
+      EventDidsRegisterEndorserDid,
+      EventDidsRegisterEndorserDidInput
+    >(EventDidsRegisterEndorserDid.token, { tenantId });
+
+    const response = await firstValueFrom(response$);
+    const eventInstance = EventDidsRegisterEndorserDid.fromEvent(response);
+
+    expect(eventInstance.data).toMatchObject({});
+  });
+
   it(EventDidsRegisterIndyFromSeed.token, async () => {
     const response$ = client.send<
       EventDidsRegisterIndyFromSeed,
@@ -84,6 +98,23 @@ describe('Dids', () => {
   });
 
   it(EventDidsDidConfiguration.token, async () => {
+    const registerIndyDidResponse$ = client.send<
+      EventDidsRegisterIndyFromSeed,
+      EventDidsRegisterIndyFromSeedInput
+    >(EventDidsRegisterIndyFromSeed.token, {
+      seed: randomBytes(16).toString('hex'),
+      tenantId,
+      services: [
+        {
+          url: 'https://example.org',
+          type: 'endpoint',
+          identifier: 'endpoint',
+        },
+      ],
+    });
+
+    await firstValueFrom(registerIndyDidResponse$);
+
     const response$ = client.send<
       EventDidsDidConfiguration,
       EventDidsDidConfigurationInput
@@ -99,7 +130,7 @@ describe('Dids', () => {
     expect(eventInstance.instance).toMatchObject({
       entries: expect.arrayContaining([
         expect.objectContaining({
-          did: 'did:indy:bcovrin:test:9MMeff63VnCpogD2FWfKnJ',
+          did: expect.any(String),
           jwt: expect.any(String),
         }),
       ]),
diff --git a/apps/ssi-abstraction/test/jest.config.js b/apps/ssi-abstraction/test/jest.config.js
index a166038..11a9deb 100644
--- a/apps/ssi-abstraction/test/jest.config.js
+++ b/apps/ssi-abstraction/test/jest.config.js
@@ -3,7 +3,7 @@ import config from '../jest.config.js';
 /** @type {import('jest').Config} */
 export default {
   ...config,
-  testTimeout: 42000,
+  testTimeout: 60000,
   rootDir: '.',
   testRegex: '.*\\.e2e-spec\\.ts$',
 };
diff --git a/apps/ssi-abstraction/test/revocation.e2e-spec.ts b/apps/ssi-abstraction/test/revocation.e2e-spec.ts
new file mode 100644
index 0000000..83b1767
--- /dev/null
+++ b/apps/ssi-abstraction/test/revocation.e2e-spec.ts
@@ -0,0 +1,129 @@
+import type { INestApplication } from '@nestjs/common';
+import type { ClientProxy } from '@nestjs/microservices';
+import type { EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput } from '@ocm/shared';
+
+import { ClientsModule, Transport } from '@nestjs/microservices';
+import { Test } from '@nestjs/testing';
+import { EventAnonCredsRevocationRegisterRevocationRegistryDefinition } from '@ocm/shared';
+import { randomBytes } from 'crypto';
+import { firstValueFrom } from 'rxjs';
+
+import { AgentModule } from '../src/agent/agent.module.js';
+import { AnonCredsCredentialsModule } from '../src/agent/anoncredsCredentials/anoncredsCredentials.module.js';
+import { ConnectionsModule } from '../src/agent/connections/connections.module.js';
+import { ConnectionsService } from '../src/agent/connections/connections.service.js';
+import { CredentialDefinitionsModule } from '../src/agent/credentialDefinitions/credentialDefinitions.module.js';
+import { CredentialDefinitionsService } from '../src/agent/credentialDefinitions/credentialDefinitions.service.js';
+import { DidsModule } from '../src/agent/dids/dids.module.js';
+import { DidsService } from '../src/agent/dids/dids.service.js';
+import { RevocationModule } from '../src/agent/revocation/revocation.module.js';
+import { SchemasModule } from '../src/agent/schemas/schemas.module.js';
+import { SchemasService } from '../src/agent/schemas/schemas.service.js';
+import { TenantsModule } from '../src/agent/tenants/tenants.module.js';
+import { TenantsService } from '../src/agent/tenants/tenants.service.js';
+import { mockConfigModule } from '../src/config/__tests__/mockConfig.js';
+
+describe('Revocation', () => {
+  const TOKEN = 'REVOCATION_CLIENT_SERVICE';
+  let app: INestApplication;
+  let client: ClientProxy;
+  let tenantId: string;
+
+  let issuerDid: string;
+  let credentialDefinitionId: string;
+
+  beforeAll(async () => {
+    const moduleRef = await Test.createTestingModule({
+      imports: [
+        mockConfigModule(3004, true),
+        AgentModule,
+        ConnectionsModule,
+        SchemasModule,
+        CredentialDefinitionsModule,
+        AnonCredsCredentialsModule,
+        TenantsModule,
+        DidsModule,
+        RevocationModule,
+        ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
+      ],
+    }).compile();
+
+    app = moduleRef.createNestApplication();
+
+    app.connectMicroservice({ transport: Transport.NATS });
+
+    await app.startAllMicroservices();
+    await app.init();
+
+    client = app.get(TOKEN);
+    await client.connect();
+
+    const tenantsService = app.get(TenantsService);
+    const { id } = await tenantsService.create({ label: TOKEN });
+    tenantId = id;
+
+    const connectionsService = app.get(ConnectionsService);
+    await connectionsService.createConnectionWithSelf({ tenantId });
+
+    const ds = app.get(DidsService);
+    await ds.registerEndorserDids();
+    const [did] = await ds.registerDidIndyFromSeed({
+      tenantId,
+      seed: randomBytes(16).toString('hex'),
+    });
+    issuerDid = did;
+
+    const schemaService = app.get(SchemasService);
+    const { schemaId } = await schemaService.register({
+      issuerDid,
+      tenantId,
+      name: 'test-schema-name',
+      version: `1.${Date.now()}`,
+      attributeNames: ['Name', 'Age'],
+    });
+
+    const credentialDefinitionService = app.get(CredentialDefinitionsService);
+    const { credentialDefinitionId: cdi } =
+      await credentialDefinitionService.register({
+        supportsRevocation: true,
+        tenantId,
+        issuerDid,
+        schemaId,
+        tag: `default-${Date.now()}`,
+      });
+
+    credentialDefinitionId = cdi;
+  });
+
+  afterAll(async () => {
+    await app.close();
+    client.close();
+  });
+
+  it(
+    EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token,
+    async () => {
+      const response$ = client.send<
+        EventAnonCredsRevocationRegisterRevocationRegistryDefinition,
+        EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput
+      >(EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token, {
+        tenantId,
+        tag: 'rev-tag',
+        issuerDid,
+        credentialDefinitionId,
+        maximumCredentialNumber: 100,
+      });
+      const response = await firstValueFrom(response$);
+      const eventInstance =
+        EventAnonCredsRevocationRegisterRevocationRegistryDefinition.fromEvent(
+          response,
+        );
+
+      expect(
+        eventInstance.instance.revocationRegistryDefinitionId.startsWith(
+          'did:indy:bcorvin:test:',
+        ),
+      ).toBeTruthy();
+    },
+  );
+});
diff --git a/apps/ssi-abstraction/test/schemas.e2e-spec.ts b/apps/ssi-abstraction/test/schemas.e2e-spec.ts
index abab76b..37c4805 100644
--- a/apps/ssi-abstraction/test/schemas.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/schemas.e2e-spec.ts
@@ -13,6 +13,7 @@ import {
   EventAnonCredsSchemasGetById,
   EventAnonCredsSchemasRegister,
 } from '@ocm/shared';
+import { randomBytes } from 'crypto';
 import { firstValueFrom } from 'rxjs';
 
 import { AgentModule } from '../src/agent/agent.module.js';
@@ -57,9 +58,11 @@ describe('Schemas', () => {
     tenantId = id;
 
     const ds = app.get(DidsService);
+
+    await ds.registerEndorserDids();
     const [did] = await ds.registerDidIndyFromSeed({
       tenantId,
-      seed: '12312367897123300000000000000000',
+      seed: randomBytes(16).toString('hex'),
     });
     issuerDid = did;
   });
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f08918a..d7a16be 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -447,12 +447,13 @@ importers:
         version: 0.5.0-alpha.116(expo@49.0.21)(react-native@0.73.2)
 =======
       '@aries-framework/anoncreds':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/core':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/tenants':
+<<<<<<< HEAD
 <<<<<<< HEAD
         specifier: ^0.5.0-alpha.87
         version: 0.5.0-alpha.91(expo@49.0.21)(react-native@0.73.2)
@@ -461,6 +462,10 @@ importers:
         specifier: 0.5.0-alpha.87
         version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
 >>>>>>> 63efb70 (fix: resolved merge issues)
+=======
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
+>>>>>>> 7db39fe (feat: added transaction endorsement)
       '@elastic/ecs-winston-format':
         specifier: ^1.5.0
         version: 1.5.2
@@ -564,24 +569,25 @@ importers:
         version: 0.5.0-alpha.116(expo@49.0.21)(react-native@0.73.2)
 =======
       '@aries-framework/anoncreds':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/anoncreds-rs':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(@hyperledger/anoncreds-shared@0.2.0-dev.8)(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(@hyperledger/anoncreds-shared@0.2.0-dev.8)(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/askar':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(@hyperledger/aries-askar-shared@0.2.0-dev.5)(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(@hyperledger/aries-askar-shared@0.2.0-dev.5)(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/core':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/indy-vdr':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(@hyperledger/indy-vdr-shared@0.2.0-dev.6)(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(@hyperledger/indy-vdr-shared@0.2.0-dev.6)(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/node':
-        specifier: 0.5.0-alpha.87
-        version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@aries-framework/tenants':
+<<<<<<< HEAD
 <<<<<<< HEAD
         specifier: ^0.5.0-alpha.87
         version: 0.5.0-alpha.91(expo@49.0.21)(react-native@0.73.2)
@@ -590,6 +596,10 @@ importers:
         specifier: 0.5.0-alpha.87
         version: 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
 >>>>>>> 63efb70 (fix: resolved merge issues)
+=======
+        specifier: 0.5.0-alpha.93
+        version: 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
+>>>>>>> 7db39fe (feat: added transaction endorsement)
       '@elastic/ecs-winston-format':
         specifier: ^1.5.0
         version: 1.5.2
@@ -799,6 +809,7 @@ packages:
       - chokidar
     dev: true
 
+<<<<<<< HEAD
 <<<<<<< HEAD
   /@astronautlabs/jsonpath@1.1.2:
     resolution: {integrity: sha512-FqL/muoreH7iltYC1EB5Tvox5E8NSOOPGkgns4G+qxRKl6k5dxEVljUjB5NcKESzkqwnUqWjSZkL61XGYOuV+A==}
@@ -807,11 +818,15 @@ packages:
 =======
   /@aries-framework/anoncreds-rs@0.5.0-alpha.87(@hyperledger/anoncreds-shared@0.2.0-dev.8)(expo@49.0.21)(react-native@0.73.2):
     resolution: {integrity: sha512-5SOfD65roN9A9WTJ+93yBdB+OcgUMhaoF9f1EDvMnneB0u80Yy+YLxEDs9QVcDJghh5mu7LlxfjGU8GLaaV7Bw==}
+=======
+  /@aries-framework/anoncreds-rs@0.5.0-alpha.93(@hyperledger/anoncreds-shared@0.2.0-dev.8)(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-jiSIjdT3CsW98/5soWTzgKTZhCHIDzM8lQhFgaads4V+1L6a/3+ZMz0lQK7CZa1Pvd1v6it92Zd2ULMnqnMd+A==}
+>>>>>>> 7db39fe (feat: added transaction endorsement)
     peerDependencies:
       '@hyperledger/anoncreds-shared': ^0.2.0-dev.5
     dependencies:
-      '@aries-framework/anoncreds': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/anoncreds': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@hyperledger/anoncreds-shared': 0.2.0-dev.8
       class-transformer: 0.5.1
       class-validator: 0.14.0
@@ -825,10 +840,10 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/anoncreds@0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-z1VtGt10INv8hYlraGpIsr8jRQBFMFGAAT107ariBHdAu+jXw8ajD1Z7VbuEHT6mxOJUd3kYxfEUchYTC88mLg==}
+  /@aries-framework/anoncreds@0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-xoDx9LpvxMD8Jci0AwlzEHJRdAat9XOF2niUOzKSbWy9WBUfgbY836mMEe05hsJXgmjGTXwfL83NCqznOdEOFg==}
     dependencies:
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       bn.js: 5.2.1
       class-transformer: 0.5.1
       class-validator: 0.14.0
@@ -841,12 +856,12 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/askar@0.5.0-alpha.87(@hyperledger/aries-askar-shared@0.2.0-dev.5)(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-KcWhKdekxnKJF/rxDrXcgBsL5UO8cd8dBZwSbtSTYP/VANb8OPakd2fw0MvSf3HF4U8JQtU0fK8taAK4tOy1Gw==}
+  /@aries-framework/askar@0.5.0-alpha.93(@hyperledger/aries-askar-shared@0.2.0-dev.5)(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-2oSIWQ+pV1zzCwBLhvsXBX1ZuM6TeH74XLbjcZmcuRbSkc1GQwTNAYg+zUS2RyfAXiWKzwHyqXLhVWjhjmUTnw==}
     peerDependencies:
       '@hyperledger/aries-askar-shared': ^0.2.0-dev.5
     dependencies:
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@hyperledger/aries-askar-shared': 0.2.0-dev.5
       bn.js: 5.2.1
       class-transformer: 0.5.1
@@ -861,8 +876,8 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/core@0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-8V0HsaakhGD9WuCz3WIYpBtD7vCYDhFYCKxXcGXEpJ76Ae3kTUpQSqhbZpFXBvccz8UalzYZtTtsi4YXpyaj3w==}
+  /@aries-framework/core@0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-mxF45NfUnBDW4/fQY2g5x5UxCk8GTAfuQb9v2zWOUY8y+qVd35QApkDBqJIvAl1D91X5+V6xRgTnW/Cluq32aA==}
     dependencies:
       '@digitalcredentials/jsonld': 5.2.2(expo@49.0.21)(react-native@0.73.2)
       '@digitalcredentials/jsonld-signatures': 9.3.2(expo@49.0.21)(react-native@0.73.2)
@@ -902,13 +917,13 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/indy-vdr@0.5.0-alpha.87(@hyperledger/indy-vdr-shared@0.2.0-dev.6)(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-rj3hqrq2MggqKp8P06edyTXWINKrtcXpFSFd4jG8Ttr5ObR9vdya0G7EdFT7tKHtGkqD8/qbyDF2D7woZMFEkg==}
+  /@aries-framework/indy-vdr@0.5.0-alpha.93(@hyperledger/indy-vdr-shared@0.2.0-dev.6)(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-xJMn1snLnA/rWvix837CkGc31ss5rcQw316dK+93YG1jh18KuqsMNBgGRGxrYdT8BeP6CwJisTz15KU7QmJIEA==}
     peerDependencies:
       '@hyperledger/indy-vdr-shared': ^0.2.0-dev.6
     dependencies:
-      '@aries-framework/anoncreds': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/anoncreds': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@hyperledger/indy-vdr-shared': 0.2.0-dev.6
     transitivePeerDependencies:
       - domexception
@@ -918,12 +933,12 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/node@0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-jXNNaGMF/qNCGI5LGyLgZ3cf7MMYNpthh3R+i10jnwFTXH+DjgNy8l+fQLx867T+Hv7+4c+belse6YAtGRZ80Q==}
+  /@aries-framework/node@0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-Ieorxky6fmayKxAMb7b7JbsCTja9enhMdeLp5UEpuWVWA2I/IQFSyAGFgLs7scTn40dQ4Fe8MvhYYk6OIpDGtw==}
     dependencies:
       '@2060.io/ffi-napi': 4.0.8
       '@2060.io/ref-napi': 3.0.6
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       '@types/express': 4.17.21
       express: 4.18.2
       ws: 8.16.0
@@ -938,10 +953,10 @@ packages:
       - web-streams-polyfill
     dev: false
 
-  /@aries-framework/tenants@0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2):
-    resolution: {integrity: sha512-txx2hZjQ5lpcS+vbfaw9ZTNF+SA1DfYuLmGwjdVMNUmMxlCr8siks4MV1h194dGecC53w44Ab+H6AozvRDktog==}
+  /@aries-framework/tenants@0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2):
+    resolution: {integrity: sha512-xgfFqOhh5EUAtCmS6MKGjfCt02WZgYF4LtE1gRZYD3uq8W5BZHSSF11QcWieO6Wl4Hnnjuz7d+p+f0WRju8BVg==}
     dependencies:
-      '@aries-framework/core': 0.5.0-alpha.87(expo@49.0.21)(react-native@0.73.2)
+      '@aries-framework/core': 0.5.0-alpha.93(expo@49.0.21)(react-native@0.73.2)
       async-mutex: 0.4.0
     transitivePeerDependencies:
       - domexception
@@ -4584,7 +4599,7 @@ packages:
     dependencies:
       '@nestjs/axios': 3.0.1(@nestjs/common@10.3.0)(axios@1.6.5)(reflect-metadata@0.1.14)(rxjs@7.8.1)
       '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1)
-      '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(@nestjs/microservices@10.3.0)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
+      '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(@nestjs/microservices@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
       '@nestjs/microservices': 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(nats@2.19.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
       boxen: 5.1.2
       check-disk-space: 3.4.0
-- 
GitLab