Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: package/namespace: Add delegate #267

Merged
merged 3 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 166 additions & 1 deletion packages/namespace/src/Namespace.chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,15 @@ import {
INamespaceCreate,
NamespaceAuthorizationUri,
NamespaceUri,
NamespacePermissionType,
NamespacePermission,
INamespaceAuthorization
} from '@cord.network/types';

import {
uriToIdentifier,
} from '@cord.network/identifier'
import { PalletNamespaceNameSpaceDetails } from '@cord.network/augment-api';
import { PalletNamespaceNameSpaceAuthorization, PalletNamespaceNameSpaceDetails } from '@cord.network/augment-api';


/**
Expand Down Expand Up @@ -170,3 +173,165 @@ export async function dispatchCreateToChain(
);
}
}

/**
* Dispatches a transaction to add a delegate authorization for a specified namespace.
*
* 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 namespace.
* 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 `NamespacePermissionType` values (e.g., ASSERT, DELEGATE, ADMIN).
* @param namespaceId - The identifier of the namespace 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(
* NamespacePermission.ASSERT,
* 'namespaceId123',
* 'delegateId456',
* 'authorizationId789'
* );
* console.log('Extrinsic to be dispatched:', extrinsic);
*
*/
function dispatchDelegateAuthorizationTx(
permission: NamespacePermissionType,
namespaceId: string,
delegateId: string,
authorizationId: string
) {
const api = ConfigService.get('api')

switch (permission) {
case NamespacePermission.ASSERT:
return api.tx.nameSpace.addDelegate(
namespaceId,
delegateId,
authorizationId
)
case NamespacePermission.DELEGATE:
return api.tx.nameSpace.addDelegator(
namespaceId,
delegateId,
authorizationId
)
case NamespacePermission.ADMIN:
return api.tx.nameSpace.addAdminDelegate(
namespaceId,
delegateId,
authorizationId
)
default:
throw new SDKErrors.InvalidPermissionError(
`Permission not valid:"${permission}".`
)
}
}

/**
* Dispatches a transaction to authorize a delegate for a specified namespace.
*
* This function checks the existence of the namespace 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 namespace URI, delegate URI, and permission.
* @param namespaceAuthorizationUri`: The URI for the associated namespace authorization.
* @param authorAccount - The account of the author who signs and submits the transaction.
* @returns The `NamespaceAuthorizationUri` after successfully dispatching the authorization.
* @throws {SDKErrors.CordDispatchError} If the namespace 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: 'namespaceUri123',
* delegateUri: 'did:cord:3delegate123',
* permission: NamespacePermission.ADMIN
* },
* 'namespaceAuthUri123',
* authorAccount
* );
* console.log('Authorization dispatched with URI:', authorizationUri);
*
*/
export async function dispatchDelegateAuthorization(
request: INamespaceAuthorization,
namespaceAuthorizationUri: NamespaceAuthorizationUri,
authorAccount: CordKeyringPair,
): Promise<NamespaceAuthorizationUri> {
try {

const registryExists = await isNamespaceStored(request.uri);
if (!registryExists) {
throw new SDKErrors.CordDispatchError(
`Registry URI does not exist: "${request.uri}".`
);
}

const authorizationExists = await isNamespaceAuthorizationStored(namespaceAuthorizationUri);
if (!authorizationExists) {
throw new SDKErrors.CordDispatchError(
`Namespace Authorization URI does not exist: "${namespaceAuthorizationUri}".`
);
}

const nameSpaceId = uriToIdentifier(request.uri);
const delegateId = request.delegateUri.replace("did:cord:3", "");
const namespaceAuthorizationId = uriToIdentifier(namespaceAuthorizationUri);

const extrinsic = dispatchDelegateAuthorizationTx(
request.permission,
nameSpaceId,
delegateId,
namespaceAuthorizationId,
)

await Chain.signAndSubmitTx(extrinsic, authorAccount)

return request.authorizationUri
} catch (error) {
throw new SDKErrors.CordDispatchError(
`Error dispatching delegate authorization: ${JSON.stringify(error)}`
)
}
}

/**
* Checks whether a namespace authorization is stored in the CORD blockchain.
*
* This function queries the chain for the existence of a namespace authorization
* using the provided authorization URI. It returns `true` if the authorization exists;
* otherwise, it returns `false`.
*
* @param authorizationUri - The URI of the namespace 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 registry storage.
*
* @example
* // Example: Checking if a registry authorization exists
* const authorizationExists = await isNamespaceAuthorizationStored('auth:cord:example_authorization_uri');
* console.log('Authorization exists:', authorizationExists);
*
*/
export async function isNamespaceAuthorizationStored(
authorizationUri: NamespaceAuthorizationUri
): Promise<boolean> {
try {
const api = ConfigService.get('api')
const identifier = uriToIdentifier(authorizationUri)
const encoded = await api.query.nameSpace.authorizations(identifier) as Option<PalletNamespaceNameSpaceAuthorization>;

return !encoded.isNone
} catch (error) {
throw new SDKErrors.CordQueryError(
`Error querying authorization existence: ${error}`
)
}
}
58 changes: 58 additions & 0 deletions packages/namespace/src/Namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import type {
DidUri,
HexString,
INamespaceCreate,
NamespacePermissionType,
} from '@cord.network/types';

import { SDKErrors, Cbor } from '@cord.network/utils';
Expand All @@ -62,6 +63,7 @@ import type {
NamespaceDigest,
NamespaceAuthorizationUri,
NamespaceUri,
INamespaceAuthorization
} from '@cord.network/types';

import {
Expand Down Expand Up @@ -436,3 +438,59 @@ export async function namespaceCreateProperties(
authorizationUri,
}
}

/**
* Creates properties for namespace authorization, including URIs for the namespace,
* delegate, and delegator, as well as the associated permission for the authorization.
*
* This function constructs the authorization properties required for a delegate
* to act on behalf in a specified namespace. It generates the
* delegate and delegator URIs and retrieves the authorization URI for the
* specified namespace.
*
* @param namespaceUri - The URI of the namespace for which authorization is being created.
* @param delegateAddress - The address of the delegate who will be granted permissions.
* @param permission - The type of permission being granted to the delegate in the namespace.
* @param delegatorAddress - The address of the delegator who is granting the permission to the delegate.
*
* @returns A promise that resolves to an object containing the properties of the namespace
* authorization, including the namespace URI, authorization URI, delegate URI, permission type,
* and delegator URI.
*
* @throws {SDKErrors.InputContentsMalformedError} If any input parameter is malformed or invalid.
*
* @example
* const authorizationProperties = await namespaceAuthorizationProperties(
* 'namespaceUri123', // registryUri
* '5F3s...', // delegateAddress
* 'delegate', // permission
* '5F3x...' // delegatorAddress
* );
* // authorizationProperties will contain the created namespace authorization properties.
*
*/
export async function namespaceAuthorizationProperties(
namespaceUri: NamespaceUri,
delegateAddress: string,
permission: NamespacePermissionType,
delegatorAddress: string,
): Promise<INamespaceAuthorization> {

// TOOD: Revisit below did-abstraction.
const delegateUri = `did:cord:3${delegateAddress}` as DidUri;
const delegatorUri = `did:cord:3${delegatorAddress}` as DidUri;

const delegateAuthorizationUri = await getUriForAuthorization(
namespaceUri,
delegateAddress,
delegatorAddress
);

return {
uri: namespaceUri,
authorizationUri: delegateAuthorizationUri,
delegateUri: delegateUri,
permission,
delegatorUri: delegatorUri,
}
}