Skip to content

Commit

Permalink
feat(registry): Fixed registration logic & improved extensibility
Browse files Browse the repository at this point in the history
  • Loading branch information
Eengineer1 committed Jul 29, 2022
1 parent 080f340 commit 3d76466
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 91 deletions.
26 changes: 15 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GeneratedType, OfflineSigner, Registry } from '@cosmjs/proto-signing'
import { DIDModule, MinimalImportableDIDModule } from './modules/did'
import { MinimalImportableResourcesModule, ResourcesModule } from './modules/resources'
import { AbstractCheqdSDKModule, applyMixins, instantiateCheqdSDKModule, } from './modules/_'
import { AbstractCheqdSDKModule, applyMixins, instantiateCheqdSDKModule, instantiateCheqdSDKModuleRegistryTypes, } from './modules/_'
import { createDefaultCheqdRegistry } from './registry'
import { CheqdSigningStargateClient } from './signer'
import { CheqdNetwork, IContext, IModuleMethodMap } from './types'
Expand All @@ -22,7 +22,7 @@ export class CheqdSDK {
methods: IModuleMethodMap
signer: CheqdSigningStargateClient
options: ICheqdSDKOptions
private protectedMethods: string[] = ['constructor', 'build', 'loadModules']
private protectedMethods: string[] = ['constructor', 'build', 'loadModules', 'loadRegistry']

constructor(options: ICheqdSDKOptions) {
if (!options?.wallet) {
Expand All @@ -49,14 +49,6 @@ export class CheqdSDK {
private loadModules(modules: AbstractCheqdSDKModule[]): CheqdSDK {
this.options.modules = this.options.modules.map((module: any) => instantiateCheqdSDKModule(module, this.signer, { sdk: this } as IContext) as unknown as AbstractCheqdSDKModule)

let registryTypes: Iterable<[string, GeneratedType]> = [];
this.options.modules.forEach((module: AbstractCheqdSDKModule) => {
registryTypes = [...registryTypes, ...module.registryTypes]
})
for (const registryType of registryTypes) {
this.signer.registry.register(registryType[0], registryType[1])
}

const methods = applyMixins(this, modules)
this.methods = { ...this.methods, ...filterUnauthorizedMethods(methods, this.options.authorizedMethods || [], this.protectedMethods) }

Expand All @@ -70,10 +62,22 @@ export class CheqdSDK {
return this
}

async build() {
private loadRegistry(): Registry {
const registryTypes = this.options.modules.map((module: any) => instantiateCheqdSDKModuleRegistryTypes(module)).reduce((acc, types) => {
return [...acc, ...types]
})
return createDefaultCheqdRegistry(registryTypes)
}

async build(): Promise<CheqdSDK> {
const registry = this.loadRegistry()

this.signer = await CheqdSigningStargateClient.connectWithSigner(
this.options.rpcUrl,
this.options.wallet,
{
registry,
}
)

return this.loadModules(this.options.modules)
Expand Down
16 changes: 12 additions & 4 deletions src/modules/_.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,36 @@ import { GeneratedType, Registry } from "@cosmjs/proto-signing"
import { QueryClient } from "@cosmjs/stargate"
import { CheqdSigningStargateClient } from '../signer'
import { IModuleMethodMap } from "../types"
import { setupDidExtension } from './did'
import { DIDModule, setupDidExtension } from './did'

export abstract class AbstractCheqdSDKModule {
_signer: CheqdSigningStargateClient
methods: IModuleMethodMap = {}
readonly _protectedMethods: string[] = ['constructor', 'exportMethods', 'registryTypes']
abstract readonly registryTypes: Iterable<[string, GeneratedType]>;
readonly _protectedMethods: string[] = ['constructor', 'getRegistryTypes']
static readonly registryTypes: Iterable<[string, GeneratedType]> = []

constructor(signer: CheqdSigningStargateClient) {
if (!signer) {
throw new Error("signer is required")
}
this._signer = signer
}

abstract getRegistryTypes(): Iterable<[string, GeneratedType]>
}

export type MinimalImportableCheqdSDKModule<T extends AbstractCheqdSDKModule> = Omit<T, '_signer' | '_protectedMethods'>
type ProtectedMethods<T extends AbstractCheqdSDKModule, K extends keyof T> = T[K] extends string[] ? T[K][number] : T[K]

export type MinimalImportableCheqdSDKModule<T extends AbstractCheqdSDKModule> = Omit<T, '_signer' | '_protectedMethods' | 'registryTypes' | 'getRegistryTypes'>

export function instantiateCheqdSDKModule<T extends new (...args: any[]) => T>(module: T, ...args: ConstructorParameters<T>): T {
return new module(...args)
}

export function instantiateCheqdSDKModuleRegistryTypes(module: any): Iterable<[string, GeneratedType]> {
return module.registryTypes ?? []
}

export function applyMixins(derivedCtor: any, constructors: any[]): IModuleMethodMap {
let methods: IModuleMethodMap = {}

Expand Down
74 changes: 54 additions & 20 deletions src/modules/did.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,72 @@
import { createProtobufRpcClient, DeliverTxResponse, QueryClient, StdFee } from "@cosmjs/stargate"
import { createProtobufRpcClient, DeliverTxResponse, QueryClient } from "@cosmjs/stargate"
/* import { QueryClientImpl } from '@cheqd/ts-proto/cheqd/v1/query' */
import { CheqdExtension, AbstractCheqdSDKModule, MinimalImportableCheqdSDKModule } from "./_"
import { CheqdSigningStargateClient } from "../signer"
import { DidStdFee, IContext, ISignInputs } from "../types"
import { MsgCreateDid, MsgCreateDidPayload, MsgCreateDidResponse, MsgUpdateDid, MsgUpdateDidPayload, MsgUpdateDidResponse } from "@cheqd/ts-proto/cheqd/v1/tx"
import { MsgCreateDidEncodeObject, MsgUpdateDidEncodeObject, typeUrlMsgCreateDid, typeUrlMsgUpdateDid, typeUrlMsgUpdateDidResponse } from "../registry"
import { VerificationMethod } from "@cheqd/ts-proto/cheqd/v1/did"
import { GeneratedType } from "@cosmjs/proto-signing"
import {
typeUrlMsgCreateDidResponse,
} from "../registry"
import { MsgCreateDid, MsgCreateDidPayload, MsgCreateDidResponse, MsgUpdateDid, MsgUpdateDidPayload, MsgUpdateDidResponse, protobufPackage } from "@cheqd/ts-proto/cheqd/v1/tx"
import { EncodeObject, GeneratedType } from "@cosmjs/proto-signing"

export const typeUrlMsgCreateDid = `/${protobufPackage}.MsgCreateDid`
export const typeUrlMsgCreateDidResponse = `/${protobufPackage}.MsgCreateDidResponse`
export const typeUrlMsgUpdateDid = `/${protobufPackage}.MsgUpdateDid`
export const typeUrlMsgUpdateDidResponse = `/${protobufPackage}.MsgUpdateDidResponse`

export interface MsgCreateDidEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgCreateDid,
readonly value: Partial<MsgCreateDid>
}

export function isMsgCreateDidEncodeObject(obj: EncodeObject): obj is MsgCreateDidEncodeObject {
return obj.typeUrl === typeUrlMsgCreateDid
}

export interface MsgCreateDidResponseEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgCreateDidResponse,
readonly value: Partial<MsgCreateDidResponse>
}

export function MsgCreateDidResponseEncodeObject(obj: EncodeObject): obj is MsgCreateDidResponseEncodeObject {
return obj.typeUrl === typeUrlMsgCreateDidResponse
}

export interface MsgUpdateDidEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgUpdateDid,
readonly value: Partial<MsgUpdateDid>
}

export function MsgUpdateDidEncodeObject(obj: EncodeObject): obj is MsgUpdateDidEncodeObject {
return obj.typeUrl === typeUrlMsgUpdateDid
}

export interface MsgUpdateDidResponseEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgUpdateDidResponse,
readonly value: Partial<MsgUpdateDidResponse>
}

export function MsgUpdateDidResponseEncodeObject(obj: EncodeObject): obj is MsgUpdateDidResponseEncodeObject {
return obj.typeUrl === typeUrlMsgUpdateDidResponse
}

export class DIDModule extends AbstractCheqdSDKModule {
readonly registryTypes: Iterable<[string, GeneratedType]>;
static readonly registryTypes: Iterable<[string, GeneratedType]> = [
[typeUrlMsgCreateDid, MsgCreateDid],
[typeUrlMsgCreateDidResponse, MsgCreateDidResponse],
[typeUrlMsgUpdateDid, MsgUpdateDid],
[typeUrlMsgUpdateDidResponse, MsgUpdateDidResponse],
]

constructor(signer: CheqdSigningStargateClient) {
super(signer)
this.methods = {
createDidTx: this.createDidTx.bind(this),
updateDidTx: this.updateDidTx.bind(this)
}

this.registryTypes = this.getRegistryTypes();
}

public getRegistryTypes(): Iterable<[string, GeneratedType]> {
return DIDModule.registryTypes
}

async createDidTx(signInputs: ISignInputs[], didPayload: Partial<MsgCreateDidPayload>, address: string, fee: DidStdFee | 'auto' | number, memo?: string, context?: IContext): Promise<DeliverTxResponse> {
if (!this._signer) {
this._signer = context!.sdk!.signer
Expand Down Expand Up @@ -75,15 +118,6 @@ export class DIDModule extends AbstractCheqdSDKModule {
memo
)
}

private getRegistryTypes(): Iterable<[string, GeneratedType]> {
return [
[typeUrlMsgCreateDid, MsgCreateDid],
[typeUrlMsgCreateDidResponse, MsgCreateDidResponse],
[typeUrlMsgUpdateDid, MsgUpdateDid],
[typeUrlMsgUpdateDidResponse, MsgUpdateDidResponse],
]
}
}

export type MinimalImportableDIDModule = MinimalImportableCheqdSDKModule<DIDModule>
Expand Down
3 changes: 1 addition & 2 deletions src/modules/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ export class ResourcesModule extends AbstractCheqdSDKModule {

constructor(signer: CheqdSigningStargateClient) {
super(signer)
this.registryTypes = this.getRegistryTypes()
}

private getRegistryTypes(): Iterable<[string, GeneratedType]> {
public getRegistryTypes(): Iterable<[string, GeneratedType]> {
return []
}
}
Expand Down
47 changes: 0 additions & 47 deletions src/registry.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,15 @@
import {
Registry,
GeneratedType,
EncodeObject
} from '@cosmjs/proto-signing'

import {
defaultRegistryTypes
} from '@cosmjs/stargate'

import {
MsgCreateDid, MsgCreateDidResponse, MsgUpdateDid, MsgUpdateDidResponse
} from '@cheqd/ts-proto/cheqd/v1/tx'

export const typeUrlMsgCreateDid = '/cheqdid.cheqdnode.cheqd.v1.MsgCreateDid'
export const typeUrlMsgCreateDidResponse = '/cheqdid.cheqdnode.cheqd.v1.MsgCreateDidResponse'
export const typeUrlMsgUpdateDid = '/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDid'
export const typeUrlMsgUpdateDidResponse = '/cheqdid.cheqdnode.cheqd.v1.MsgUpdateDidResponse'

export function createDefaultCheqdRegistry(customTypes?: Iterable<[string, GeneratedType]>): Registry {
if (!customTypes) customTypes = [];

return new Registry([...defaultRegistryTypes, ...customTypes])
}

export const CheqdRegistry = new Registry(defaultRegistryTypes)

export interface MsgCreateDidEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgCreateDid,
readonly value: Partial<MsgCreateDid>
}

export function isMsgCreateDidEncodeObject(obj: EncodeObject): obj is MsgCreateDidEncodeObject {
return obj.typeUrl === typeUrlMsgCreateDid
}

export interface MsgCreateDidResponseEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgCreateDidResponse,
readonly value: Partial<MsgCreateDidResponse>
}

export function MsgCreateDidResponseEncodeObject(obj: EncodeObject): obj is MsgCreateDidResponseEncodeObject {
return obj.typeUrl === typeUrlMsgCreateDidResponse
}

export interface MsgUpdateDidEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgUpdateDid,
readonly value: Partial<MsgUpdateDid>
}

export function MsgUpdateDidEncodeObject(obj: EncodeObject): obj is MsgUpdateDidEncodeObject {
return obj.typeUrl === typeUrlMsgUpdateDid
}

export interface MsgUpdateDidResponseEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgUpdateDidResponse,
readonly value: Partial<MsgUpdateDidResponse>
}

export function MsgUpdateDidResponseEncodeObject(obj: EncodeObject): obj is MsgUpdateDidResponseEncodeObject {
return obj.typeUrl === typeUrlMsgUpdateDidResponse
}
22 changes: 20 additions & 2 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'
import { DirectSecp256k1HdWallet, GeneratedType } from '@cosmjs/proto-signing'
import { createCheqdSDK, DIDModule, ICheqdSDKOptions } from '../src/index'
import { exampleCheqdNetwork, faucet } from './testutils.test'
import { AbstractCheqdSDKModule } from '../src/modules/_'
import { CheqdSigningStargateClient } from '../src/signer'
import { createDefaultCheqdRegistry } from '../src/registry'

describe(
'CheqdSDK', () => {
Expand All @@ -27,15 +28,18 @@ describe(
it('should use module methods', async () => {
const rpcUrl = exampleCheqdNetwork.rpcUrl
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic)
const testSigner = await CheqdSigningStargateClient.connectWithSigner(rpcUrl, wallet)

class TestModule extends AbstractCheqdSDKModule {
registryTypes: Iterable<[string, GeneratedType]> = []
methods = {
doSomething: this.doSomething.bind(this)
}
constructor(signer: CheqdSigningStargateClient) {
super(signer)
}
public getRegistryTypes(): Iterable<[string, GeneratedType]> {
return TestModule.registryTypes
}
async doSomething(): Promise<string> {
return 'did something'
}
Expand All @@ -58,6 +62,20 @@ describe(
await cheqdSDK.doSomething()
expect(spy).toHaveBeenCalled()
})

it('should instantiate registry from passed modules', async () => {
const options = {
modules: [DIDModule as unknown as AbstractCheqdSDKModule],
rpcUrl: exampleCheqdNetwork.rpcUrl,
wallet: await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic)
} as ICheqdSDKOptions
const cheqdSDK = await createCheqdSDK(options)

const didRegistryTypes = DIDModule.registryTypes
const cheqdRegistry = createDefaultCheqdRegistry(didRegistryTypes)

expect(cheqdSDK.signer.registry).toStrictEqual(cheqdRegistry)
})
})
}
)
13 changes: 9 additions & 4 deletions tests/modules/did.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"
import { DeliverTxResponse } from "@cosmjs/stargate"
import { fromString, toString } from 'uint8arrays'
import { DIDModule } from "../../src"
import { AbstractCheqdSDKModule } from "../../src/modules/_"
import { createDefaultCheqdRegistry } from "../../src/registry"
import { CheqdSigningStargateClient } from "../../src/signer"
import { DidStdFee, ISignInputs, MethodSpecificIdAlgo, VerificationMethods } from "../../src/types"
import { createDidPayload, createDidVerificationMethod, createKeyPairBase64, createVerificationKeys, exampleCheqdNetwork, faucet } from "../testutils.test"

const defaultAsyncTxTimeout = 10000
const defaultAsyncTxTimeout = 20000

describe('DIDModule', () => {
describe('constructor', () => {
Expand All @@ -22,7 +24,8 @@ describe('DIDModule', () => {
describe('createDidTx', () => {
it('should create a new multibase DID', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic, {prefix: faucet.prefix})
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet)
const registry = createDefaultCheqdRegistry(DIDModule.registryTypes)
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet, { registry })
const didModule = new DIDModule(signer)
const keyPair = createKeyPairBase64()
const verificationKeys = createVerificationKeys(keyPair, MethodSpecificIdAlgo.Base58, 'key-1', 16)
Expand Down Expand Up @@ -59,7 +62,8 @@ describe('DIDModule', () => {

it('should create a new uuid DID', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic, {prefix: faucet.prefix})
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet)
const registry = createDefaultCheqdRegistry(DIDModule.registryTypes)
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet, { registry })
const didModule = new DIDModule(signer)
const keyPair = createKeyPairBase64()
const verificationKeys = createVerificationKeys(keyPair, MethodSpecificIdAlgo.Uuid, 'key-1', 16)
Expand Down Expand Up @@ -98,7 +102,8 @@ describe('DIDModule', () => {
describe('updateDidTx', () => {
it('should update a DID', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic, {prefix: faucet.prefix})
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet)
const registry = createDefaultCheqdRegistry(DIDModule.registryTypes)
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet, { registry })
const didModule = new DIDModule(signer)

const keyPair = createKeyPairBase64()
Expand Down
2 changes: 1 addition & 1 deletion tests/signer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { VerificationMethod } from "@cheqd/ts-proto/cheqd/v1/did"
import { MsgCreateDid, MsgCreateDidPayload, SignInfo } from "@cheqd/ts-proto/cheqd/v1/tx"
import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing"
import { base64ToBytes, EdDSASigner } from "did-jwt"
import { typeUrlMsgCreateDid } from "../src/registry"
import { typeUrlMsgCreateDid } from '../src/modules/did'
import { CheqdSigningStargateClient } from "../src/signer"
import { ISignInputs, MethodSpecificIdAlgo, VerificationMethods } from "../src/types"
import { fromString, toString } from 'uint8arrays'
Expand Down

0 comments on commit 3d76466

Please sign in to comment.