diff --git a/demo/src/registry-entries-tx.ts b/demo/src/dedi/registry-entries-tx.ts similarity index 71% rename from demo/src/registry-entries-tx.ts rename to demo/src/dedi/registry-entries-tx.ts index 282ed731..732ee9dc 100644 --- a/demo/src/registry-entries-tx.ts +++ b/demo/src/dedi/registry-entries-tx.ts @@ -1,5 +1,5 @@ import * as Cord from '@cord.network/sdk' -import { createAccount } from './utils/createAccount' +import { createAccount } from '../utils/createAccount' import { BN @@ -115,12 +115,12 @@ async function main() { const entryDigest = await Cord.Registries.getDigestFromRawData(stringifiedEntryBlob); // Create a Registry Entry Properties. - const registryEntryDetails = await Cord.Entries.CreateEntriesProperties( + const registryEntryDetails = await Cord.Entries.createEntriesProperties( authorIdentity.address, + registry.uri, //registryUri + registry.authorizationUri, //registryAuthUri entryDigest, //digest entryBlob, //blob - registry.uri, //registryUri - registry.authorizationUri //registryAuthUri ); console.log(`\n❄️ Registry Entry Create Details `, registryEntryDetails); @@ -131,7 +131,52 @@ async function main() { authorIdentity, ) - console.log('\n✅ Registry Entry created!'); + console.log('\n✅ Registry Entry created!', registryEntry); + + // Update the Registry Entry + const updateEntryBlob = { + "name": "New Tech Solutions Ltd.", + "description": "A technology company providing software development and IT consulting services.", + "metadata": { + "category": "Technology", + "registrationDate": "15-06-2022", + "status": "Active", + "registrationNumber": "TSL12345", + "industry": "Technology", + "regulatoryAuthority": "National Business Bureau", + "documentsProvided": [ + "Incorporation Certificate", + "Tax Identification Number", + "Proof of Address", + "Board Resolution" + ], + "feePaid": "INR500", + "lastUpdated": "01-10-2024" + } + }; + + const updateStringifiedEntryBlob = JSON.stringify(updateEntryBlob); + const updateEntryDigest = await Cord.Registries.getDigestFromRawData(updateStringifiedEntryBlob); + + // Create Update Entry Properties + const registryEntryUpdateDetails = await Cord.Entries.updateEntriesProperties( + registryEntry, + authorIdentity.address, + registry.uri, + registry.authorizationUri, + updateEntryDigest, //digest + updateEntryBlob, //blob + ); + + console.log(`\n❄️ Registry Entry Update Details `, registryEntryUpdateDetails); + + // Dispatch the Property to the chain + const registryEntryUpdate = await Cord.Entries.dispatchUpdateEntryToChain( + registryEntryUpdateDetails, + authorIdentity, + ); + + console.log('\n✅ Registry Entry updated!', registryEntryUpdate); } main() diff --git a/demo/src/registry-tx.ts b/demo/src/dedi/registry-tx.ts similarity index 99% rename from demo/src/registry-tx.ts rename to demo/src/dedi/registry-tx.ts index 2d9a53f2..e144f452 100644 --- a/demo/src/registry-tx.ts +++ b/demo/src/dedi/registry-tx.ts @@ -1,5 +1,5 @@ import * as Cord from '@cord.network/sdk' -import { createAccount } from './utils/createAccount' +import { createAccount } from '../utils/createAccount' import { BN diff --git a/package.json b/package.json index b6075840..2fc19cc4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "test:watch": "yarn test --watch", "demo-statement": "tsx --no-cache demo/src/func-test.ts", "demo-network-score": "tsx --no-cache demo/src/network-score-test.ts", - "demo-asset": "tsx --no-cache demo/src/asset-tx.ts" + "demo-asset": "tsx --no-cache demo/src/asset-tx.ts", + "demo-registry": "tsx --no-cache demo/src/dedi/registry-tx.ts", + "demo-registry-entries": "tsx --no-cache demo/src/dedi/registry-entries-tx.ts" }, "husky": { "hooks": { diff --git a/packages/entries/src/Entries.chain.ts b/packages/entries/src/Entries.chain.ts index 9bbdc8f2..148d2532 100644 --- a/packages/entries/src/Entries.chain.ts +++ b/packages/entries/src/Entries.chain.ts @@ -19,10 +19,10 @@ * * The Entries module provides several functions for managing registry entries: * - * - `dispatchCreateToChain`: Creates a new registry entry in a decentralized registry. - * - `dispatchUpdateToChain`: Updates an existing registry entry with new data. - * - `dispatchRevokeToChain`: Revokes a registry entry, marking it as inactive or invalid. - * - `dispatchReinstateToChain`: Restores a revoked registry entry to an active state. + * - `dispatchCreateEntryToChain`: Creates a new registry entry in a decentralized registry. + * - `dispatchUpdateEntryToChain`: Updates an existing registry entry with new data. + * - `dispatchRevokeEntryToChain`: Revokes a registry entry, marking it as inactive or invalid. + * - `dispatchReinstateEntryToChain`: Restores a revoked registry entry to an active state. * * ## Usage * @@ -39,23 +39,47 @@ * */ import { - CordKeyringPair, -} from '@cord.network/types'; + SDKErrors, +} from '@cord.network/utils'; -import { SDKErrors } from '@cord.network/utils'; import { - IRegistryEntry, EntryUri + IRegistryEntry, + EntryUri, + CordKeyringPair, } from '@cord.network/types'; import { Chain } from '@cord.network/network'; +import { Option } from '@polkadot/types'; + import { ConfigService } from '@cord.network/config' +import type { + PalletEntriesRegistryEntryDetails, +} from '@cord.network/augment-api' + import { uriToIdentifier, + uriToEntryIdAndDigest, } from '@cord.network/identifier' +export async function isRegistryEntryStored( + registryEntryId: string +): Promise { + try { + const api = ConfigService.get('api'); + const encoded = await api.query.entries.registryEntries(registryEntryId) as Option; + + return !encoded.isNone + } catch (error) { + throw new SDKErrors.CordQueryError( + `Error querying the registry-entry: ${error}` + ) + } +} + + /** * Dispatches the creation of a new registry entry to the CORD blockchain by submitting an extrinsic. * @@ -90,29 +114,103 @@ import { * ``` */ export async function dispatchCreateEntryToChain( - registryEntryDetails: IRegistryEntry, - authorAccount: CordKeyringPair + registryEntryDetails: IRegistryEntry, + authorAccount: CordKeyringPair +): Promise { + try { + const api = ConfigService.get('api'); + + const registryEntryObj = uriToEntryIdAndDigest(registryEntryDetails.uri); + + const registryEntryId = registryEntryObj.identifier; + const authorizationId = uriToIdentifier(registryEntryDetails.authorizationUri); + + const registryEntryExists = await isRegistryEntryStored(registryEntryId); + if (registryEntryExists) { + throw new SDKErrors.CordDispatchError( + `Registry Entry already exists at URI: "${registryEntryDetails.uri}".` + ); + } + + const extrinsic = api.tx.entries.create( + registryEntryId, + authorizationId, + registryEntryDetails.digest, + registryEntryDetails.blob, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + return registryEntryDetails.uri; +} catch (error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error); + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ); + } +} + + +/** + * Dispatches an update operation for a registry entry to the blockchain. + * The function verifies the existence of the entry on-chain and submits an extrinsic + * to update it with the provided digest and blob values. + * + * It ensures that the registry entry exists before proceeding with the update and handles + * errors related to on-chain operations by throwing relevant exceptions. + * + * @param {IRegistryEntry} registryEntryDetails - An object containing the registry entry's details: + * - `uri`: The URI identifying the registry entry to be updated. + * - `digest`: A hash representing the contents of the blob associated with the entry. + * - `blob`: The optional serialized content associated with the registry entry. + * - `authorizationUri`: The URI authorizing the update. + * - `registryUri`: The URI identifying the registry to which the entry belongs. + * - `creatorUri`: The DID URI of the account that initially created the registry entry. + * + * @param {CordKeyringPair} authorAccount - The keypair of the account authorized to sign + * and submit the transaction. + * + * @throws {SDKErrors.CordDispatchError} - Thrown if: + * - The registry entry does not exist on-chain. + * - An error occurs during the transaction dispatch or validation. + * + * @returns {Promise} - A promise that resolves to the URI of the successfully updated + * registry entry. + * + */ +export async function dispatchUpdateEntryToChain( + registryEntryDetails: IRegistryEntry, + authorAccount: CordKeyringPair ): Promise { - try { - const api = ConfigService.get('api'); - - const registryEntryId = uriToIdentifier(registryEntryDetails.uri); - const authorizationId = uriToIdentifier(registryEntryDetails.authorizationUri); - - const extrinsic = api.tx.entries.create( - registryEntryId, - authorizationId, - registryEntryDetails.digest, - registryEntryDetails.blob, - ); - - await Chain.signAndSubmitTx(extrinsic, authorAccount); - return registryEntryDetails.uri; - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : JSON.stringify(error); - throw new SDKErrors.CordDispatchError( - `Error dispatching to chain: "${errorMessage}".` - ); + try { + const api = ConfigService.get('api'); + + const registryEntryObj = uriToEntryIdAndDigest(registryEntryDetails.uri); + + const registryEntryId = registryEntryObj.identifier; + const authorizationId = uriToIdentifier(registryEntryDetails.authorizationUri); + + const registryEntryExists = await isRegistryEntryStored(registryEntryId); + if (!registryEntryExists) { + throw new SDKErrors.CordDispatchError( + `Registry Entry does not exists at URI: "${registryEntryDetails.uri}".` + ); } + + const extrinsic = api.tx.entries.update( + registryEntryId, + authorizationId, + registryEntryDetails.digest, + registryEntryDetails.blob, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + return registryEntryDetails.uri; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error); + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ); + } } diff --git a/packages/entries/src/Entries.ts b/packages/entries/src/Entries.ts index c75fb758..70fae928 100644 --- a/packages/entries/src/Entries.ts +++ b/packages/entries/src/Entries.ts @@ -10,12 +10,7 @@ * The `Entries` module ensures that new entries can be created, updated, revoked, and reinstated, maintaining * a flexible, transparent, and secure record-keeping system. * - * Key functionality includes: - * - `createEntryProperties`: Constructs the necessary properties to create a new entry within an existing registry, - * including the creator’s address, digest, schema identifier, and a serialized, optionally CBOR-encoded blob - * containing the entry’s content. - * - * These functionalities enable the decentralized management of entries on the CORD blockchain, ensuring that records + * These below functionalities enable the decentralized management of entries on the CORD blockchain, ensuring that records * are securely stored, verified, and managed across different registries. * * @example @@ -49,16 +44,19 @@ import { EntryDigest, RegistryAuthorizationUri, IRegistryEntry, - ENTRY_IDENT, - ENTRY_PREFIX, blake2AsHex, } from "@cord.network/types"; -import { SDKErrors } from '@cord.network/utils'; +import { + SDKErrors, + DataUtils, + } from '@cord.network/utils'; import { - hashToUri, uriToIdentifier, + updateRegistryEntryUri, + buildRegistryEntryUri, + checkIdentifier, } from '@cord.network/identifier'; import { ConfigService } from '@cord.network/config'; @@ -109,19 +107,48 @@ export async function getUriForRegistryEntry( const scaleEncodedCreator = api .createType('AccountId', creatorAddress) .toU8a() - const digest = blake2AsHex( + const IdDigest = blake2AsHex( Uint8Array.from([ ...scaleEncodedRegistryDigest, ...scaleEncodedRegistryId, ...scaleEncodedCreator ]) ); + + // Below `entryUri` is of type `entry:cord:IdDigest:entryDigest` + const entryUri = buildRegistryEntryUri(IdDigest, entryDigest) as EntryUri; - const entryUri = hashToUri(digest, ENTRY_IDENT, ENTRY_PREFIX) as EntryUri; return entryUri; } +/** + * Verifies the integrity of the given IRegistryEntry object. + * + * @remarks + * This function ensures that the input conforms to the expected data structure + * by checking required fields, identifiers, and digest format. + * + * @param input - The IRegistryEntry object to verify. + * @throws {SDKErrors.RegistryEntryError} If any required field is missing or invalid. + */ +export function verifyRegistryEntry(input: IRegistryEntry): void { + if (!input.digest) { + throw new SDKErrors.InvalidInputError('Digest is required.'); + } + + checkIdentifier(input.registryUri); + checkIdentifier(input.authorizationUri); + checkIdentifier(input.creatorUri); + + DataUtils.verifyIsHex(input.digest, 256); + + if (input.blob !== null && typeof input.blob !== 'string') { + throw new SDKErrors.InvalidInputError('Blob must be a string or null.'); + } +} + + /** * Constructs the properties required to create a registry entry in the CORD blockchain. * @@ -171,12 +198,12 @@ export async function getUriForRegistryEntry( * - The `creatorUri` is constructed as a DID using the creator's address. * */ -export async function CreateEntriesProperties( +export async function createEntriesProperties( creatorAddress: string, + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, digest: HexString | null = null, blob: string | null = null, - registryUri: RegistryUri, - authorizationUri: RegistryAuthorizationUri ): Promise { if (!digest && !blob) { @@ -225,11 +252,126 @@ export async function CreateEntriesProperties( // Revisit if use of creatorUri as below is correct. const creatorUri = `did:cord:3${creatorAddress}` as DidUri; - return { + const registryEntryObj = { uri: entryUri, creatorUri, digest, blob, + registryUri, authorizationUri, + }; + + /* Process the entry object before dispatch */ + try { + verifyRegistryEntry(registryEntryObj); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error); + throw new SDKErrors.CordDispatchError( + `Validating Registry Entry Failed!"${errorMessage}".` + ); } + + return registryEntryObj +} + + +/** + * Updates the properties of a registry entry by validating and processing + * the provided digest or blob. If the blob is present and not serialized, + * it is serialized and encoded using CBOR. If the digest is absent, it + * is computed from the serialized blob. The function returns an updated + * registry entry object with the new URI, digest, and processed blob. + * + * @param {EntryUri} registryEntryUri - The original URI of the registry entry to update. + * @param {string} creatorAddress - The creator's address, which is used to generate a DID URI. + * @param {RegistryUri} registryUri - The URI of the registry associated with the entry. + * @param {RegistryAuthorizationUri} authorizationUri - The authorization URI associated with the registry entry. + * @param {HexString | null} [digest=null] - The optional hash of the blob. If not provided, it will be computed from the blob. + * @param {string | null} [blob=null] - The optional blob data. If provided, it will be serialized and encoded if needed. + * + * @throws {SDKErrors.InputContentsMalformedError} - Thrown if both `digest` and `blob` are `null` or if `digest` is missing after processing. + * @throws {SDKErrors.CordDispatchError} - Thrown if the registry entry object fails validation. + * + * @returns {Promise} - A promise that resolves to the updated registry entry object with the new URI, digest, and processed blob. + * + */ +export async function updateEntriesProperties( + registryEntryUri: EntryUri, + creatorAddress: string, + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, + digest: HexString | null = null, + blob: string | null = null, +): Promise { + + if (!digest && !blob) { + throw new SDKErrors.InputContentsMalformedError( + `Either 'digest' or 'blob' must be provided. Both cannot be null.` + ); + } + + /* Construct digest from serialized blob if digest is absent */ + if (!digest && blob) { + const isASerializedBlob = await isBlobSerialized(blob); + if (!isASerializedBlob) { + blob = JSON.stringify(blob); + } + + digest = await getDigestFromRawData(blob); + + /* Encode the serialized 'blob' in CBOR before dispatch to chain */ + blob = await encodeStringifiedBlobToCbor(blob); + } + + /* Process the blob to be serialized and CBOR encoded if digest is present */ + else if (digest && blob) { + const isASerializedBlob = await isBlobSerialized(blob); + if (!isASerializedBlob){ + blob = JSON.stringify(blob); + } + + /* Encode the 'blob' in CBOR before dispatch to chain */ + blob = await encodeStringifiedBlobToCbor(blob); + } + + if (!digest) { + throw new SDKErrors.InputContentsMalformedError( + `Digest cannot be empty.` + ); + } + + /* + * Update the entryUri to have newer digest as suffix + * Below `entryUri` is of type `entry:cord:IdDigest:entryDigest` + */ + const entryUri = updateRegistryEntryUri( + registryEntryUri, digest + ); + + // TODO: + // Revisit if use of creatorUri as below is correct. + const creatorUri = `did:cord:3${creatorAddress}` as DidUri; + + const registryEntryObj = { + uri: entryUri, + creatorUri, + digest, + blob, + registryUri, + authorizationUri, + }; + + /* Process the entry object before dispatch */ + try { + verifyRegistryEntry(registryEntryObj); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error); + throw new SDKErrors.CordDispatchError( + `Validating Registry Entry Failed!"${errorMessage}".` + ); + } + + return registryEntryObj } diff --git a/packages/identifier/src/Identifier.ts b/packages/identifier/src/Identifier.ts index 128fef64..ed8695bd 100644 --- a/packages/identifier/src/Identifier.ts +++ b/packages/identifier/src/Identifier.ts @@ -41,7 +41,9 @@ import type { HexString, StatementDigest, StatementUri, + EntryUri, } from '@cord.network/types' + import { base58Decode, base58Encode, @@ -73,6 +75,7 @@ import { ENTRY_IDENT, ENTRY_PREFIX, } from '@cord.network/types' + import { SDKErrors } from '@cord.network/utils' const defaults = { @@ -767,3 +770,170 @@ export function elementUriToStatementUri( return statementId } + + +/** + * Constructs a registry-entry URI from given hexadecimal string digests. + * + * @remarks + * This function generates a standardized URI for a registry entry by combining a hashed identifier digest + * and another digest. The identifier digest is first converted to a URI with a specific prefix, and + * then concatenated with the sliced second digest to form the complete registry-entry URI. + * + * @param idDigest - A hexadecimal string representing the identifier digest. Must start with '0x'. + * @param digest - Another hexadecimal string representing the registry entry's content digest. Must also start with '0x'. + * @returns A `RegistryEntryUri` representing the combined URI for the entry. + * + * @example + * ```typescript + * const idDigest = '0x1234...'; + * const digest = '0xabcd...'; + * const entryUri = buildRegistryEntryUri(idDigest, digest); + * console.log('Registry Entry URI:', entryUri); + * ``` + * + * @throws {SDKErrors.InvalidInputError} If either `idDigest` or `digest` does not start with '0x'. + * + * @description + * The function first checks if both input parameters start with '0x' as required for hexadecimal digests. + * It then uses the `hashToUri` function to convert `idDigest` to a URI with a specified identifier and prefix. + * The `digest` is then sliced to remove its '0x' prefix and concatenated with the identifier URI to form + * the final registry entry URI, which is returned as a `RegistryEntryUri` type. + */ +export function buildRegistryEntryUri( + idDigest: HexString, + digest: HexString +): EntryUri { + if (!digest.startsWith('0x') || !idDigest.startsWith('0x')) { + throw new SDKErrors.InvalidInputError('Digest must start with 0x'); + } + const prefix = hashToUri(idDigest, ENTRY_IDENT, ENTRY_PREFIX); + const suffix = digest.slice(2); + + const registryEntryUri = `${prefix}:${suffix}` as EntryUri; + return registryEntryUri; +} + + +/** + * Updates the digest component of a given registry entry URI with a new digest. + * + * @remarks + * This function modifies an existing registry entry URI by replacing its digest with a new provided digest. + * It ensures that the URI retains its original structure and prefix, while only the digest part is updated. + * + * @param registryEntryUri - The original registry entry URI to be updated. Format: 'entry:cord::'. + * @param digest - The new hexadecimal string digest to be inserted into the URI. Must start with '0x'. + * @returns The updated registry entry URI with the new digest. + * + * @example + * ```typescript + * const originalUri = 'entry:cord:1234:abcd'; + * const newDigest = '0x5678...'; + * const updatedUri = updateRegistryEntryUri(originalUri, newDigest); + * console.log('Updated Registry Entry URI:', updatedUri); + * ``` + * + * @throws {SDKErrors.InvalidIdentifierError} If the `registryEntryUri` does not follow the expected format. + * @throws {SDKErrors.InvalidInputError} If the new `digest` does not start with '0x'. + * + * @description + * The function splits the `registryEntryUri` and validates its structure. If valid, it replaces the digest with the new one. + * The updated URI is constructed with the new digest (without '0x' prefix) and returned. + */ +export function updateRegistryEntryUri( + registryEntryUri: EntryUri, + digest: HexString +): EntryUri { + const parts = registryEntryUri.split(':'); + + if (parts[0] !== 'entry' || parts[1] !== 'cord') { + throw new SDKErrors.InvalidIdentifierError('Invalid registry entry URI format'); + } + + if (!digest.startsWith('0x')) { + throw new SDKErrors.InvalidInputError('Digest must start with 0x'); + } + const suffix = digest.slice(2); + + const entryUri = `entry:cord:${parts[2]}:${suffix}` as EntryUri; + return entryUri; +} + + +/** + * Extracts the identifier and digest from a given registry entry URI. + * + * @remarks + * This function parses a registry entry URI and extracts the identifier and digest components. + * + * @param registryEntryUri - The registry entry URI to be parsed. Format: 'entry:cord::'. + * @returns An object containing the extracted identifier and digest. + * + * @example + * ```typescript + * const entryUri = 'entry:cord:1234:abcd'; + * const { identifier, digest } = uriToEntryIdAndDigest(entryUri); + * console.log('Identifier:', identifier, 'Digest:', digest); + * ``` + * + * @throws {SDKErrors.InvalidIdentifierError} If the `registryEntryUri` does not follow the expected format. + * + * @description + * The function splits the `registryEntryUri` string and validates its format. If valid, it returns the identifier + * and the digest (with '0x' prefix). + */ +export function uriToEntryIdAndDigest(registryEntryUri: EntryUri): { + identifier: string; + digest: HexString; +} { + const parts = registryEntryUri.split(':'); + + if (parts.length !== 4 || parts[0] !== 'entry' || parts[1] !== 'cord') { + throw new SDKErrors.InvalidIdentifierError('Invalid registry entry URI format'); + } + + const identifier = parts[2]; + const suffix = parts[3]; + + const digest = `0x${suffix}` as HexString; + + return { identifier, digest }; +} + + +/** + * Converts a registry entry URI to a simpler identifier URI. + * + * @remarks + * This function processes a registry entry URI and returns a URI containing only the identifier part. + * + * @param registryEntryUri - The registry entry URI to be converted. Format: 'entry:cord::'. + * @returns A simplified identifier URI: 'entry:cord:'. + * + * @example + * ```typescript + * const entryUri = 'entry:cord:1234:abcd'; + * const identifierUri = elementUriToEntryUri(entryUri); + * console.log('Identifier URI:', identifierUri); + * ``` + * + * @throws {SDKErrors.InvalidIdentifierError} If the `registryEntryUri` does not conform to the expected format. + * + * @description + * The function splits the `registryEntryUri`, validates its structure, and constructs a URI using only the identifier part. + */ +export function elementUriToEntryUri( + registryEntryUri: EntryUri +): EntryUri { + const parts = registryEntryUri.split(':'); + + if (parts.length !== 4 || parts[0] !== 'entry' || parts[1] !== 'cord') { + throw new SDKErrors.InvalidIdentifierError('Invalid registry entry URI format'); + } + + const identifier = parts[2]; + const identifierUri = `entry:cord:${identifier}` as EntryUri; + + return identifierUri; +} diff --git a/packages/types/src/Entries.ts b/packages/types/src/Entries.ts index 37d06127..23dbb170 100644 --- a/packages/types/src/Entries.ts +++ b/packages/types/src/Entries.ts @@ -1,6 +1,6 @@ import { HexString } from './Imported.js' import { - RegistryAuthorizationUri, + RegistryAuthorizationUri, RegistryUri } from './Registries.js' import type { DidUri } from './DidDocument' @@ -15,6 +15,7 @@ export interface IRegistryEntry { creatorUri: DidUri digest: HexString blob: string | null + registryUri: RegistryUri authorizationUri: RegistryAuthorizationUri } @@ -22,6 +23,7 @@ export interface IRegistryEntryDetails { uri: EntryUri digest: HexString blob: string | null + registryUri: RegistryUri authorizationUri: RegistryAuthorizationUri } @@ -29,7 +31,16 @@ export interface IRegistryEntryStatus { uri: EntryUri digest: HexString blob: string | null + registryUri: RegistryUri authorizationUri: RegistryAuthorizationUri creatorUri: DidUri revoked: boolean } + +export interface IRegistryEntryChainStorage { + uri: EntryUri + digest: HexString + revoked: boolean + creatorUri: DidUri + registryUri: RegistryUri +}