@cheqd/sdk
Version:
A TypeScript SDK built with CosmJS to interact with the cheqd network ledger
600 lines • 26.2 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultBackoffOptions = exports.createMsgUpdateDidDocPayloadToSign = exports.EnglishMnemonic = exports.TImportableEd25519Key = void 0;
exports.isEqualKeyValuePair = isEqualKeyValuePair;
exports.createSignInputsFromImportableEd25519Key = createSignInputsFromImportableEd25519Key;
exports.createKeyPairRaw = createKeyPairRaw;
exports.createKeyPairBase64 = createKeyPairBase64;
exports.createKeyPairHex = createKeyPairHex;
exports.createVerificationKeys = createVerificationKeys;
exports.createDidVerificationMethod = createDidVerificationMethod;
exports.createDidPayload = createDidPayload;
exports.validateSpecCompliantPayload = validateSpecCompliantPayload;
exports.createCosmosPayerWallet = createCosmosPayerWallet;
exports.toMultibaseRaw = toMultibaseRaw;
exports.createMsgCreateDidDocPayloadToSign = createMsgCreateDidDocPayloadToSign;
exports.createMsgDeactivateDidDocPayloadToSign = createMsgDeactivateDidDocPayloadToSign;
exports.createMsgResourcePayloadToSign = createMsgResourcePayloadToSign;
exports.getCosmosAccount = getCosmosAccount;
exports.checkBalance = checkBalance;
exports.isJSON = isJSON;
exports.retry = retry;
exports.normalizeAuthentication = normalizeAuthentication;
exports.normalizeController = normalizeController;
exports.normalizeService = normalizeService;
exports.denormalizeService = denormalizeService;
const types_1 = require("./types");
const uint8arrays_cjs_1 = require("uint8arrays-cjs");
const basics_1 = require("multiformats-cjs/basics");
const did_jwt_cjs_1 = require("did-jwt-cjs");
const ed25519_cjs_1 = require("@stablelib/ed25519-cjs");
const proto_signing_cjs_1 = require("@cosmjs/proto-signing-cjs");
const crypto_cjs_1 = require("@cosmjs/crypto-cjs");
const amino_cjs_1 = require("@cosmjs/amino-cjs");
const secp256k1_cjs_1 = __importDefault(require("secp256k1-cjs"));
const uuid_cjs_1 = require("uuid-cjs");
const v2_1 = require("@cheqd/ts-proto-cjs/cheqd/did/v2");
const did_1 = require("./modules/did");
const v2_2 = require("@cheqd/ts-proto-cjs/cheqd/resource/v2");
const encoding_cjs_1 = require("@cosmjs/encoding-cjs");
const stargate_cjs_1 = require("@cosmjs/stargate-cjs");
const exponential_backoff_cjs_1 = require("exponential-backoff-cjs");
/**
* Utility object for validating TImportableEd25519Key objects.
* Provides type guard functionality to ensure key structure integrity.
*/
exports.TImportableEd25519Key = {
/**
* Type guard to validate if an object is a valid TImportableEd25519Key.
*
* @param key - Object to validate
* @returns True if the object is a valid TImportableEd25519Key
*/
isValid(key) {
return (typeof key === 'object' &&
key !== null &&
typeof key.publicKeyHex === 'string' &&
isHex(key.publicKeyHex) &&
typeof key.privateKeyHex === 'string' &&
isHex(key.privateKeyHex) &&
typeof key.kid === 'string' &&
key.type === 'Ed25519');
},
};
/** Multicodec header for Ed25519 public keys */
const MULTICODEC_ED25519_HEADER = new Uint8Array([0xed, 0x01]);
/**
* Compares two arrays of key-value pairs for equality.
*
* @param kv1 - First array of key-value pairs
* @param kv2 - Second array of key-value pairs
* @returns True if both arrays contain identical key-value pairs in the same order
*/
function isEqualKeyValuePair(kv1, kv2) {
return kv1.every((item, index) => item.key === kv2[index].key && item.value === kv2[index].value);
}
/**
* Extended English mnemonic class with additional validation patterns.
* Provides regex pattern matching for mnemonic phrase validation.
*/
class EnglishMnemonic extends crypto_cjs_1.EnglishMnemonic {
/** Regular expression pattern for validating English mnemonic phrases */
static _mnemonicMatcher = /^[a-z]+( [a-z]+)*$/;
}
exports.EnglishMnemonic = EnglishMnemonic;
/**
* Creates signing inputs from an importable Ed25519 key by matching it with verification methods.
* Supports multiple verification method types and key formats.
*
* @param key - The Ed25519 key to create signing inputs from
* @param verificationMethod - Array of verification methods to match against
* @returns Signing inputs containing verification method ID and private key
* @throws Error if key validation fails or no matching verification method is found
*/
function createSignInputsFromImportableEd25519Key(key, verificationMethod) {
if (!exports.TImportableEd25519Key.isValid(key))
throw new Error(`Key validation failed. Expected ${Object.values(exports.TImportableEd25519Key).join(', ')}`);
const publicKey = (0, uint8arrays_cjs_1.fromString)(key.publicKeyHex, 'hex');
for (const method of verificationMethod) {
switch (method.type) {
case types_1.VerificationMethods.Ed255192020:
const publicKeyMultibase = toMultibaseRaw(publicKey);
if (method.publicKeyMultibase === publicKeyMultibase) {
return {
verificationMethodId: method.id,
privateKeyHex: key.privateKeyHex,
};
}
case types_1.VerificationMethods.Ed255192018:
const publicKeyBase58 = basics_1.bases['base58btc'].encode(publicKey).slice(1);
if (method.publicKeyBase58 === publicKeyBase58) {
return {
verificationMethodId: method.id,
privateKeyHex: key.privateKeyHex,
};
}
case types_1.VerificationMethods.JWK:
const publicKeyJwk = {
crv: 'Ed25519',
kty: 'OKP',
x: (0, uint8arrays_cjs_1.toString)(publicKey, 'base64url'),
};
if (JSON.stringify(method.publicKeyJwk) === JSON.stringify(publicKeyJwk)) {
return {
verificationMethodId: method.id,
privateKeyHex: key.privateKeyHex,
};
}
}
throw new Error(`Unsupported verification method type: ${method.type}. Expected one of: ${Object.values(types_1.VerificationMethods).join(', ')}`);
}
throw new Error(`No verification method type provided. Expected one of: ${Object.values(types_1.VerificationMethods).join(', ')}`);
}
/**
* Creates a raw Ed25519 key pair using the StableLib library.
*
* @param seed - Optional seed string for deterministic key generation
* @returns Raw KeyPair object with publicKey and secretKey as Uint8Arrays
*/
function createKeyPairRaw(seed) {
return seed ? (0, ed25519_cjs_1.generateKeyPairFromSeed)((0, uint8arrays_cjs_1.fromString)(seed)) : (0, ed25519_cjs_1.generateKeyPair)();
}
/**
* Creates an Ed25519 key pair with Base64-encoded keys.
*
* @param seed - Optional seed string for deterministic key generation
* @returns Key pair with Base64-encoded public and private keys
*/
function createKeyPairBase64(seed) {
const keyPair = seed ? (0, ed25519_cjs_1.generateKeyPairFromSeed)((0, uint8arrays_cjs_1.fromString)(seed)) : (0, ed25519_cjs_1.generateKeyPair)();
return {
publicKey: (0, uint8arrays_cjs_1.toString)(keyPair.publicKey, 'base64'),
privateKey: (0, uint8arrays_cjs_1.toString)(keyPair.secretKey, 'base64'),
};
}
/**
* Creates an Ed25519 key pair with hexadecimal-encoded keys.
*
* @param seed - Optional seed string for deterministic key generation
* @returns Key pair with hexadecimal-encoded public and private keys
*/
function createKeyPairHex(seed) {
const keyPair = createKeyPairRaw(seed);
return {
publicKey: (0, uint8arrays_cjs_1.toString)(keyPair.publicKey, 'hex'),
privateKey: (0, uint8arrays_cjs_1.toString)(keyPair.secretKey, 'hex'),
};
}
/**
* Creates verification keys structure with DID URLs and key identifiers.
* Supports multiple algorithm types and network configurations.
*
* @param publicKey - Public key in base64 or hex format
* @param algo - Algorithm for method-specific ID generation
* @param keyFragment - Key fragment for the verification key identifier
* @param network - Cheqd network (defaults to Testnet)
* @param methodSpecificId - Optional pre-computed method-specific ID
* @param didUrl - Optional pre-computed DID URL
* @returns Verification keys structure with all identifiers
* @throws Error if public key format is invalid
*/
function createVerificationKeys(publicKey, algo, keyFragment, network = types_1.CheqdNetwork.Testnet, methodSpecificId, didUrl) {
if (isHex(publicKey)) {
publicKey = (0, uint8arrays_cjs_1.toString)((0, uint8arrays_cjs_1.fromString)(publicKey, 'hex'), 'base64');
}
else if (!isBase64(publicKey)) {
throw new Error('publicKey validation failed. PublicKey should be in base64 or hex format');
}
switch (algo) {
case types_1.MethodSpecificIdAlgo.Base58:
methodSpecificId ||= basics_1.bases['base58btc'].encode((0, did_jwt_cjs_1.base64ToBytes)(publicKey));
didUrl ||= `did:cheqd:${network}:${basics_1.bases['base58btc']
.encode((0, crypto_cjs_1.sha256)((0, did_jwt_cjs_1.base64ToBytes)(publicKey)).slice(0, 16))
.slice(1)}`;
return {
methodSpecificId,
didUrl,
keyId: `${didUrl}#${keyFragment}`,
publicKey,
};
case types_1.MethodSpecificIdAlgo.Uuid:
methodSpecificId ||= (0, uuid_cjs_1.v4)();
didUrl ||= `did:cheqd:${network}:${methodSpecificId}`;
return {
methodSpecificId,
didUrl,
keyId: `${didUrl}#${keyFragment}`,
publicKey,
};
}
}
/**
* Creates DID verification methods from verification method types and keys.
* Supports Ed25519 keys in multiple formats (multibase, base58, JWK).
*
* @param verificationMethodTypes - Array of verification method types to create
* @param verificationKeys - Array of verification keys corresponding to each type
* @returns Array of formatted verification methods for DID documents
*/
function createDidVerificationMethod(verificationMethodTypes, verificationKeys) {
return (verificationMethodTypes.map((type, _) => {
switch (type) {
case types_1.VerificationMethods.Ed255192020:
return {
id: verificationKeys[_].keyId,
type,
controller: verificationKeys[_].didUrl,
publicKeyMultibase: toMultibaseRaw((0, did_jwt_cjs_1.base64ToBytes)(verificationKeys[_].publicKey)),
};
case types_1.VerificationMethods.Ed255192018:
return {
id: verificationKeys[_].keyId,
type,
controller: verificationKeys[_].didUrl,
publicKeyBase58: basics_1.bases['base58btc']
.encode((0, did_jwt_cjs_1.base64ToBytes)(verificationKeys[_].publicKey))
.slice(1),
};
case types_1.VerificationMethods.JWK:
return {
id: verificationKeys[_].keyId,
type,
controller: verificationKeys[_].didUrl,
publicKeyJwk: {
crv: 'Ed25519',
kty: 'OKP',
x: (0, uint8arrays_cjs_1.toString)((0, uint8arrays_cjs_1.fromString)(verificationKeys[_].publicKey, 'base64pad'), 'base64url'),
},
};
}
}) ?? []);
}
/**
* Creates a complete DID document payload with verification methods and controllers.
*
* @param verificationMethods - Array of verification methods for the DID
* @param verificationKeys - Array of verification keys for authentication
* @param controller - Optional array of controller DIDs (defaults to self-controlled)
* @returns Complete DID document with all required fields
* @throws Error if verification methods or keys are missing
*/
function createDidPayload(verificationMethods, verificationKeys, controller = []) {
if (!verificationMethods || verificationMethods.length === 0)
throw new Error('No verification methods provided');
if (!verificationKeys || verificationKeys.length === 0)
throw new Error('No verification keys provided');
const did = verificationKeys[0].didUrl;
return {
id: did,
controller: controller.length ? controller : Array.from(new Set(verificationKeys.map((key) => key.didUrl))),
verificationMethod: verificationMethods,
authentication: verificationKeys.map((key) => key.keyId),
assertionMethod: verificationKeys.map((key) => key.keyId),
};
}
/**
* Validates a DID document against the Cheqd specification and converts to protobuf format.
* Ensures all required fields are present and verification methods are supported.
*
* @param didDocument - DID document to validate
* @returns Validation result with protobuf conversion or error details
*/
function validateSpecCompliantPayload(didDocument) {
// id is required, validated on both compile and runtime
if (!didDocument?.id)
return { valid: false, error: 'id is required' };
// verificationMethod is required
if (!didDocument?.verificationMethod)
return { valid: false, error: 'verificationMethod is required' };
// verificationMethod must be an array
if (!Array.isArray(didDocument?.verificationMethod))
return { valid: false, error: 'verificationMethod must be an array' };
// verificationMethod types must be supported
const protoVerificationMethod = didDocument.verificationMethod.map((vm) => {
switch (vm?.type) {
case types_1.VerificationMethods.Ed255192020:
if (!vm.publicKeyMultibase)
throw new Error('publicKeyMultibase is required');
return v2_1.VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: types_1.VerificationMethods.Ed255192020,
verificationMaterial: vm.publicKeyMultibase,
});
case types_1.VerificationMethods.JWK:
if (!vm.publicKeyJwk)
throw new Error('publicKeyJwk is required');
return v2_1.VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: types_1.VerificationMethods.JWK,
verificationMaterial: JSON.stringify(vm.publicKeyJwk),
});
case types_1.VerificationMethods.Ed255192018:
if (!vm.publicKeyBase58)
throw new Error('publicKeyBase58 is required');
return v2_1.VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: types_1.VerificationMethods.Ed255192018,
verificationMaterial: vm.publicKeyBase58,
});
default:
throw new Error(`Unsupported verificationMethod type: ${vm?.type}`);
}
});
const protoService = normalizeService(didDocument);
return {
valid: true,
protobufVerificationMethod: protoVerificationMethod,
protobufService: protoService,
};
}
/**
* Creates a Cosmos wallet from a seed phrase or private key.
* Automatically detects whether the input is a mnemonic phrase or hex-encoded private key.
*
* @param cosmosPayerSeed - Mnemonic phrase or hexadecimal private key
* @returns Promise resolving to DirectSecp256k1HdWallet or DirectSecp256k1Wallet
*/
function createCosmosPayerWallet(cosmosPayerSeed) {
return EnglishMnemonic._mnemonicMatcher.test(cosmosPayerSeed)
? proto_signing_cjs_1.DirectSecp256k1HdWallet.fromMnemonic(cosmosPayerSeed, { prefix: 'cheqd' })
: proto_signing_cjs_1.DirectSecp256k1Wallet.fromKey((0, uint8arrays_cjs_1.fromString)(cosmosPayerSeed.replace(/^0x/, ''), 'hex'), 'cheqd');
}
/**
* Converts a raw Ed25519 public key to multibase format with proper multicodec header.
*
* @param key - Raw Ed25519 public key as Uint8Array
* @returns Multibase-encoded string with Ed25519 multicodec prefix
*/
function toMultibaseRaw(key) {
const multibase = new Uint8Array(MULTICODEC_ED25519_HEADER.length + key.length);
multibase.set(MULTICODEC_ED25519_HEADER);
multibase.set(key, MULTICODEC_ED25519_HEADER.length);
return basics_1.bases['base58btc'].encode(multibase);
}
/**
* Creates a MsgCreateDidDoc payload ready for signing.
* Validates the DID document and converts it to protobuf format.
*
* @param didPayload - DID document to create message payload from
* @param versionId - Version identifier for the DID document
* @returns Encoded message payload bytes ready for signing
*/
async function createMsgCreateDidDocPayloadToSign(didPayload, versionId) {
const { protobufVerificationMethod, protobufService } = await did_1.DIDModule.validateSpecCompliantPayload(didPayload);
return v2_1.MsgCreateDidDocPayload.encode(v2_1.MsgCreateDidDocPayload.fromPartial({
context: didPayload?.['@context'],
id: didPayload.id,
controller: didPayload.controller,
verificationMethod: protobufVerificationMethod,
authentication: didPayload.authentication,
assertionMethod: didPayload.assertionMethod,
capabilityInvocation: didPayload.capabilityInvocation,
capabilityDelegation: didPayload.capabilityDelegation,
keyAgreement: didPayload.keyAgreement,
service: protobufService,
alsoKnownAs: didPayload.alsoKnownAs,
versionId,
})).finish();
}
/** Alias for createMsgCreateDidDocPayloadToSign - used for DID document updates */
exports.createMsgUpdateDidDocPayloadToSign = createMsgCreateDidDocPayloadToSign;
/**
* Creates a MsgDeactivateDidDoc payload ready for signing.
*
* @param didPayload - DID document containing the ID to deactivate
* @param versionId - Optional version identifier for the deactivation
* @returns Encoded deactivation message payload bytes ready for signing
*/
function createMsgDeactivateDidDocPayloadToSign(didPayload, versionId) {
return v2_1.MsgDeactivateDidDocPayload.encode(v2_1.MsgDeactivateDidDocPayload.fromPartial({
id: didPayload.id,
versionId,
})).finish();
}
/**
* Creates a MsgCreateResource payload ready for signing.
*
* @param payload - Resource creation payload (partial or complete)
* @returns Encoded resource creation message payload bytes ready for signing
*/
function createMsgResourcePayloadToSign(payload) {
return v2_2.MsgCreateResourcePayload.encode(v2_2.MsgCreateResourcePayload.fromPartial(payload)).finish();
}
/**
* Derives a Cosmos account address from a hexadecimal public key.
* Converts the public key to the appropriate format and generates a bech32 address.
*
* @param publicKeyHex - Secp256k1 public key in hexadecimal format
* @returns Bech32-encoded Cheqd account address
*/
function getCosmosAccount(publicKeyHex) {
const { publicKeyConvert } = secp256k1_cjs_1.default;
return (0, encoding_cjs_1.toBech32)('cheqd', (0, amino_cjs_1.rawSecp256k1PubkeyToRawAddress)(publicKeyConvert((0, uint8arrays_cjs_1.fromString)(publicKeyHex, 'hex'), true)));
}
/**
* Checks the balance of all coins for a given address on the blockchain.
*
* @param address - Bech32-encoded account address to check balance for
* @param rpcAddress - RPC endpoint URL of the blockchain node
* @returns Promise resolving to array of coin balances
*/
async function checkBalance(address, rpcAddress) {
const client = await stargate_cjs_1.StargateClient.connect(rpcAddress);
return await client.getAllBalances(address);
}
/**
* Checks if a given input is valid JSON.
*
* @param input - Input to validate as JSON
* @returns True if the input is a valid JSON string
*/
function isJSON(input) {
if (typeof input !== 'string')
return false;
try {
JSON.parse(input);
return true;
}
catch (e) {
return false;
}
}
/** Default configuration options for exponential backoff retry logic */
exports.DefaultBackoffOptions = {
jitter: 'full',
timeMultiple: 1,
delayFirstAttempt: false,
maxDelay: 100,
startingDelay: 100,
numOfAttempts: 3,
};
/**
* Retries a function with exponential backoff strategy.
* Provides configurable retry logic with jitter and delay options.
*
* @template T - Return type of the function being retried
* @param fn - Async function to retry
* @param options - Optional backoff configuration (uses defaults if not provided)
* @returns Promise resolving to the function result or undefined if all retries fail
*/
async function retry(fn, options) {
// set default options
if (!options) {
options = exports.DefaultBackoffOptions;
}
else {
// overwrite defaults with user supplied options
options = { ...exports.DefaultBackoffOptions, ...options };
}
let result;
try {
result = await (0, exponential_backoff_cjs_1.backOff)(fn, options);
}
catch (e) {
console.error(e);
}
return result;
}
/**
* Validates if a string is properly formatted Base64.
* Performs pattern matching and encoding validation.
*
* @param str - String to validate as Base64
* @returns True if the string is valid Base64
*/
function isBase64(str) {
// Quick pattern check to filter obvious non-base64 strings
const base64Pattern = /^[A-Za-z0-9+/]*={0,3}$/;
if (!base64Pattern.test(str)) {
return false;
}
try {
return (0, uint8arrays_cjs_1.toString)((0, uint8arrays_cjs_1.fromString)(str, 'base64'), 'base64') === str;
}
catch (e) {
return false;
}
}
/**
* Validates if a string is properly formatted hexadecimal.
* Performs pattern matching and encoding validation.
*
* @param str - String to validate as hexadecimal
* @returns True if the string is valid hexadecimal
*/
function isHex(str) {
// Quick pattern check to filter obvious non-hex strings
const hexPattern = /^[0-9a-fA-F]*$/;
if (!hexPattern.test(str)) {
return false;
}
try {
return (0, uint8arrays_cjs_1.toString)((0, uint8arrays_cjs_1.fromString)(str, 'hex'), 'hex') === str;
}
catch {
return false;
}
}
/**
* Normalizes the authentication property of a DID document to an array of strings.
* Handles both string references and embedded verification method objects.
*
* @param didDocument - DID document to normalize authentication for
* @returns Array of authentication method identifiers
* @throws Error if authentication section is missing
*/
function normalizeAuthentication(didDocument) {
if (!didDocument.authentication)
throw new Error('Invalid DID Document: Authentication section is required in DID Document');
const authArray = Array.isArray(didDocument.authentication)
? didDocument.authentication
: [didDocument.authentication];
return authArray.map((a) => (typeof a === 'string' ? a : a.id));
}
/**
* Normalizes the controller property of a DID document to an array of strings.
* Defaults to self-controlled if no controller is specified.
*
* @param didDocument - DID document to normalize controller for
* @returns Array of controller DID identifiers
*/
function normalizeController(didDocument) {
if (!didDocument.controller)
return [didDocument.id];
return Array.isArray(didDocument.controller) ? didDocument.controller : [didDocument.controller];
}
/**
* Normalizes DID document services to protobuf format.
* Converts service endpoints to arrays and includes optional properties.
*
* @param didDocument - DID document containing services to normalize
* @returns Array of protobuf-formatted services or undefined if no services
*/
function normalizeService(didDocument) {
return didDocument.service?.map((s) => {
return v2_1.Service.fromPartial({
id: s?.id,
serviceType: s?.type,
serviceEndpoint: s ? (Array.isArray(s.serviceEndpoint) ? s.serviceEndpoint : [s.serviceEndpoint]) : [],
...(s?.recipientKeys && { recipientKeys: s.recipientKeys }),
...(s?.routingKeys && { routingKeys: s.routingKeys }),
...(s?.accept && { accept: s.accept }),
...(s?.priority !== undefined && { priority: s.priority }),
});
});
}
/**
* Converts protobuf services back to standard DID document service format.
* Handles special context requirements for LinkedDomains services.
*
* @param didDocument - Protobuf DID document containing services to denormalize
* @returns Array of standard DID document services
*/
function denormalizeService(didDocument) {
return didDocument.service.map((s) => {
if (s.serviceType === types_1.ServiceType.LinkedDomains) {
const updatedContext = [...didDocument.context, did_1.contexts.LinkedDomainsContext];
didDocument = { ...didDocument, context: updatedContext };
}
return {
id: s.id,
type: s.serviceType,
serviceEndpoint: Array.isArray(s?.serviceEndpoint)
? s.serviceEndpoint.length === 1
? s.serviceEndpoint[0]
: s.serviceEndpoint
: s?.serviceEndpoint,
...(s.recipientKeys && { recipientKeys: s.recipientKeys }),
...(s.routingKeys && { routingKeys: s.routingKeys }),
...(s.accept && { accept: s.accept }),
...(s.priority !== undefined && { priority: s.priority }),
};
});
}
//# sourceMappingURL=utils.js.map
;