From 02265ea2c0b05e53ff9bbb84fcaf1708e7bb311b Mon Sep 17 00:00:00 2001 From: Shreevatsa N Date: Tue, 15 Oct 2024 17:50:24 +0530 Subject: [PATCH 1/6] entries: Add support for updation of registry-entries Signed-off-by: Shreevatsa N --- demo/src/dedi/registry-entries-tx.ts | 190 ++++++++++++++++++ demo/src/dedi/registry-tx.ts | 288 +++++++++++++++++++++++++++ 2 files changed, 478 insertions(+) create mode 100644 demo/src/dedi/registry-entries-tx.ts create mode 100644 demo/src/dedi/registry-tx.ts diff --git a/demo/src/dedi/registry-entries-tx.ts b/demo/src/dedi/registry-entries-tx.ts new file mode 100644 index 00000000..732ee9dc --- /dev/null +++ b/demo/src/dedi/registry-entries-tx.ts @@ -0,0 +1,190 @@ +import * as Cord from '@cord.network/sdk' +import { createAccount } from '../utils/createAccount' + +import { + BN +} from 'bn.js'; + +async function getBalance(address: string, api) { + Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) + + const { data: balance } = await api.query.system.account(address); + return balance.free.toString(); // Returns free balance as a string +} + +async function main() { + const networkAddress = process.env.NETWORK_ADDRESS + ? process.env.NETWORK_ADDRESS + : 'ws://127.0.0.1:9944' + + Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) + await Cord.connect(networkAddress) + + const api = Cord.ConfigService.get('api'); + + // Step 1: Setup Membership + // Setup transaction author account - CORD Account. + + console.log(`\n❄️ New Network Member`) + const authorityAuthorIdentity = Cord.Utils.Crypto.makeKeypairFromUri( + process.env.ANCHOR_URI ? process.env.ANCHOR_URI : '//Alice', + 'sr25519' + ) + + // Setup network member account. + const { account: authorIdentity } = await createAccount() + console.log(`🏦 Member (${authorIdentity.type}): ${authorIdentity.address}`) + + let tx = await api.tx.balances.transferAllowDeath(authorIdentity.address, new BN('1000000000000000')); + await Cord.Chain.signAndSubmitTx(tx, authorityAuthorIdentity); + + // Create a Registry. + const blob = { + "name": "Companies Registry", + "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", + "metadata": { + "category": "business", + "totalCompaniesRegistered": 15000, + "industriesCovered": [ + "Technology", + "Healthcare", + "Renewable Energy", + "Finance", + "Manufacturing" + ], + "lastUpdated": "01-10-2024", + "regulatoryAuthority": "National Business Bureau", + "registrationRequirements": { + "documentsNeeded": [ + "Incorporation Certificate", + "Tax Identification Number", + "Proof of Address", + "Board Resolution" + ], + "feeStructure": { + "smallBusiness": "INR500", + "mediumBusiness": "INR1000", + "largeBusiness": "INR5000" + } + } + } + }; + const stringified_blob = JSON.stringify(blob); + const digest = await Cord.Registries.getDigestFromRawData(stringified_blob); + + // Crreate a Registry Property. + const registryDetails = await Cord.Registries.registryCreateProperties( + authorIdentity.address, + digest, //digest + null, //schemaId + blob, //blob + ); + + console.log(`\n❄️ Registry Create Details `, registryDetails); + + // Dispatch the Registry Property to the chain. + const registry = await Cord.Registries.dispatchCreateRegistryToChain( + registryDetails, + authorIdentity, + ); + + console.log('\nβœ… Registry created!'); + + // Create a Registry Entry. + const entryBlob = { + "name": "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 stringifiedEntryBlob = JSON.stringify(entryBlob); + const entryDigest = await Cord.Registries.getDigestFromRawData(stringifiedEntryBlob); + + // Create a Registry Entry Properties. + const registryEntryDetails = await Cord.Entries.createEntriesProperties( + authorIdentity.address, + registry.uri, //registryUri + registry.authorizationUri, //registryAuthUri + entryDigest, //digest + entryBlob, //blob + ); + + console.log(`\n❄️ Registry Entry Create Details `, registryEntryDetails); + + // Dispatch the Registry Entry to the chain. + const registryEntry = await Cord.Entries.dispatchCreateEntryToChain( + registryEntryDetails, + authorIdentity, + ) + + 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() + .then(() => console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ ')) + .finally(Cord.disconnect) + +process.on('SIGINT', async () => { + console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ \n') + Cord.disconnect() + process.exit(0) +}) diff --git a/demo/src/dedi/registry-tx.ts b/demo/src/dedi/registry-tx.ts new file mode 100644 index 00000000..e144f452 --- /dev/null +++ b/demo/src/dedi/registry-tx.ts @@ -0,0 +1,288 @@ +import * as Cord from '@cord.network/sdk' +import { createAccount } from '../utils/createAccount' + +import { + BN +} from 'bn.js'; + +async function getBalance(address: string, api) { + Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) + + const { data: balance } = await api.query.system.account(address); + return balance.free.toString(); // Returns free balance as a string +} + +async function main() { + const networkAddress = process.env.NETWORK_ADDRESS + ? process.env.NETWORK_ADDRESS + : 'ws://127.0.0.1:9944' + + Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) + await Cord.connect(networkAddress) + + const api = Cord.ConfigService.get('api'); + + // Step 1: Setup Membership + // Setup transaction author account - CORD Account. + + console.log(`\n❄️ New Network Member`) + const authorityAuthorIdentity = Cord.Utils.Crypto.makeKeypairFromUri( + process.env.ANCHOR_URI ? process.env.ANCHOR_URI : '//Alice', + 'sr25519' + ) + + // Setup network member account. + const { account: authorIdentity } = await createAccount() + console.log(`🏦 Member (${authorIdentity.type}): ${authorIdentity.address}`) + + let tx = await api.tx.balances.transferAllowDeath(authorIdentity.address, new BN('1000000000000000')); + await Cord.Chain.signAndSubmitTx(tx, authorityAuthorIdentity); + + // Create a Registry. + const blob = { + "name": "Companies Registry", + "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", + "metadata": { + "category": "business", + "totalCompaniesRegistered": 15000, + "industriesCovered": [ + "Technology", + "Healthcare", + "Renewable Energy", + "Finance", + "Manufacturing" + ], + "lastUpdated": "01-10-2024", + "regulatoryAuthority": "National Business Bureau", + "registrationRequirements": { + "documentsNeeded": [ + "Incorporation Certificate", + "Tax Identification Number", + "Proof of Address", + "Board Resolution" + ], + "feeStructure": { + "smallBusiness": "INR500", + "mediumBusiness": "INR1000", + "largeBusiness": "INR5000" + } + } + } + }; + const stringified_blob = JSON.stringify(blob); + const digest = await Cord.Registries.getDigestFromRawData(stringified_blob); + + const registryDetails = await Cord.Registries.registryCreateProperties( + authorIdentity.address, + digest, //digest + null, //schemaId + blob, //blob + ); + + console.log(`\n❄️ Registry Create Details `, registryDetails); + + const registry = await Cord.Registries.dispatchCreateRegistryToChain( + registryDetails, + authorIdentity, + ); + + console.log('\nβœ… Registry created!'); + + // Update a existing Registry. + const new_blob = { + "name": "Companies Registry - A", + "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", + "metadata": { + "category": "business", + "totalCompaniesRegistered": 15000, + "industriesCovered": [ + "Technology", + "Healthcare", + "Renewable Energy", + "Finance", + "Manufacturing" + ], + "lastUpdated": "01-10-2024", + "regulatoryAuthority": "National Business Bureau", + "registrationRequirements": { + "documentsNeeded": [ + "Incorporation Certificate", + "Tax Identification Number", + "Proof of Address", + "Board Resolution" + ], + "feeStructure": { + "smallBusiness": "INR500", + "mediumBusiness": "INR1000", + "largeBusiness": "INR5000" + } + } + } + }; + const new_stringified_blob = JSON.stringify(new_blob); + const new_digest = await Cord.Registries.getDigestFromRawData(new_stringified_blob); + + const registryUpdateDetails = await Cord.Registries.registryUpdateProperties( + registry.uri, + registry.authorizationUri, + authorIdentity.address, + new_digest, //digest + new_blob, //blob + ); + + console.log(`\n❄️ Registry Update Details `, registryUpdateDetails); + + const registry_update = await Cord.Registries.dispatchUpdateRegistryToChain( + registryUpdateDetails, + authorIdentity, + ); + + console.log('\nβœ… Registry updated!'); + + // Revoke a Registry + console.log(`\n❄️ Revoking Registry `, registry.uri); + const registry_revoke = await Cord.Registries.dispatchRevokeToChain( + registry.uri, + registry.authorizationUri, + authorIdentity + ); + console.log('βœ… Registry Revoked!'); + + // Reinstate a Revoked Registry + console.log(`\n❄️ Reinstating Revoked Registry `, registry.uri); + const registry_reinstate = await Cord.Registries.dispatchReinstateToChain( + registry.uri, + registry.authorizationUri, + authorIdentity + ); + console.log('βœ… Revoked Registry Reinstated!'); + + // Archive a Registry + console.log(`\n❄️ Archiving Registry `, registry.uri); + const registry_archive = await Cord.Registries.dispatchArchiveToChain( + registry.uri, + registry.authorizationUri, + authorIdentity + ); + console.log('βœ… Registry Archived!'); + + // Restore a Archived Registry + console.log(`\n❄️ Restoring Archived Registry `, registry.uri); + const registry_restore = await Cord.Registries.dispatchRestoreToChain( + registry.uri, + registry.authorizationUri, + authorIdentity + ); + console.log('βœ… Archived Registry Restored!'); + + // Setup a account to be added as a `ASSERT` delegate. + const { account: assertIdentity } = await createAccount() + console.log(`\n🏦 Delegate Member (${assertIdentity.type}): ${assertIdentity.address}`) + + console.log(`\n❄️ Registry Assert Authorization `); + + // Add a delegate with ASSERT permission + const assertPermission: Cord.RegistryPermissionType = Cord.RegistryPermission.ASSERT; + const registryAssertAuthProperties = + await Cord.Registries.registryAuthorizationProperties( + registry.uri, + assertIdentity.address, + assertPermission, + authorIdentity.address + ) + + console.dir(registryAssertAuthProperties, { + depth: null, + colors: true, + }) + + const delegateAssertAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( + registryAssertAuthProperties, + registry.authorizationUri, + authorIdentity + ) + + console.log(`\nβœ… Registry Authorization added with ASSERT permission - ${delegateAssertAuthorizationUri} - added!`) + + // Setup a account to be added as a `DELEGATE` delegate. + const { account: delegateIdentity } = await createAccount() + console.log(`\n🏦 Delegate Member (${delegateIdentity.type}): ${delegateIdentity.address}`) + + console.log(`\n❄️ Registry Delegate Authorization `); + + // Add a delegate with DELEGATE permission + const delegatePermission: Cord.RegistryPermissionType = Cord.RegistryPermission.DELEGATE; + const registryDelegateAuthProperties = + await Cord.Registries.registryAuthorizationProperties( + registry.uri, + delegateIdentity.address, + delegatePermission, + authorIdentity.address + ) + + console.dir(registryDelegateAuthProperties, { + depth: null, + colors: true, + }) + + const delegateAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( + registryDelegateAuthProperties, + registry.authorizationUri, + authorIdentity + ) + + console.log(`\nβœ… Registry Authorization added with DELEGATE permission - ${delegateAuthorizationUri} - added!`) + + // Setup a account to be added as a `DELEGATE` delegate. + const { account: adminIdentity } = await createAccount() + console.log(`\n🏦 Delegate Member (${adminIdentity.type}): ${adminIdentity.address}`) + + console.log(`\n❄️ Registry Admin Authorization `); + + // Add a delegate with DELEGATE permission + const adminPermission: Cord.RegistryPermissionType = Cord.RegistryPermission.ADMIN; + const registryAdminAuthProperties = + await Cord.Registries.registryAuthorizationProperties( + registry.uri, + adminIdentity.address, + adminPermission, + authorIdentity.address + ) + + console.dir(registryAdminAuthProperties, { + depth: null, + colors: true, + }) + + const delegateAdminAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( + registryAdminAuthProperties, + registry.authorizationUri, + authorIdentity + ) + + console.log(`\nβœ… Registry Authorization added with ADMIN permission - ${delegateAdminAuthorizationUri} - added!`) + + console.log(`\n❄️ Remove Registry Assert Authorization `); + + // Remove a delegate with ASSERT permission + const removeAuthObj = await Cord.Registries.dispatchRemoveDelegateToChain( + registry.uri, + delegateAssertAuthorizationUri, + registry.authorizationUri, + authorIdentity + ) + + console.log(`\nβœ… Registry ASSERT Authorization removed - ${delegateAssertAuthorizationUri} - removed!`) + + console.log("Balance of Registry Creator after all transactions", await getBalance(authorIdentity.address, api)); +} + +main() + .then(() => console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ ')) + .finally(Cord.disconnect) + +process.on('SIGINT', async () => { + console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ \n') + Cord.disconnect() + process.exit(0) +}) From 07c4dd1fc33a246325c046e8d48253e1da41bb44 Mon Sep 17 00:00:00 2001 From: Shreevatsa N Date: Tue, 15 Oct 2024 17:51:00 +0530 Subject: [PATCH 2/6] Entries chain updates Signed-off-by: Shreevatsa N --- packages/entries/src/Entries.chain.ts | 216 ++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 packages/entries/src/Entries.chain.ts diff --git a/packages/entries/src/Entries.chain.ts b/packages/entries/src/Entries.chain.ts new file mode 100644 index 00000000..148d2532 --- /dev/null +++ b/packages/entries/src/Entries.chain.ts @@ -0,0 +1,216 @@ +/** + * @packageDocumentation + * @module Entries/chain + * + * The Entries module, a crucial part of the `DeDir (Decentralized Directory)`, provides a framework for + * managing decentralized entries or records within registries on the CORD blockchain. It enables + * the creation, updating, revocation, and reinstatement of entries in a transparent and trustless manner, + * ensuring that registries are managed in a decentralized environment. The Registries module manages + * governance and delegation for these registries. + * + * ## Overview + * + * The Entries module allows for the creation and modification of individual registry entries, each + * representing a unique record within a registry. These entries can be updated, revoked, or reinstated + * through a permissioned system. The decentralized nature of this module ensures trust, transparency, + * and immutability for registry entries on the CORD blockchain. + * + * ## Interface + * + * The Entries module provides several functions for managing registry entries: + * + * - `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 + * + * The Entries module integrates with the Registries module to offer a decentralized directory + * management system. It can be used in various applications requiring transparent and decentralized + * record management, such as credential registries, asset tracking, or any system needing immutable + * and auditable records. + * + * ## Examples + * + * - Create an entry for a verifiable credential in a decentralized identity registry. + * - Revoke an entry that is no longer valid or relevant. + * - Reinstate an entry after resolving governance issues or discrepancies. + * + */ +import { + SDKErrors, +} from '@cord.network/utils'; + + +import { + 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. + * + * This method constructs and submits an `entries.create` extrinsic to the CORD blockchain, allowing + * for the creation of a new registry entry. It takes the details of the entry, such as the registry entry URI, + * authorization URI, digest, and blob, and signs the transaction using the provided author account. + * + * @param {IRegistryEntry} registryEntryDetails - The details of the registry entry to be created, including the URI, authorization URI, digest, and blob. + * @param {CordKeyringPair} authorAccount - The account (keyring pair) that will be used to sign and submit the extrinsic to the blockchain. + * + * @returns {Promise} - A promise that resolves to the URI of the created registry entry if the transaction is successful. + * + * @throws {SDKErrors.CordDispatchError} - Throws an error if the transaction fails or encounters an issue during submission. + * + * @example + * ```typescript + * const registryEntryDetails = { + * uri: 'entryUri123', + * authorizationUri: 'authUri456', + * digest: '0x123...', + * blob: '{"key": "value"}' + * }; + * + * const authorAccount = await CordKeyring.createFromUri('//Alice'); + * + * try { + * const entryUri = await dispatchCreateEntryToChain(registryEntryDetails, authorAccount); + * console.log('Registry Entry created with URI:', entryUri); + * } catch (error) { + * console.error('Error creating registry entry:', error); + * } + * ``` + */ +export async function dispatchCreateEntryToChain( + 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 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}".` + ); + } +} From 579e780fcc9f8eab577600c0def7ca382d453af4 Mon Sep 17 00:00:00 2001 From: Shreevatsa N Date: Tue, 15 Oct 2024 17:51:18 +0530 Subject: [PATCH 3/6] Entries Properties updates Signed-off-by: Shreevatsa N --- packages/entries/src/Entries.ts | 376 ++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 packages/entries/src/Entries.ts diff --git a/packages/entries/src/Entries.ts b/packages/entries/src/Entries.ts new file mode 100644 index 00000000..e5b07f26 --- /dev/null +++ b/packages/entries/src/Entries.ts @@ -0,0 +1,376 @@ +/** + * @packageDocumentation + * @module Entries + * @preferred + * + * The `Entries` module is part of the CORD SDK, providing essential functionality for creating and managing + * registry entries within the CORD blockchain. Entries represent records or claims that are registered within + * a registry and are critical for organizing decentralized data in a structured way. + * + * The `Entries` module ensures that new entries can be created, updated, revoked, and reinstated, maintaining + * a flexible, transparent, and secure record-keeping system. + * + * 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 + * ```typescript + * // Example: Creating properties for a new entry + * const entryProperties = await createEntryProperties( + * '5F3s...', // creatorAddress + * '0x23...', // digest + * 'schemaId123', // schemaId + * '{"key":"value"}' // blob + * ); + * console.log('Entry Properties:', entryProperties); + * ``` + * + */ + +import { + encodeStringifiedBlobToCbor, + getDigestFromRawData, + isBlobSerialized +} from "@cord.network/registries"; + +import { + EntryUri, + AccountId, + H256, + RegistryUri, + Bytes, + DidUri, + HexString, + EntryDigest, + RegistryAuthorizationUri, + IRegistryEntry, + blake2AsHex, +} from "@cord.network/types"; + +import { + SDKErrors, + DataUtils, + } from '@cord.network/utils'; + +import { + uriToIdentifier, + updateRegistryEntryUri, + buildRegistryEntryUri, + checkIdentifier, +} from '@cord.network/identifier'; + +import { ConfigService } from '@cord.network/config'; + +/** + * Generates a URI for a registry entry based on its digest, registry URI, and creator's address. + * + * This function computes the unique URI for a registry entry by hashing the combination of the + * entry digest, registry URI identifier, and creator's address. It uses the BLAKE2 hashing algorithm + * to ensure a unique and secure identifier for the entry. The resulting hash is then formatted into + * a URI using a predefined entry identifier and prefix. + * + * @param {EntryDigest} entryDigest - The digest representing the data of the registry entry. + * @param {RegistryUri} registryUri - The URI of the registry that the entry belongs to. + * @param {string} creatorAddress - The address (in SS58 format) of the account that created the registry entry. + * + * @returns {Promise} - A promise that resolves to the computed `EntryUri` for the registry entry. + * + * @example + * ```typescript + * const entryDigest = '0x123...'; // Entry digest (H256 hash) + * const registryUri = 'registryUri123'; // Registry URI + * const creatorAddress = '5F3s...'; // Creator's SS58 address + * + * const entryUri = await getUriForRegistryEntry(entryDigest, registryUri, creatorAddress); + * console.log('Generated Entry URI:', entryUri); + * ``` + * + * @remarks + * This function makes use of the BLAKE2 hashing algorithm to combine the entry's digest, registry ID, + * and creator's address into a unique URI for the entry. The resulting hash is then converted to a URI + * using the `hashToUri` function. + * + */ +export async function getUriForRegistryEntry( + entryDigest: EntryDigest, + registryUri: RegistryUri, + creatorAddress: string +): Promise { + const api = ConfigService.get('api') + const scaleEncodedRegistryDigest = api + .createType('H256', entryDigest) + .toU8a() + const scaleEncodedRegistryId = api + .createType('Bytes', uriToIdentifier(registryUri)) + .toU8a() + const scaleEncodedCreator = api + .createType('AccountId', creatorAddress) + .toU8a() + const IdDigest = blake2AsHex( + Uint8Array.from([ + ...scaleEncodedRegistryDigest, + ...scaleEncodedRegistryId, + ...scaleEncodedCreator + ]) + ); + + // Below `entryUri` is of type `entry:cord:IdDigest:entryDigest` + const entryUri = buildRegistryEntryUri(IdDigest, entryDigest) 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. + * + * This function prepares the necessary data for creating a new registry entry, including + * the creator's address, the entry's digest, and an optional serialized and CBOR-encoded blob. + * It validates the input, ensuring either a digest or a blob is provided, processes the blob + * if necessary, and computes a unique URI for the registry entry. The function returns an + * object containing all the properties needed for dispatching the entry to the blockchain. + * + * @param {string} creatorAddress - The SS58 address of the account that will create the registry entry. + * @param {HexString | null} digest - A precomputed digest (hash) of the registry entry, if available. + * @param {string | null} blob - The blob (serialized data) to be associated with the registry entry, if available. + * @param {RegistryUri} registryUri - The URI of the registry to which the entry belongs. + * @param {RegistryAuthorizationUri} authorizationUri - The URI for the authorization properties within the registry. + * + * @returns {Promise} - A promise that resolves to an `IRegistryEntry` object containing the properties of the new registry entry. + * + * @throws {SDKErrors.InputContentsMalformedError} - If neither `digest` nor `blob` are provided, or if the digest is invalid. + * + * @example + * ```typescript + * // Example: Creating properties for a registry entry with a blob + * const entryProperties = await CreateEntriesProperties( + * '5F3s...', // Creator's SS58 address + * null, // Digest is null, will be generated from blob + * '{"key":"value"}',// Blob data + * 'registryUri123', // Registry URI + * 'authUri456' // Authorization URI + * ); + * console.log('Registry Entry Properties:', entryProperties); + * + * // Example: Creating properties with a precomputed digest + * const entryPropertiesWithDigest = await CreateEntriesProperties( + * '5F3s...', // Creator's SS58 address + * '0x123...', // Precomputed digest + * '{"key":"value"}', // Optional blob + * 'registryUri123', // Registry URI + * 'authUri456' // Authorization URI + * ); + * console.log('Registry Entry Properties with Digest:', entryPropertiesWithDigest); + * ``` + * + * @remarks + * - If both a `digest` and `blob` are provided, the blob will be serialized (if necessary) and encoded in CBOR format. + * - If only a `blob` is provided, the digest is computed from the raw blob data. + * - The `entryUri` is computed by hashing the registry URI, digest, and creator's address using the `getUriForRegistryEntry` function. + * - The `creatorUri` is constructed as a DID using the creator's address. + * + */ +export async function createEntriesProperties( + 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.` + ); + } + + const entryUri = await getUriForRegistryEntry( + digest as HexString, + registryUri, + creatorAddress + ) + + // 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 +} + + +/** + * 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 +} From 0a8456afd67e53478f31103a0469d9105fa48cdc Mon Sep 17 00:00:00 2001 From: Shreevatsa N Date: Tue, 15 Oct 2024 17:52:15 +0530 Subject: [PATCH 4/6] Packages updates of identifier, registries & package.json Signed-off-by: Shreevatsa N --- package.json | 4 +- packages/identifier/src/Identifier.ts | 170 +++++ packages/registries/src/Registries.chain.ts | 781 ++++++++++++++++++++ packages/types/src/Entries.ts | 46 ++ 4 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 packages/registries/src/Registries.chain.ts create mode 100644 packages/types/src/Entries.ts diff --git a/package.json b/package.json index 782ca953..242a2475 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/identifier/src/Identifier.ts b/packages/identifier/src/Identifier.ts index 6b3a0c60..2494b255 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, @@ -67,6 +69,7 @@ import { u8aToU8a, stringToU8a, } from '@cord.network/types' + import { SDKErrors } from '@cord.network/utils' const defaults = { @@ -752,3 +755,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/registries/src/Registries.chain.ts b/packages/registries/src/Registries.chain.ts new file mode 100644 index 00000000..b557f6c7 --- /dev/null +++ b/packages/registries/src/Registries.chain.ts @@ -0,0 +1,781 @@ + +/** + * @packageDocumentation + * @module Registries/chain + * + * The Registries module provides a framework for creating and managing + * isolated registries within the CORD blockchain, offering fine-grained + * control through a permission system. It allows for the creation, + * status modification, and delegate management within these registries. + * + * ## Overview + * + * The Registries module enables the creation of distinct registries on the + * CORD blockchain, each with its own governance rules. These registries can + * be used to manage various ecosystems or communities within the larger + * blockchain network. Each registry is identified by a unique identifier + * and can be governed by appointed delegates. + * + * ## Interface + * + * The module provides various functions for managing registries: + * + * - `create`: Initializes a new registry with a unique identifier. + * - `update`: Updates an existing registry with new information. + * - `revoke`: Marks a registry as revoked, effectively deactivating it. + * - `reinstate`: Reactivates a previously revoked registry. + * - `archive`: Moves a registry to an archived state. + * - `restore`: Restores a previously archived registry to active status. + * - `addDelegate`: Adds a delegate to the registry with specific permissions. + * - `addAdminDelegate`: Adds an administrative delegate to manage the registry. + * - `addAuditDelegate`: Adds an audit delegate with auditing permissions. + * - `removeDelegate`: Removes a delegate, revoking their permissions. + * + * ## Permissions + * + * This module implements a granular permission system to manage actions + * that can be performed by delegates within a registry. Delegates can be + * assigned roles such as admin or regular delegate, each with defined permissions. + * + * ## Data Privacy + * + * The Registries module prioritizes data privacy, avoiding the storage of personal + * or sensitive data directly on-chain. Instead, it manages references to off-chain + * data, ensuring compliance with privacy regulations. Users and developers are responsible + * for managing off-chain data according to applicable laws and standards. + * + * ## Usage + * + * The Registries module can be leveraged by other modules (e.g., the Entries module) + * to create compartmentalized, governed sections within the blockchain. This is useful + * for applications requiring distinct governance models or privacy settings. + * + * ## Governance Integration + * + * The module integrates with on-chain governance tools, enabling registry + * administrators and delegates to propose changes, vote on initiatives, and manage + * registries in line with the collective decisions of its members. + * + * ## Examples + * + * - Create a registry for a community-driven project. + * - Archive and restore a registry for future use. + * - Revoke and reinstate registries based on inactivity or violations. + * - Add delegates to a registry to ensure compliance with governance standards. + */ + +import { + CordKeyringPair, +} from '@cord.network/types' + +import { Option } from '@polkadot/types'; + +import { Chain } from '@cord.network/network' + +import { SDKErrors } from '@cord.network/utils' + +import { ConfigService } from '@cord.network/config' + +import { + IRegistryCreate, IRegistryUpdate, + RegistryAuthorizationUri, + RegistryUri, RegistryPermissionType, + RegistryPermission, IRegistryAuthorization, +} from '@cord.network/types'; + +import { + uriToIdentifier, +} from '@cord.network/identifier' + +import type { + PalletRegistriesRegistryAuthorization, +} from '@cord.network/augment-api' + + +/** + * Checks whether a registry is stored in the CORD blockchain. + * + * This function queries the chain for the existence of a registry using the provided + * registry URI. It returns `true` if the registry exists; otherwise, it returns `false`. + * + * @param registryUri - The URI of the registry to check for existence. + * @returns A promise that resolves to a boolean indicating whether the registry exists. + * @throws {SDKErrors.CordQueryError} If an error occurs while querying the chain space. + * + * @example + * // Example: Checking if a registry exists + * const registryExists = await isRegistryStored('space:cord:example_registry_uri'); + * console.log('Registry exists:', registryExists); + */ +export async function isRegistryStored( + registryUri: RegistryUri +): Promise { + try { + const api = ConfigService.get('api'); + const identifier = uriToIdentifier(registryUri); + const encoded = await api.query.registries.registryInfo(identifier); + + return !encoded.isNone + } catch (error) { + throw new SDKErrors.CordQueryError( + `Error querying the registry: ${error}` + ) + } +} + + +/** + * Checks whether a registry authorization is stored in the CORD blockchain. + * + * This function queries the chain for the existence of a registry authorization + * using the provided authorization URI. It returns `true` if the authorization exists; + * otherwise, it returns `false`. + * + * @param authorizationUri - The URI of the registry authorization to check for existence. + * @returns A promise that resolves to a boolean indicating whether the registry authorization exists. + * @throws {SDKErrors.CordQueryError} If an error occurs while querying the chain space. + * + * @example + * // Example: Checking if a registry authorization exists + * const authorizationExists = await isRegistryAuthorizationStored('auth:cord:example_authorization_uri'); + * console.log('Authorization exists:', authorizationExists); + * + */ +export async function isRegistryAuthorizationStored( + authorizationUri: RegistryAuthorizationUri +): Promise { + try { + const api = ConfigService.get('api') + const identifier = uriToIdentifier(authorizationUri) + const encoded = await api.query.registries.authorizations(identifier) as Option; + + return !encoded.isNone + } catch (error) { + throw new SDKErrors.CordQueryError( + `Error querying authorization existence: ${error}` + ) + } +} + + +/** + * Dispatches a request to create a new registry on the CORD blockchain. + * + * This function checks if a registry already exists at the specified URI. If it does, + * an error is thrown. If the registry does not exist, it creates a new registry + * using the provided details and submits the transaction to the chain. + * + * @param registryDetails - An object containing the details required to create the registry, including: + * - `uri`: The unique identifier for the registry. + * - `authorizationUri`: The URI for the associated authorization. + * - `digest`: A hash representing the registry's content. + * - `schemaId`: The identifier for the schema used. + * - `blob`: Additional data related to the registry. + * @param authorAccount - The account that will authorize the creation of the registry. + * @returns A promise that resolves to an object containing the created registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry already exists or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Creating a new registry + * const newRegistry = await dispatchCreateRegistryToChain({ + * uri: 'registry:cord:example_registry_uri', + * authorizationUri: 'auth:cord:example_authorization_uri', + * digest: '0xabc123...', + * schemaId: 'schema:cord:example_schema_id', + * blob: 'Registry data blob' + * }, authorAccount); + * console.log('Created Registry URI:', newRegistry.uri); + * + */ +export async function dispatchCreateRegistryToChain( + registryDetails: IRegistryCreate, + authorAccount: CordKeyringPair +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryDetails.uri, + authorizationUri: registryDetails.authorizationUri + } + + const registryExists = await isRegistryStored(registryDetails.uri); + + if (registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry already exists at URI: "${registryDetails.uri}".` + ); + } + + try { + const api = ConfigService.get('api'); + const registryId = uriToIdentifier(registryDetails.uri); + + const extrinsic = api.tx.registries.create( + registryId, + registryDetails.digest, + registryDetails.schemaId, + registryDetails.blob + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error); + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ); + } +} + + +/** + * Dispatches a request to update an existing registry on the CORD blockchain. + * + * This function checks if the specified registry exists. If it does not exist, + * an error is thrown. If the registry is found, it updates the registry with + * the new details provided and submits the transaction to the chain. + * + * @param registryDetails - An object containing the details required to update the registry, including: + * - `uri`: The unique identifier for the registry to be updated. + * - `authorizationUri`: The URI for the associated authorization. + * - `digest`: A hash representing the updated content of the registry. + * - `blob`: Additional data related to the registry update. + * @param authorAccount - The account that will authorize the update of the registry. + * @returns A promise that resolves to an object containing the updated registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry does not exist or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Updating an existing registry + * const updatedRegistry = await dispatchUpdateRegistryToChain({ + * uri: 'registry:cord:example_registry_uri', + * authorizationUri: 'auth:cord:example_authorization_uri', + * digest: '0xdef456...', + * blob: 'Updated registry data blob' + * }, authorAccount); + * console.log('Updated Registry URI:', updatedRegistry.uri); + * + */ +export async function dispatchUpdateRegistryToChain( + registryDetails: IRegistryUpdate, + authorAccount: CordKeyringPair, +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryDetails.uri, + authorizationUri: registryDetails.authorizationUri + } + + const registryExists = await isRegistryStored(registryDetails.uri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryDetails.uri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryDetails.uri); + const authorizationId = uriToIdentifier(registryDetails.authorizationUri); + + const extrinsic = api.tx.registries.update( + registryId, + registryDetails.digest, + registryDetails.blob, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } catch(error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error) + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ) + } +} + + +/** + * Dispatches a request to revoke authorization for a specified registry on the CORD blockchain. + * + * This function checks if the specified registry exists. If it does not exist, + * an error is thrown. If the registry is found, it revokes the specified authorization + * and submits the transaction to the chain. + * + * @param registryUri - The URI of the registry for which the authorization is to be revoked. + * @param authorizationUri - The URI of the authorization to be revoked. + * @param authorAccount - The account that will authorize the revocation of the authorization. + * @returns A promise that resolves to an object containing the revoked registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry does not exist or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Revoking authorization for a registry + * const revokedAuthorization = await dispatchRevokeToChain( + * 'registry:cord:example_registry_uri', + * 'auth:cord:example_authorization_uri', + * authorAccount + * ); + * console.log('Revoked Registry URI:', revokedAuthorization.uri); + * + */ +export async function dispatchRevokeToChain( + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryUri, + authorizationUri: authorizationUri + } + + const registryExists = await isRegistryStored(registryUri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryUri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryUri); + const authorizationId = uriToIdentifier(authorizationUri); + + const extrinsic = api.tx.registries.revoke( + registryId, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } catch(error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error) + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ) + } +} + + +/** + * Dispatches a request to reinstate authorization for a specified registry on the CORD blockchain. + * + * This function checks if the specified registry exists. If it does not exist, + * an error is thrown. If the registry is found, it reinstates the specified authorization + * and submits the transaction to the chain. + * + * @param registryUri - The URI of the registry for which the authorization is to be reinstated. + * @param authorizationUri - The URI of the authorization to be reinstated. + * @param authorAccount - The account that will authorize the reinstatement of the authorization. + * @returns A promise that resolves to an object containing the reinstated registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry does not exist or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Reinstate authorization for a registry + * const reinstatedAuthorization = await dispatchReinstateToChain( + * 'registry:cord:example_registry_uri', + * 'auth:cord:example_authorization_uri', + * authorAccount + * ); + * console.log('Reinstated Registry URI:', reinstatedAuthorization.uri); + * + */ +export async function dispatchReinstateToChain( + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryUri, + authorizationUri: authorizationUri + } + + const registryExists = await isRegistryStored(registryUri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryUri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryUri); + const authorizationId = uriToIdentifier(authorizationUri); + + const extrinsic = api.tx.registries.reinstate( + registryId, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } catch(error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error) + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ) + } +} + + +/** + * Dispatches a request to archive a specified registry on the CORD blockchain. + * + * This function checks if the specified registry exists. If it does not exist, + * an error is thrown. If the registry is found, it archives the specified registry + * and submits the transaction to the chain. + * + * @param registryUri - The URI of the registry to be archived. + * @param authorizationUri - The URI of the authorization associated with the registry. + * @param authorAccount - The account that will authorize the archiving of the registry. + * @returns A promise that resolves to an object containing the archived registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry does not exist or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Archive a registry + * const archivedRegistry = await dispatchArchiveToChain( + * 'registry:cord:example_registry_uri', + * 'auth:cord:example_authorization_uri', + * authorAccount + * ); + * console.log('Archived Registry URI:', archivedRegistry.uri); + * + */ +export async function dispatchArchiveToChain( + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryUri, + authorizationUri: authorizationUri + } + + const registryExists = await isRegistryStored(registryUri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryUri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryUri); + const authorizationId = uriToIdentifier(authorizationUri); + + const extrinsic = api.tx.registries.archive( + registryId, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } catch(error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error) + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ) + } +} + + +/** + * Dispatches a request to restore a already archived registry on the CORD blockchain. + * + * This function checks if the specified registry exists. If it does not exist, + * an error is thrown. If the registry is found, it restores the specified registry + * and submits the transaction to the chain. + * + * @param registryUri - The URI of the registry to be restored. + * @param authorizationUri - The URI of the authorization associated with the registry. + * @param authorAccount - The account that will authorize the restoration of the registry. + * @returns A promise that resolves to an object containing the restored registry's URI and its authorization URI. + * @throws {SDKErrors.CordDispatchError} If the registry does not exist or if an error occurs while dispatching to the chain. + * + * @example + * // Example: Restore a registry + * const restoredRegistry = await dispatchRestoreToChain( + * 'registry:cord:example_registry_uri', + * 'auth:cord:example_authorization_uri', + * authorAccount + * ); + * console.log('Restored Registry URI:', restoredRegistry.uri); + * + */ +export async function dispatchRestoreToChain( + registryUri: RegistryUri, + authorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise<{ uri: RegistryUri, authorizationUri: RegistryAuthorizationUri }> { + const registryObj = { + uri: registryUri, + authorizationUri: authorizationUri + } + + const registryExists = await isRegistryStored(registryUri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryUri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryUri); + const authorizationId = uriToIdentifier(authorizationUri); + + const extrinsic = api.tx.registries.restore( + registryId, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } catch(error) { + const errorMessage = + error instanceof Error ? error.message : JSON.stringify(error) + throw new SDKErrors.CordDispatchError( + `Error dispatching to chain: "${errorMessage}".` + ) + } +} + + +/** + * Dispatches a transaction to add a delegate authorization for a specified registry. + * + * This function creates an extrinsic based on the provided permission type, which determines + * the kind of authorization to be granted to the specified delegate for the given registry. + * It throws an error if an invalid permission is provided. + * + * @param permission - The type of permission to grant to the delegate. Must be one of the + * defined `RegistryPermission` values (e.g., ASSERT, DELEGATE, ADMIN). + * @param registryId - The identifier of the registry to which the delegate is being added. + * @param delegateId - The identifier of the delegate to be authorized. + * @param authorizationId - The identifier of the authorization associated with the delegate. + * @returns An extrinsic that can be signed and submitted to the chain. + * @throws {SDKErrors.InvalidPermissionError} If the provided permission is not valid. + * + * @example + * // Example: Dispatch a transaction to add a delegate authorization + * const extrinsic = dispatchDelegateAuthorizationTx( + * RegistryPermission.ASSERT, + * 'registryId123', + * 'delegateId456', + * 'authorizationId789' + * ); + * console.log('Extrinsic to be dispatched:', extrinsic); + * + */ +function dispatchDelegateAuthorizationTx( + permission: RegistryPermissionType, + registryId: string, + delegateId: string, + authorizationId: string +) { + const api = ConfigService.get('api') + + switch (permission) { + case RegistryPermission.ASSERT: + return api.tx.registries.addDelegate(registryId, delegateId, authorizationId) + case RegistryPermission.DELEGATE: + return api.tx.registries.addDelegator(registryId, delegateId, authorizationId) + case RegistryPermission.ADMIN: + return api.tx.registries.addAdminDelegate(registryId, delegateId, authorizationId) + default: + throw new SDKErrors.InvalidPermissionError( + `Permission not valid:"${permission}".` + ) + } +} + + +/** + * Dispatches a transaction to authorize a delegate for a specified registry. + * + * This function checks the existence of the registry and the authorization for the delegator, + * then constructs an extrinsic to add the delegate authorization with the given permission. + * It submits the transaction to the chain and throws an error if any step fails. + * + * @param request - The authorization request object, containing the registry URI, delegate URI, and permission. + * @param delegatorAuthorizationUri - The authorization URI of the delegator authorizing the action. + * @param authorAccount - The account of the author who signs and submits the transaction. + * @returns The `RegistryAuthorizationUri` after successfully dispatching the authorization. + * @throws {SDKErrors.CordDispatchError} If the registry or authorization does not exist, or if there's an error during dispatch. + * + * @example + * // Example: Dispatch a delegate authorization to the chain + * const authorizationUri = await dispatchDelegateAuthorization( + * { + * uri: 'registryUri123', + * delegateUri: 'did:cord:3delegate123', + * permission: RegistryPermission.ADMIN + * }, + * 'delegatorAuthorizationUri456', + * authorAccount + * ); + * console.log('Authorization dispatched with URI:', authorizationUri); + * + */ +export async function dispatchDelegateAuthorization( + request: IRegistryAuthorization, + delegatorAuthorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise { + try { + + const registryExists = await isRegistryStored(request.uri); + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${request.uri}".` + ); + } + + const authorizationExists = await isRegistryAuthorizationStored(delegatorAuthorizationUri); + if (!authorizationExists) { + throw new SDKErrors.CordDispatchError( + `Registry Authorization URI does not exist: "${delegatorAuthorizationUri}".` + ); + } + + const registryId = uriToIdentifier(request.uri); + const delegateId = request.delegateUri.replace("did:cord:3", ""); + const delegatorAuthorizationId = uriToIdentifier(delegatorAuthorizationUri); + + const extrinsic = dispatchDelegateAuthorizationTx( + request.permission, + registryId, + delegateId, + delegatorAuthorizationId, + ) + + await Chain.signAndSubmitTx(extrinsic, authorAccount) + + return request.authorizationUri + } catch (error) { + throw new SDKErrors.CordDispatchError( + `Error dispatching delegate authorization: ${JSON.stringify(error)}` + ) + } +} + + +/** + * Removes a delegate from a registry on the chain. + * + * This method is used to remove a delegate's authorization from a given registry. It checks whether the registry + * and the provided authorization exist on-chain, constructs the required parameters, and dispatches the extrinsic + * to the blockchain for execution. + * + * @async + * @function + * @param {RegistryUri} registryUri - The URI of the registry from which the delegate will be removed. + * @param {RegistryAuthorizationUri} removeAuthorizationUri - The URI of the authorization to be removed (i.e., the delegate's authorization). + * @param {RegistryAuthorizationUri} authorizationUri - The URI of the authorization of the account performing the removal (the caller's authorization). + * @param {CordKeyringPair} authorAccount - The account key pair of the entity removing the delegate, used for signing the transaction. + * + * @returns {Promise<{ uri: RegistryUri, removeAuthorizationUri: RegistryAuthorizationUri, authorizationUri: RegistryAuthorizationUri }>} + * An object containing the URIs related to the registry and authorizations. + * - `uri`: The URI of the registry. + * - `removeAuthorizationUri`: The authorization URI of the delegate being removed. + * - `authorizationUri`: The authorization URI of the signer performing the removal. + * + * @throws {SDKErrors.CordDispatchError} + * - If the registry URI does not exist on-chain. + * - If the authorization URI of the signer does not exist on-chain. + * - If an error occurs while dispatching the transaction to the chain. + * + * @example + * ```typescript + * const registryUri = 'did:cord:registry:3abc...'; + * const removeAuthorizationUri = 'did:cord:auth:3xyz...'; + * const authorizationUri = 'did:cord:auth:3signer...'; + * const authorAccount = keyring.addFromUri('//Alice'); + * + * dispatchRemoveDelegateToChain(registryUri, removeAuthorizationUri, authorizationUri, authorAccount) + * .then(result => { + * console.log('Delegate removed:', result); + * }) + * .catch(error => { + * console.error('Error removing delegate:', error); + * }); + * ``` + * + * @description + * The function first verifies the existence of the registry and the signer’s authorization on the blockchain. + * It then encodes the provided URIs into identifiers and submits a signed transaction to remove the delegate + * from the registry. If the removal is successful, it returns an object with the registry URI and relevant authorization URIs. + * + */ +export async function dispatchRemoveDelegateToChain( + registryUri: RegistryUri, + removeAuthorizationUri: RegistryAuthorizationUri, + authorizationUri: RegistryAuthorizationUri, + authorAccount: CordKeyringPair, +): Promise<{ + uri: RegistryUri, + removeAuthorizationUri: RegistryAuthorizationUri, + authorizationUri: RegistryAuthorizationUri +}> { + const registryObj = { + uri: registryUri, + removeAuthorizationUri: removeAuthorizationUri, + authorizationUri: authorizationUri, + } + + const registryExists = await isRegistryStored(registryUri); + + if (!registryExists) { + throw new SDKErrors.CordDispatchError( + `Registry URI does not exist: "${registryUri}".` + ); + } + + const authorizationExists = await isRegistryAuthorizationStored(authorizationUri); + if (!authorizationExists) { + throw new SDKErrors.CordDispatchError( + `Registry remover Authorization URI does not exist: "${authorizationUri}".` + ); + } + + try { + const api = ConfigService.get('api') + + const registryId = uriToIdentifier(registryUri); + const removeAuthorizationId = uriToIdentifier(removeAuthorizationUri); + const authorizationId = uriToIdentifier(authorizationUri); + + const extrinsic = api.tx.registries.removeDelegate( + registryId, + removeAuthorizationId, + authorizationId, + ); + + await Chain.signAndSubmitTx(extrinsic, authorAccount); + + return registryObj + } 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/types/src/Entries.ts b/packages/types/src/Entries.ts new file mode 100644 index 00000000..99f59b5b --- /dev/null +++ b/packages/types/src/Entries.ts @@ -0,0 +1,46 @@ +import { HexString } from './Imported.js' +import { + RegistryAuthorizationUri, RegistryUri +} from './Registries.js' +import type { DidUri } from './DidDocument' + +export const ENTRY_IDENT = 9944; +export const ENTRY_PREFIX = 'entry:cord:'; +export type EntryUri = `${typeof ENTRY_PREFIX}${string}`; +export type EntryId = string; +export type EntryDigest = HexString; + +export interface IRegistryEntry { + uri: EntryUri + creatorUri: DidUri + digest: HexString + blob: string | null + registryUri: RegistryUri + authorizationUri: RegistryAuthorizationUri +} + +export interface IRegistryEntryDetails { + uri: EntryUri + digest: HexString + blob: string | null + registryUri: RegistryUri + authorizationUri: RegistryAuthorizationUri +} + +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 +} \ No newline at end of file From f3486af7bdd406cbbc027a8d6b40724aeaa5af85 Mon Sep 17 00:00:00 2001 From: Shree Vatsa N Date: Tue, 15 Oct 2024 18:06:21 +0530 Subject: [PATCH 5/6] Delete demo/src/registry-entries-tx.ts Move under demo/dedi --- demo/src/registry-entries-tx.ts | 145 -------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 demo/src/registry-entries-tx.ts diff --git a/demo/src/registry-entries-tx.ts b/demo/src/registry-entries-tx.ts deleted file mode 100644 index 282ed731..00000000 --- a/demo/src/registry-entries-tx.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as Cord from '@cord.network/sdk' -import { createAccount } from './utils/createAccount' - -import { - BN -} from 'bn.js'; - -async function getBalance(address: string, api) { - Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) - - const { data: balance } = await api.query.system.account(address); - return balance.free.toString(); // Returns free balance as a string -} - -async function main() { - const networkAddress = process.env.NETWORK_ADDRESS - ? process.env.NETWORK_ADDRESS - : 'ws://127.0.0.1:9944' - - Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) - await Cord.connect(networkAddress) - - const api = Cord.ConfigService.get('api'); - - // Step 1: Setup Membership - // Setup transaction author account - CORD Account. - - console.log(`\n❄️ New Network Member`) - const authorityAuthorIdentity = Cord.Utils.Crypto.makeKeypairFromUri( - process.env.ANCHOR_URI ? process.env.ANCHOR_URI : '//Alice', - 'sr25519' - ) - - // Setup network member account. - const { account: authorIdentity } = await createAccount() - console.log(`🏦 Member (${authorIdentity.type}): ${authorIdentity.address}`) - - let tx = await api.tx.balances.transferAllowDeath(authorIdentity.address, new BN('1000000000000000')); - await Cord.Chain.signAndSubmitTx(tx, authorityAuthorIdentity); - - // Create a Registry. - const blob = { - "name": "Companies Registry", - "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", - "metadata": { - "category": "business", - "totalCompaniesRegistered": 15000, - "industriesCovered": [ - "Technology", - "Healthcare", - "Renewable Energy", - "Finance", - "Manufacturing" - ], - "lastUpdated": "01-10-2024", - "regulatoryAuthority": "National Business Bureau", - "registrationRequirements": { - "documentsNeeded": [ - "Incorporation Certificate", - "Tax Identification Number", - "Proof of Address", - "Board Resolution" - ], - "feeStructure": { - "smallBusiness": "INR500", - "mediumBusiness": "INR1000", - "largeBusiness": "INR5000" - } - } - } - }; - const stringified_blob = JSON.stringify(blob); - const digest = await Cord.Registries.getDigestFromRawData(stringified_blob); - - // Crreate a Registry Property. - const registryDetails = await Cord.Registries.registryCreateProperties( - authorIdentity.address, - digest, //digest - null, //schemaId - blob, //blob - ); - - console.log(`\n❄️ Registry Create Details `, registryDetails); - - // Dispatch the Registry Property to the chain. - const registry = await Cord.Registries.dispatchCreateRegistryToChain( - registryDetails, - authorIdentity, - ); - - console.log('\nβœ… Registry created!'); - - // Create a Registry Entry. - const entryBlob = { - "name": "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 stringifiedEntryBlob = JSON.stringify(entryBlob); - const entryDigest = await Cord.Registries.getDigestFromRawData(stringifiedEntryBlob); - - // Create a Registry Entry Properties. - const registryEntryDetails = await Cord.Entries.CreateEntriesProperties( - authorIdentity.address, - entryDigest, //digest - entryBlob, //blob - registry.uri, //registryUri - registry.authorizationUri //registryAuthUri - ); - - console.log(`\n❄️ Registry Entry Create Details `, registryEntryDetails); - - // Dispatch the Registry Entry to the chain. - const registryEntry = await Cord.Entries.dispatchCreateEntryToChain( - registryEntryDetails, - authorIdentity, - ) - - console.log('\nβœ… Registry Entry created!'); -} - -main() - .then(() => console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ ')) - .finally(Cord.disconnect) - -process.on('SIGINT', async () => { - console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ \n') - Cord.disconnect() - process.exit(0) -}) From 4fa351ea65ef4a25c36dcedb61f90aae9738c487 Mon Sep 17 00:00:00 2001 From: Shree Vatsa N Date: Tue, 15 Oct 2024 18:06:41 +0530 Subject: [PATCH 6/6] Delete demo/src/registry-tx.ts Move under demo/dedi/ --- demo/src/registry-tx.ts | 288 ---------------------------------------- 1 file changed, 288 deletions(-) delete mode 100644 demo/src/registry-tx.ts diff --git a/demo/src/registry-tx.ts b/demo/src/registry-tx.ts deleted file mode 100644 index 2d9a53f2..00000000 --- a/demo/src/registry-tx.ts +++ /dev/null @@ -1,288 +0,0 @@ -import * as Cord from '@cord.network/sdk' -import { createAccount } from './utils/createAccount' - -import { - BN -} from 'bn.js'; - -async function getBalance(address: string, api) { - Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) - - const { data: balance } = await api.query.system.account(address); - return balance.free.toString(); // Returns free balance as a string -} - -async function main() { - const networkAddress = process.env.NETWORK_ADDRESS - ? process.env.NETWORK_ADDRESS - : 'ws://127.0.0.1:9944' - - Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK }) - await Cord.connect(networkAddress) - - const api = Cord.ConfigService.get('api'); - - // Step 1: Setup Membership - // Setup transaction author account - CORD Account. - - console.log(`\n❄️ New Network Member`) - const authorityAuthorIdentity = Cord.Utils.Crypto.makeKeypairFromUri( - process.env.ANCHOR_URI ? process.env.ANCHOR_URI : '//Alice', - 'sr25519' - ) - - // Setup network member account. - const { account: authorIdentity } = await createAccount() - console.log(`🏦 Member (${authorIdentity.type}): ${authorIdentity.address}`) - - let tx = await api.tx.balances.transferAllowDeath(authorIdentity.address, new BN('1000000000000000')); - await Cord.Chain.signAndSubmitTx(tx, authorityAuthorIdentity); - - // Create a Registry. - const blob = { - "name": "Companies Registry", - "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", - "metadata": { - "category": "business", - "totalCompaniesRegistered": 15000, - "industriesCovered": [ - "Technology", - "Healthcare", - "Renewable Energy", - "Finance", - "Manufacturing" - ], - "lastUpdated": "01-10-2024", - "regulatoryAuthority": "National Business Bureau", - "registrationRequirements": { - "documentsNeeded": [ - "Incorporation Certificate", - "Tax Identification Number", - "Proof of Address", - "Board Resolution" - ], - "feeStructure": { - "smallBusiness": "INR500", - "mediumBusiness": "INR1000", - "largeBusiness": "INR5000" - } - } - } - }; - const stringified_blob = JSON.stringify(blob); - const digest = await Cord.Registries.getDigestFromRawData(stringified_blob); - - const registryDetails = await Cord.Registries.registryCreateProperties( - authorIdentity.address, - digest, //digest - null, //schemaId - blob, //blob - ); - - console.log(`\n❄️ Registry Create Details `, registryDetails); - - const registry = await Cord.Registries.dispatchCreateRegistryToChain( - registryDetails, - authorIdentity, - ); - - console.log('\nβœ… Registry created!'); - - // Update a existing Registry. - const new_blob = { - "name": "Companies Registry - A", - "description": "A centralized registry that tracks the registration, incorporation status, and key business details of companies across various industries.", - "metadata": { - "category": "business", - "totalCompaniesRegistered": 15000, - "industriesCovered": [ - "Technology", - "Healthcare", - "Renewable Energy", - "Finance", - "Manufacturing" - ], - "lastUpdated": "01-10-2024", - "regulatoryAuthority": "National Business Bureau", - "registrationRequirements": { - "documentsNeeded": [ - "Incorporation Certificate", - "Tax Identification Number", - "Proof of Address", - "Board Resolution" - ], - "feeStructure": { - "smallBusiness": "INR500", - "mediumBusiness": "INR1000", - "largeBusiness": "INR5000" - } - } - } - }; - const new_stringified_blob = JSON.stringify(new_blob); - const new_digest = await Cord.Registries.getDigestFromRawData(new_stringified_blob); - - const registryUpdateDetails = await Cord.Registries.registryUpdateProperties( - registry.uri, - registry.authorizationUri, - authorIdentity.address, - new_digest, //digest - new_blob, //blob - ); - - console.log(`\n❄️ Registry Update Details `, registryUpdateDetails); - - const registry_update = await Cord.Registries.dispatchUpdateRegistryToChain( - registryUpdateDetails, - authorIdentity, - ); - - console.log('\nβœ… Registry updated!'); - - // Revoke a Registry - console.log(`\n❄️ Revoking Registry `, registry.uri); - const registry_revoke = await Cord.Registries.dispatchRevokeToChain( - registry.uri, - registry.authorizationUri, - authorIdentity - ); - console.log('βœ… Registry Revoked!'); - - // Reinstate a Revoked Registry - console.log(`\n❄️ Reinstating Revoked Registry `, registry.uri); - const registry_reinstate = await Cord.Registries.dispatchReinstateToChain( - registry.uri, - registry.authorizationUri, - authorIdentity - ); - console.log('βœ… Revoked Registry Reinstated!'); - - // Archive a Registry - console.log(`\n❄️ Archiving Registry `, registry.uri); - const registry_archive = await Cord.Registries.dispatchArchiveToChain( - registry.uri, - registry.authorizationUri, - authorIdentity - ); - console.log('βœ… Registry Archived!'); - - // Restore a Archived Registry - console.log(`\n❄️ Restoring Archived Registry `, registry.uri); - const registry_restore = await Cord.Registries.dispatchRestoreToChain( - registry.uri, - registry.authorizationUri, - authorIdentity - ); - console.log('βœ… Archived Registry Restored!'); - - // Setup a account to be added as a `ASSERT` delegate. - const { account: assertIdentity } = await createAccount() - console.log(`\n🏦 Delegate Member (${assertIdentity.type}): ${assertIdentity.address}`) - - console.log(`\n❄️ Registry Assert Authorization `); - - // Add a delegate with ASSERT permission - const assertPermission: Cord.RegistryPermissionType = Cord.RegistryPermission.ASSERT; - const registryAssertAuthProperties = - await Cord.Registries.registryAuthorizationProperties( - registry.uri, - assertIdentity.address, - assertPermission, - authorIdentity.address - ) - - console.dir(registryAssertAuthProperties, { - depth: null, - colors: true, - }) - - const delegateAssertAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( - registryAssertAuthProperties, - registry.authorizationUri, - authorIdentity - ) - - console.log(`\nβœ… Registry Authorization added with ASSERT permission - ${delegateAssertAuthorizationUri} - added!`) - - // Setup a account to be added as a `DELEGATE` delegate. - const { account: delegateIdentity } = await createAccount() - console.log(`\n🏦 Delegate Member (${delegateIdentity.type}): ${delegateIdentity.address}`) - - console.log(`\n❄️ Registry Delegate Authorization `); - - // Add a delegate with DELEGATE permission - const delegatePermission: Cord.RegistryPermissionType = Cord.RegistryPermission.DELEGATE; - const registryDelegateAuthProperties = - await Cord.Registries.registryAuthorizationProperties( - registry.uri, - delegateIdentity.address, - delegatePermission, - authorIdentity.address - ) - - console.dir(registryDelegateAuthProperties, { - depth: null, - colors: true, - }) - - const delegateAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( - registryDelegateAuthProperties, - registry.authorizationUri, - authorIdentity - ) - - console.log(`\nβœ… Registry Authorization added with DELEGATE permission - ${delegateAuthorizationUri} - added!`) - - // Setup a account to be added as a `DELEGATE` delegate. - const { account: adminIdentity } = await createAccount() - console.log(`\n🏦 Delegate Member (${adminIdentity.type}): ${adminIdentity.address}`) - - console.log(`\n❄️ Registry Admin Authorization `); - - // Add a delegate with DELEGATE permission - const adminPermission: Cord.RegistryPermissionType = Cord.RegistryPermission.ADMIN; - const registryAdminAuthProperties = - await Cord.Registries.registryAuthorizationProperties( - registry.uri, - adminIdentity.address, - adminPermission, - authorIdentity.address - ) - - console.dir(registryAdminAuthProperties, { - depth: null, - colors: true, - }) - - const delegateAdminAuthorizationUri = await Cord.Registries.dispatchDelegateAuthorization( - registryAdminAuthProperties, - registry.authorizationUri, - authorIdentity - ) - - console.log(`\nβœ… Registry Authorization added with ADMIN permission - ${delegateAdminAuthorizationUri} - added!`) - - console.log(`\n❄️ Remove Registry Assert Authorization `); - - // Remove a delegate with ASSERT permission - const removeAuthObj = await Cord.Registries.dispatchRemoveDelegateToChain( - registry.uri, - delegateAssertAuthorizationUri, - registry.authorizationUri, - authorIdentity - ) - - console.log(`\nβœ… Registry ASSERT Authorization removed - ${delegateAssertAuthorizationUri} - removed!`) - - console.log("Balance of Registry Creator after all transactions", await getBalance(authorIdentity.address, api)); -} - -main() - .then(() => console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ ')) - .finally(Cord.disconnect) - -process.on('SIGINT', async () => { - console.log('\nBye! πŸ‘‹ πŸ‘‹ πŸ‘‹ \n') - Cord.disconnect() - process.exit(0) -})