From 30c48829f6ea7752447be14d42dc6667ad41c221 Mon Sep 17 00:00:00 2001 From: ilya-korotya Date: Thu, 28 Nov 2024 18:27:23 +0100 Subject: [PATCH] handle onchain-offer message --- src/iden3comm/handlers/fetch.ts | 49 +++++++++++++++++++ .../onchain-non-merklized-issuer-adapter.ts | 9 ++++ src/storage/blockchain/onchain-issuer.ts | 29 +++++++++-- src/storage/interfaces/index.ts | 1 + src/storage/interfaces/onchain-issuer.ts | 13 +++++ 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 src/storage/interfaces/onchain-issuer.ts diff --git a/src/iden3comm/handlers/fetch.ts b/src/iden3comm/handlers/fetch.ts index dd5a197c..630af3af 100644 --- a/src/iden3comm/handlers/fetch.ts +++ b/src/iden3comm/handlers/fetch.ts @@ -6,6 +6,7 @@ import { CredentialFetchRequestMessage, CredentialIssuanceMessage, CredentialsOfferMessage, + CredentialsOnchainOfferMessage, IPackageManager, JWSPackerParams, MessageFetchRequestMessage @@ -19,6 +20,7 @@ import { proving } from '@iden3/js-jwz'; import { DID } from '@iden3/js-iden3-core'; import * as uuid from 'uuid'; import { AbstractMessageHandler, IProtocolMessageHandler } from './message-handler'; +import { IOnchainIssuer } from '../../storage'; /** * @@ -99,6 +101,7 @@ export class FetchHandler private readonly _packerMgr: IPackageManager, private readonly opts?: { credentialWallet: ICredentialWallet; + onchainIssuer?: IOnchainIssuer; } ) { super(); @@ -123,11 +126,43 @@ export class FetchHandler return this.handleFetchRequest(message as CredentialFetchRequestMessage); case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE: return this.handleIssuanceResponseMsg(message as CredentialIssuanceMessage); + case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE: { + const result = await this.handleOnchainOfferMessage( + message as CredentialsOnchainOfferMessage + ); + if (Array.isArray(result)) { + const credWallet = this.opts?.credentialWallet; + if (!credWallet) throw new Error('Credential wallet is not provided'); + await credWallet.saveAll(result); + return null; + } + return result as BasicMessage; + } default: return super.handle(message, ctx); } } + private async handleOnchainOfferMessage( + offerMessage: CredentialsOnchainOfferMessage + ): Promise { + if (!this.opts?.onchainIssuer) { + throw new Error('onchain issuer is not provided'); + } + + const credentials: W3CCredential[] = []; + for (const credentialInfo of offerMessage.body.credentials) { + const userId = DID.idFromDID(DID.parse(offerMessage.from)); + const credential = await this.opts.onchainIssuer.getCredential( + userId, + BigInt(credentialInfo.id) + ); + credentials.push(credential); + } + + return credentials; + } + private async handleOfferMessage( offerMessage: CredentialsOfferMessage, ctx: { @@ -244,6 +279,20 @@ export class FetchHandler throw new Error('invalid protocol message response'); } + /** + * Handles only messages with credentials/1.0/onchain-offer type + * @beta + */ + async handleOnchainOffer(offer: Uint8Array): Promise { + const offerMessage = await FetchHandler.unpackMessage( + this._packerMgr, + offer, + PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE + ); + + return this.handleOnchainOfferMessage(offerMessage); + } + private async handleFetchRequest( msgRequest: CredentialFetchRequestMessage ): Promise { diff --git a/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts b/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts index 9dd450bc..fef45ae4 100644 --- a/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts +++ b/src/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.ts @@ -127,6 +127,15 @@ export class OnchainNonMerklizedIssuerAdapter { return { credentialData, coreClaimBigInts, credentialSubjectFields }; } + /** + * Retrieves the credential IDs of a user. + * @param userId The user's core.Id. + * @returns An array of credential IDs. + */ + public async getUserCredentialsIds(userId: Id): Promise { + return this._contract.getUserCredentialIds(userId.bigInt()); + } + /** * Converts on-chain credential to a verifiable credential. * diff --git a/src/storage/blockchain/onchain-issuer.ts b/src/storage/blockchain/onchain-issuer.ts index 405a6b21..a952982c 100644 --- a/src/storage/blockchain/onchain-issuer.ts +++ b/src/storage/blockchain/onchain-issuer.ts @@ -4,7 +4,8 @@ import { INonMerklizedIssuerABI as abi } from '@iden3/onchain-non-merklized-issu import { Options } from '@iden3/js-jsonld-merklization'; import { W3CCredential } from '../../verifiable'; import { OnchainNonMerklizedIssuerAdapter } from './onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter'; -import { EthConnectionConfig } from '..'; +import { EthConnectionConfig } from './state'; +import { IOnchainIssuer } from '../interfaces/onchain-issuer'; enum OnchainIssuerVersion { 'v0.0.1' = '0.0.1' @@ -17,7 +18,7 @@ enum OnchainIssuerVersion { * @beta * @class OnchainIssuer */ -export class OnchainIssuer { +export class OnchainIssuer implements IOnchainIssuer { private readonly _url: string; private readonly _chainId: number; private readonly _contractAddress: string; @@ -52,7 +53,7 @@ export class OnchainIssuer { } /** - * Retrieves a credential from the on-chain non-merklized contract. + * Retrieves a credential from the on-chain issuer. * @param userId The user's core.Id. * @param credentialId The unique identifier of the credential. */ @@ -79,4 +80,26 @@ export class OnchainIssuer { throw new Error(`Unsupported adapter version ${response}`); } } + + /** + * Retrieves the credential identifiers for a user from the on-chain issuer. + * @param userId The user's core.Id. + */ + public async getUserCredentialIds(userId: Id): Promise { + const response = await this._contract.getCredentialAdapterVersion(); + switch (response) { + case OnchainIssuerVersion['v0.0.1']: { + const adapter = new OnchainNonMerklizedIssuerAdapter(this._contractAddress, { + rpcUrl: this._url, + chainId: this._chainId, + issuerDid: this._issuerDid, + merklizationOptions: this._merklizationOptions + }); + await adapter.isSupportsInterface(); + return await adapter.getUserCredentialsIds(userId); + } + default: + throw new Error(`Unsupported adapter version ${response}`); + } + } } diff --git a/src/storage/interfaces/index.ts b/src/storage/interfaces/index.ts index a24d2597..8086ee77 100644 --- a/src/storage/interfaces/index.ts +++ b/src/storage/interfaces/index.ts @@ -7,3 +7,4 @@ export * from './data-source'; export * from './circuits'; export * from './onchain-zkp-verifier'; export * from './onchain-revocation'; +export * from './onchain-issuer'; diff --git a/src/storage/interfaces/onchain-issuer.ts b/src/storage/interfaces/onchain-issuer.ts new file mode 100644 index 00000000..d2588079 --- /dev/null +++ b/src/storage/interfaces/onchain-issuer.ts @@ -0,0 +1,13 @@ +import { Id } from '@iden3/js-iden3-core'; +import { W3CCredential } from '../../verifiable'; + +/** + * Interface that allows the processing of the on-chain issuer + * + * @beta + * @interface IOnchainIssuer + */ +export interface IOnchainIssuer { + getCredential(userId: Id, credentialId: bigint): Promise; + getUserCredentialIds(userId: Id): Promise; +}