From da2b52ffddcfbb977bfcd0e88828999a22c18180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Tue, 19 Nov 2024 20:20:43 +0300 Subject: [PATCH 1/4] feat: revoke in issuer --- packages/credentials/src/issuer.ts | 71 ++++++++++++++++++++++++++++++ tests/bundle/bundle-test.ts | 18 ++++++++ 2 files changed, 89 insertions(+) diff --git a/packages/credentials/src/issuer.ts b/packages/credentials/src/issuer.ts index 712b40442..853a5dad0 100644 --- a/packages/credentials/src/issuer.ts +++ b/packages/credentials/src/issuer.ts @@ -15,6 +15,16 @@ import type { CTypeLoader } from './ctype/index.js' import type { IssuerOptions, SubmitOverride } from './interfaces.js' export type { IssuerOptions } +import * as Kilt from '@kiltprotocol/sdk-js' +import * as KiltChain from '@kiltprotocol/chain-helpers' +import type { + KiltAddress, + SignerInterface, + KeyringPair, + DidUrl, +} from '@kiltprotocol/types' +import {authorizeTx} from "@kiltprotocol/did" +import { base58Decode } from '@polkadot/util-crypto' /** * Creates a new credential document as a basis for issuing a credential. @@ -134,3 +144,64 @@ export async function issue({ ) } } + +/** +* Revokes a Kilt credential on the blockchain, making it invalid. +* +* @param attester The DID URL of the attester revoking the credential +* @param submitterAccount The account that will submit and pay for the transaction +* @param signCallback Callback function to sign the DID authorization +* @param credential The Verifiable Credential to be revoked +* @returns An object containing: +* - success: Boolean indicating if revocation was successful +* - error?: Array of error messages if revocation failed +* - info: Object containing blockchain transaction details: +* - blockNumber?: Block number where transaction was included +* - blockHash?: Hash of the block +* - transactionHash?: Hash of the transaction +*/ +export async function revoke( + attester: DidUrl, + submitterAccount: KeyringPair, + signCallback: any, + credential: VerifiableCredential, + ): Promise<{success: boolean, error?: Array, info: {blockNumber?: string, blockHash?: string, transactionHash?: string}}> { + try { + const api = Kilt.ConfigService.get('api') + const rootHash = credential.id?.split(':').pop()! + const decodedroothash = base58Decode(rootHash); + + const revokeTx = api.tx.attestation.revoke(decodedroothash, null) as any + const [submitter] = (await Kilt.getSignersForKeypair({ + keypair: submitterAccount, + type: 'Ed25519', + })) as Array> + + const authorizedTx = await authorizeTx( + attester, + revokeTx, + signCallback, + submitter.id + ) + + const response = await KiltChain.Blockchain.signAndSubmitTx(authorizedTx, submitterAccount) as Object + const responseObj = JSON.parse(JSON.stringify(response)); + + return { + success: true, + info: { + blockNumber: responseObj.blockNumber, + blockHash: responseObj.status.finalized, + transactionHash: responseObj.txHash + } + } + + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + return { + success: false, + error: [errorMessage], + info: {} + } + } +} \ No newline at end of file diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 43ca10776..6e2a912b4 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -370,6 +370,24 @@ async function runAll() { console.log('Did deactivated') +// ┏━━━━━━━━━━━━━━━━━━┓ +// ┃ Revoke credential┃ +// ┗━━━━━━━━━━━━━━━━━━┛ +// +// Revoke a previously issued credential on chain +const revokeCredentialResult = await Kilt.Issuer.revoke( + didDocument.id, + submitter, + signers, + credential + ) + + if (!revokeCredentialResult.success) { + throw new Error(`revoke credential failed: ${revokeCredentialResult.error?.join(', ')}`) + } + + console.log('credential revoked') + // Release the connection to the blockchain. await api.disconnect() From ccac9b90e1ceac14a1c26d443d3fcef994745055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Tue, 3 Dec 2024 13:20:16 +0300 Subject: [PATCH 2/4] fix: review notes --- packages/credentials/src/issuer.ts | 151 ++++++++++++++++++----------- tests/bundle/bundle-test.ts | 36 +++---- 2 files changed, 115 insertions(+), 72 deletions(-) diff --git a/packages/credentials/src/issuer.ts b/packages/credentials/src/issuer.ts index 853a5dad0..d2555d3f0 100644 --- a/packages/credentials/src/issuer.ts +++ b/packages/credentials/src/issuer.ts @@ -5,26 +5,28 @@ * found in the LICENSE file in the root directory of this source tree. */ -import type { Did, ICType, IClaimContents } from '@kiltprotocol/types' - -import { SDKErrors } from '@kiltprotocol/utils' -import { KiltAttestationProofV1, KiltCredentialV1 } from './V1/index.js' -import type { UnsignedVc, VerifiableCredential } from './V1/types.js' -import type { CTypeLoader } from './ctype/index.js' +import { SDKErrors, Signers } from '@kiltprotocol/utils' // eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { IssuerOptions, SubmitOverride } from './interfaces.js' - -export type { IssuerOptions } -import * as Kilt from '@kiltprotocol/sdk-js' import * as KiltChain from '@kiltprotocol/chain-helpers' +// import * as Kilt from '@kiltprotocol/sdk-js' +// import * as KiltChain from '@kiltprotocol/chain-helpers' import type { KiltAddress, SignerInterface, - KeyringPair, - DidUrl, + Did, + ICType, + IClaimContents, + MultibaseKeyPair, } from '@kiltprotocol/types' -import {authorizeTx} from "@kiltprotocol/did" +import { authorizeTx } from '@kiltprotocol/did' import { base58Decode } from '@polkadot/util-crypto' +import { ConfigService } from '@kiltprotocol/config' +import type { IssuerOptions, SubmitOverride } from './interfaces.js' +import type { CTypeLoader } from './ctype/index.js' +import type { UnsignedVc, VerifiableCredential } from './V1/types.js' +import { KiltAttestationProofV1, KiltCredentialV1 } from './V1/index.js' + +export type { IssuerOptions } /** * Creates a new credential document as a basis for issuing a credential. @@ -145,63 +147,104 @@ export async function issue({ } } +interface RevokeResult { + success: boolean + error?: string[] + info: { + blockNumber?: string + blockHash?: string + transactionHash?: string + } +} + +interface BlockchainResponse { + blockNumber: string + status: { + finalized: string + } + txHash: string +} + /** -* Revokes a Kilt credential on the blockchain, making it invalid. -* -* @param attester The DID URL of the attester revoking the credential -* @param submitterAccount The account that will submit and pay for the transaction -* @param signCallback Callback function to sign the DID authorization -* @param credential The Verifiable Credential to be revoked -* @returns An object containing: -* - success: Boolean indicating if revocation was successful -* - error?: Array of error messages if revocation failed -* - info: Object containing blockchain transaction details: -* - blockNumber?: Block number where transaction was included -* - blockHash?: Hash of the block -* - transactionHash?: Hash of the transaction -*/ + * Revokes a Kilt credential on the blockchain, making it invalid. + * + * @param params Named parameters for the revocation process. + * @param params.issuer Interfaces for interacting with the issuer identity. + * @param params.issuer.didDocument The DID Document of the issuer revoking the credential. + * @param params.issuer.signers Array of signer interfaces for credential authorization. + * @param params.issuer.submitter The submitter can be one of: + * - A MultibaseKeyPair for signing transactions + * - A Ed25519 type keypair for blockchain interactions + * The submitter will be used to cover transaction fees and blockchain operations. + * @param params.credential The Verifiable Credential to be revoked. Must contain a valid credential ID. + * @param issuer + * @param credential + * @returns An object containing: + * - success: Boolean indicating if revocation was successful + * - error?: Array of error messages if revocation failed + * - info: Object containing blockchain transaction details: + * - blockNumber?: The block number where revocation was included + * - blockHash?: The hash of the finalized block + * - transactionHash?: The hash of the revocation transaction. + * @throws Will return error response if: + * - Credential ID is invalid or cannot be decoded + * - DID authorization fails + * - Transaction signing or submission fails. + */ export async function revoke( - attester: DidUrl, - submitterAccount: KeyringPair, - signCallback: any, - credential: VerifiableCredential, - ): Promise<{success: boolean, error?: Array, info: {blockNumber?: string, blockHash?: string, transactionHash?: string}}> { + issuer: IssuerOptions, + credential: VerifiableCredential +): Promise { try { - const api = Kilt.ConfigService.get('api') - const rootHash = credential.id?.split(':').pop()! - const decodedroothash = base58Decode(rootHash); - + if (!credential.id) { + throw new Error('Credential ID is required for revocation') + } + + const rootHash = credential.id.split(':').pop() + if (!rootHash) { + throw new Error('Invalid credential ID format') + } + + const decodedroothash = base58Decode(rootHash) + const { didDocument, signers, submitter } = issuer + const api = ConfigService.get('api') + + console.log(didDocument) + const revokeTx = api.tx.attestation.revoke(decodedroothash, null) as any - const [submitter] = (await Kilt.getSignersForKeypair({ - keypair: submitterAccount, - type: 'Ed25519', + const [Txsubmitter] = (await Signers.getSignersForKeypair({ + keypair: submitter as MultibaseKeyPair, + type: 'Ed25519', })) as Array> - const authorizedTx = await authorizeTx( - attester, + didDocument, revokeTx, - signCallback, - submitter.id + signers as SignerInterface[], + Txsubmitter.id ) - - const response = await KiltChain.Blockchain.signAndSubmitTx(authorizedTx, submitterAccount) as Object - const responseObj = JSON.parse(JSON.stringify(response)); - + + const response = (await KiltChain.Blockchain.signAndSubmitTx( + authorizedTx, + Txsubmitter + )) as unknown as BlockchainResponse + + const responseObj = JSON.parse(JSON.stringify(response)) + return { success: true, info: { blockNumber: responseObj.blockNumber, blockHash: responseObj.status.finalized, - transactionHash: responseObj.txHash - } + transactionHash: responseObj.txHash, + }, } - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + const errorMessage = + error instanceof Error ? error.message : 'Unknown error occurred' return { success: false, error: [errorMessage], - info: {} + info: {}, } - } -} \ No newline at end of file + } +} diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 6e2a912b4..302a45344 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -370,24 +370,24 @@ async function runAll() { console.log('Did deactivated') -// ┏━━━━━━━━━━━━━━━━━━┓ -// ┃ Revoke credential┃ -// ┗━━━━━━━━━━━━━━━━━━┛ -// -// Revoke a previously issued credential on chain -const revokeCredentialResult = await Kilt.Issuer.revoke( - didDocument.id, - submitter, - signers, - credential - ) - - if (!revokeCredentialResult.success) { - throw new Error(`revoke credential failed: ${revokeCredentialResult.error?.join(', ')}`) - } - - console.log('credential revoked') - + // ┏━━━━━━━━━━━━━━━━━━┓ + // ┃ Revoke credential┃ + // ┗━━━━━━━━━━━━━━━━━━┛ + // + // Revoke a previously issued credential on chain + const revokeCredentialResult = await Kilt.Issuer.revoke( + didDocument.id, + credential + ) + + if (!revokeCredentialResult.success) { + throw new Error( + `revoke credential failed: ${revokeCredentialResult.error?.join(', ')}` + ) + } + + console.log('credential revoked') + // Release the connection to the blockchain. await api.disconnect() From d7562d1eb5e1b552e4558c50a9f982fa1108d97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Tue, 3 Dec 2024 13:25:53 +0300 Subject: [PATCH 3/4] fix: merge-fix --- packages/credentials/src/issuer.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/credentials/src/issuer.ts b/packages/credentials/src/issuer.ts index d2555d3f0..2f8ca5f6e 100644 --- a/packages/credentials/src/issuer.ts +++ b/packages/credentials/src/issuer.ts @@ -7,9 +7,7 @@ import { SDKErrors, Signers } from '@kiltprotocol/utils' // eslint-disable-next-line @typescript-eslint/no-unused-vars -import * as KiltChain from '@kiltprotocol/chain-helpers' -// import * as Kilt from '@kiltprotocol/sdk-js' -// import * as KiltChain from '@kiltprotocol/chain-helpers' +import { Blockchain } from '@kiltprotocol/chain-helpers' import type { KiltAddress, SignerInterface, @@ -223,7 +221,7 @@ export async function revoke( Txsubmitter.id ) - const response = (await KiltChain.Blockchain.signAndSubmitTx( + const response = (await Blockchain.signAndSubmitTx( authorizedTx, Txsubmitter )) as unknown as BlockchainResponse From 110a5cc482545b61bf5e514493616e2ffd3aaa69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Thu, 19 Dec 2024 12:26:09 +0300 Subject: [PATCH 4/4] fix: relocation of revoke func --- .../src/V1/KiltRevocationStatusV1.ts | 120 +++++++++++++- packages/credentials/src/issuer.ts | 155 ++++++------------ 2 files changed, 162 insertions(+), 113 deletions(-) diff --git a/packages/credentials/src/V1/KiltRevocationStatusV1.ts b/packages/credentials/src/V1/KiltRevocationStatusV1.ts index 16130a9d7..237781418 100644 --- a/packages/credentials/src/V1/KiltRevocationStatusV1.ts +++ b/packages/credentials/src/V1/KiltRevocationStatusV1.ts @@ -9,23 +9,133 @@ import { u8aEq, u8aToHex, u8aToU8a } from '@polkadot/util' import { base58Decode, base58Encode } from '@polkadot/util-crypto' import type { ApiPromise } from '@polkadot/api' import type { U8aLike } from '@polkadot/util/types' - +import { authorizeTx } from '@kiltprotocol/did' import { ConfigService } from '@kiltprotocol/config' -import type { Caip2ChainId } from '@kiltprotocol/types' -import { Caip2, SDKErrors } from '@kiltprotocol/utils' - +import type { + Caip2ChainId, + KiltAddress, + SignerInterface, + MultibaseKeyPair, +} from '@kiltprotocol/types' +import { Caip2, SDKErrors, Signers } from '@kiltprotocol/utils' +import { Blockchain } from '@kiltprotocol/chain-helpers' import * as CType from '../ctype/index.js' import * as Attestation from '../attestation/index.js' import { assertMatchingConnection, getDelegationNodeIdForCredential, } from './common.js' -import type { KiltCredentialV1, KiltRevocationStatusV1 } from './types.js' +import type { IssuerOptions } from '../interfaces.js' +import type { + KiltCredentialV1, + KiltRevocationStatusV1, + VerifiableCredential, +} from './types.js' export type Interface = KiltRevocationStatusV1 export const STATUS_TYPE = 'KiltRevocationStatusV1' +interface RevokeResult { + success: boolean + error?: string[] + info: { + blockNumber?: string + blockHash?: string + transactionHash?: string + } +} + +interface BlockchainResponse { + blockNumber: string + status: { + finalized: string + } + txHash: string +} + +/** + * Revokes a Kilt credential on the blockchain, making it invalid. + * + * @param params Named parameters for the revocation process. + * @param params.issuer Interfaces for interacting with the issuer identity. + * @param params.issuer.didDocument The DID Document of the issuer revoking the credential. + * @param params.issuer.signers Array of signer interfaces for credential authorization. + * @param params.issuer.submitter The submitter can be one of: + * - A MultibaseKeyPair for signing transactions + * - A Ed25519 type keypair for blockchain interactions + * The submitter will be used to cover transaction fees and blockchain operations. + * @param params.credential The Verifiable Credential to be revoked. Must contain a valid credential ID. + * @param issuer + * @param credential + * @returns An object containing: + * - success: Boolean indicating if revocation was successful + * - error?: Array of error messages if revocation failed + * - info: Object containing blockchain transaction details: + * - blockNumber?: The block number where revocation was included + * - blockHash?: The hash of the finalized block + * - transactionHash?: The hash of the revocation transaction. + * @throws Will return error response if: + * - Credential ID is invalid or cannot be decoded + * - DID authorization fails + * - Transaction signing or submission fails. + */ +export async function revoke( + issuer: IssuerOptions, + credential: VerifiableCredential +): Promise { + try { + if (!credential.id) { + throw new Error('Credential ID is required for revocation') + } + + const rootHash = credential.id.split(':').pop() + if (!rootHash) { + throw new Error('Invalid credential ID format') + } + + const decodedroothash = base58Decode(rootHash) + const { didDocument, signers, submitter } = issuer + const api = ConfigService.get('api') + + const revokeTx = api.tx.attestation.revoke(decodedroothash, null) as any + const [Txsubmitter] = (await Signers.getSignersForKeypair({ + keypair: submitter as MultibaseKeyPair, + type: 'Ed25519', + })) as Array> + const authorizedTx = await authorizeTx( + didDocument, + revokeTx, + signers as SignerInterface[], + Txsubmitter.id + ) + + const response = (await Blockchain.signAndSubmitTx( + authorizedTx, + Txsubmitter + )) as unknown as BlockchainResponse + + const responseObj = JSON.parse(JSON.stringify(response)) + + return { + success: true, + info: { + blockNumber: responseObj.blockNumber, + blockHash: responseObj.status.finalized, + transactionHash: responseObj.txHash, + }, + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error occurred' + return { + success: false, + error: [errorMessage], + info: {}, + } + } +} + /** * Check attestation and revocation status of a credential at the latest block available. * diff --git a/packages/credentials/src/issuer.ts b/packages/credentials/src/issuer.ts index 2f8ca5f6e..c18a13999 100644 --- a/packages/credentials/src/issuer.ts +++ b/packages/credentials/src/issuer.ts @@ -5,27 +5,30 @@ * found in the LICENSE file in the root directory of this source tree. */ -import { SDKErrors, Signers } from '@kiltprotocol/utils' +import { SDKErrors } from '@kiltprotocol/utils' // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Blockchain } from '@kiltprotocol/chain-helpers' -import type { - KiltAddress, - SignerInterface, - Did, - ICType, - IClaimContents, - MultibaseKeyPair, -} from '@kiltprotocol/types' -import { authorizeTx } from '@kiltprotocol/did' -import { base58Decode } from '@polkadot/util-crypto' -import { ConfigService } from '@kiltprotocol/config' -import type { IssuerOptions, SubmitOverride } from './interfaces.js' +import type { Did, ICType, IClaimContents } from '@kiltprotocol/types' +import type { IssuerOptions } from './interfaces.js' import type { CTypeLoader } from './ctype/index.js' import type { UnsignedVc, VerifiableCredential } from './V1/types.js' -import { KiltAttestationProofV1, KiltCredentialV1 } from './V1/index.js' +import { + KiltAttestationProofV1, + KiltCredentialV1, + KiltRevocationStatusV1, +} from './V1/index.js' export type { IssuerOptions } +interface RevokeResult { + success: boolean + error?: string[] + info: { + blockNumber?: string + blockHash?: string + transactionHash?: string + } +} + /** * Creates a new credential document as a basis for issuing a credential. * This document can be shown to users as a preview or be extended with additional properties before moving on to the second step of credential issuance: @@ -144,105 +147,41 @@ export async function issue({ ) } } - -interface RevokeResult { - success: boolean - error?: string[] - info: { - blockNumber?: string - blockHash?: string - transactionHash?: string - } -} - -interface BlockchainResponse { - blockNumber: string - status: { - finalized: string - } - txHash: string -} - /** * Revokes a Kilt credential on the blockchain, making it invalid. * * @param params Named parameters for the revocation process. - * @param params.issuer Interfaces for interacting with the issuer identity. - * @param params.issuer.didDocument The DID Document of the issuer revoking the credential. - * @param params.issuer.signers Array of signer interfaces for credential authorization. - * @param params.issuer.submitter The submitter can be one of: - * - A MultibaseKeyPair for signing transactions - * - A Ed25519 type keypair for blockchain interactions - * The submitter will be used to cover transaction fees and blockchain operations. - * @param params.credential The Verifiable Credential to be revoked. Must contain a valid credential ID. - * @param issuer - * @param credential - * @returns An object containing: - * - success: Boolean indicating if revocation was successful - * - error?: Array of error messages if revocation failed - * - info: Object containing blockchain transaction details: - * - blockNumber?: The block number where revocation was included - * - blockHash?: The hash of the finalized block - * - transactionHash?: The hash of the revocation transaction. - * @throws Will return error response if: - * - Credential ID is invalid or cannot be decoded - * - DID authorization fails - * - Transaction signing or submission fails. + * @param params.credential The Verifiable Credential to be revoked. + * @param params.issuer Options for the issuer performing the revocation. + * @param params.proofOptions Optional parameters for proof configuration. + * @param params.proofOptions.proofType The type of proof to use for revocation. Currently only supports KiltAttestationProofV1. + * @returns Promise containing the revocation result. + * @throws {SDKError} When an unsupported proof type is provided. */ -export async function revoke( - issuer: IssuerOptions, +export async function revoke({ + credential, + issuer, + proofOptions = {}, +}: { credential: VerifiableCredential -): Promise { - try { - if (!credential.id) { - throw new Error('Credential ID is required for revocation') - } - - const rootHash = credential.id.split(':').pop() - if (!rootHash) { - throw new Error('Invalid credential ID format') - } - - const decodedroothash = base58Decode(rootHash) - const { didDocument, signers, submitter } = issuer - const api = ConfigService.get('api') - - console.log(didDocument) - - const revokeTx = api.tx.attestation.revoke(decodedroothash, null) as any - const [Txsubmitter] = (await Signers.getSignersForKeypair({ - keypair: submitter as MultibaseKeyPair, - type: 'Ed25519', - })) as Array> - const authorizedTx = await authorizeTx( - didDocument, - revokeTx, - signers as SignerInterface[], - Txsubmitter.id - ) - - const response = (await Blockchain.signAndSubmitTx( - authorizedTx, - Txsubmitter - )) as unknown as BlockchainResponse - - const responseObj = JSON.parse(JSON.stringify(response)) - - return { - success: true, - info: { - blockNumber: responseObj.blockNumber, - blockHash: responseObj.status.finalized, - transactionHash: responseObj.txHash, - }, - } - } catch (error: unknown) { - const errorMessage = - error instanceof Error ? error.message : 'Unknown error occurred' - return { - success: false, - error: [errorMessage], - info: {}, + issuer: IssuerOptions + proofOptions?: { + proofType?: string + } +}): Promise { + const { proofType } = proofOptions + switch (proofType) { + case undefined: + case KiltAttestationProofV1.PROOF_TYPE: { + const result = await KiltRevocationStatusV1.revoke( + issuer as IssuerOptions, + credential as VerifiableCredential + ) + return result } + default: + throw new SDKErrors.SDKError( + `Only proof type ${KiltAttestationProofV1.PROOF_TYPE} is currently supported.` + ) } }