Skip to content

Commit

Permalink
feat!: Added v3 core protocol support
Browse files Browse the repository at this point in the history
  • Loading branch information
Eengineer1 committed Nov 21, 2024
1 parent d9dbe56 commit 36936de
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 18 deletions.
32 changes: 21 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"README.md"
],
"dependencies": {
"@cheqd/ts-proto": "^3.4.4",
"@cheqd/ts-proto": "^4.0.0",
"@cosmjs/amino": "^0.32.4",
"@cosmjs/crypto": "^0.32.4",
"@cosmjs/encoding": "^0.32.4",
Expand Down
25 changes: 20 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { OfflineSigner, Registry } from '@cosmjs/proto-signing';
import { DIDModule, MinimalImportableDIDModule, DidExtension } from './modules/did.js';
import { MinimalImportableResourceModule, ResourceModule, ResourceExtension } from './modules/resource.js';
import { FeemarketModule, FeemarketExtension, MinimalImportableFeemarketModule } from './modules/feemarket.js';
import {
AbstractCheqdSDKModule,
applyMixins,
Expand All @@ -25,14 +26,16 @@ export interface ICheqdSDKOptions {
readonly wallet: OfflineSigner;
}

export type DefaultCheqdSDKModules = MinimalImportableDIDModule & MinimalImportableResourceModule;
export type DefaultCheqdSDKModules = MinimalImportableDIDModule &
MinimalImportableResourceModule &
MinimalImportableFeemarketModule;

export interface CheqdSDK extends DefaultCheqdSDKModules {}

export class CheqdSDK {
methods: IModuleMethodMap;
signer: CheqdSigningStargateClient;
querier: CheqdQuerier & DidExtension & ResourceExtension;
querier: CheqdQuerier & DidExtension & ResourceExtension & FeemarketExtension;
options: ICheqdSDKOptions;
private protectedMethods: string[] = ['constructor', 'build', 'loadModules', 'loadRegistry'];

Expand Down Expand Up @@ -92,12 +95,14 @@ export class CheqdSDK {
return createDefaultCheqdRegistry(registryTypes);
}

private async loadQuerierExtensions(): Promise<CheqdQuerier & DidExtension & ResourceExtension> {
private async loadQuerierExtensions(): Promise<
CheqdQuerier & DidExtension & ResourceExtension & FeemarketExtension
> {
const querierExtensions = this.options.modules.map((module) =>
instantiateCheqdSDKModuleQuerierExtensionSetup(module)
);
const querier = await CheqdQuerier.connectWithExtensions(this.options.rpcUrl, ...querierExtensions);
return <CheqdQuerier & DidExtension & ResourceExtension>querier;
return <CheqdQuerier & DidExtension & ResourceExtension & FeemarketExtension>querier;
}

async build(): Promise<CheqdSDK> {
Expand Down Expand Up @@ -133,7 +138,7 @@ export async function createCheqdSDK(options: ICheqdSDKOptions): Promise<CheqdSD
return await new CheqdSDK(options).build();
}

export { DIDModule, ResourceModule };
export { DIDModule, ResourceModule, FeemarketModule };
export { AbstractCheqdSDKModule, applyMixins } from './modules/_.js';
export {
DidExtension,
Expand Down Expand Up @@ -168,6 +173,16 @@ export {
setupResourceExtension,
isMsgCreateResourceEncodeObject,
} from './modules/resource.js';
export {
FeemarketExtension,
MinimalImportableFeemarketModule,
defaultFeemarketExtensionKey,
protobufLiterals as protobufLiteralsFeemarket,
setupFeemarketExtension,
isGasPriceEncodeObject,
isGasPricesEncodeObject,
isParamsEncodeObject,
} from './modules/feemarket.js';
export * from './signer.js';
export * from './querier.js';
export * from './registry.js';
Expand Down
1 change: 1 addition & 0 deletions src/modules/did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export const setupDidExtension = (base: QueryClient): DidExtension => {
};

export class DIDModule extends AbstractCheqdSDKModule {
// @ts-expect-error underlying type `GeneratedType` is intentionally wider
static readonly registryTypes: Iterable<[string, GeneratedType]> = [
[typeUrlMsgCreateDidDoc, MsgCreateDidDoc],
[typeUrlMsgCreateDidDocResponse, MsgCreateDidDocResponse],
Expand Down
131 changes: 131 additions & 0 deletions src/modules/feemarket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {
GasPriceResponse,
GasPricesResponse,
ParamsResponse,
QueryClientImpl,
protobufPackage,
} from '@cheqd/ts-proto/feemarket/feemarket/v1/index.js';
import { EncodeObject, GeneratedType } from '@cosmjs/proto-signing';
import { createProtobufRpcClient, QueryClient } from '@cosmjs/stargate';
import { AbstractCheqdSDKModule, MinimalImportableCheqdSDKModule } from './_';
import { IContext, QueryExtensionSetup } from '../types';
import { CheqdQuerier } from '../querier';
import { CheqdSigningStargateClient } from '../signer';

export const defaultFeemarketExtensionKey = 'feemarket' as const;

export const protobufLiterals = {
GasPriceResponse: 'GasPriceResponse',
GasPricesResponse: 'GasPricesResponse',
ParamsResponse: 'ParamsResponse',
} as const;

export const typeUrlGasPriceResponse = `/${protobufPackage}.${protobufLiterals.GasPriceResponse}`;
export const typeUrlGasPricesResponse = `/${protobufPackage}.${protobufLiterals.GasPricesResponse}`;
export const typeUrlParamsResponse = `/${protobufPackage}.${protobufLiterals.ParamsResponse}`;

export interface GasPriceEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlGasPriceResponse;
readonly value: Partial<GasPriceResponse>;
}

export function isGasPriceEncodeObject(obj: EncodeObject): obj is GasPriceEncodeObject {
return obj.typeUrl === typeUrlGasPriceResponse;
}

export interface GasPricesEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlGasPricesResponse;
readonly value: Partial<GasPricesResponse>;
}

export function isGasPricesEncodeObject(obj: EncodeObject): obj is GasPricesEncodeObject {
return obj.typeUrl === typeUrlGasPricesResponse;
}

export interface ParamsEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlParamsResponse;
readonly value: Partial<ParamsResponse>;
}

export function isParamsEncodeObject(obj: EncodeObject): obj is ParamsEncodeObject {
return obj.typeUrl === typeUrlParamsResponse;
}

export type MinimalImportableFeemarketModule = MinimalImportableCheqdSDKModule<FeemarketModule>;

export type FeemarketExtension = {
readonly [defaultFeemarketExtensionKey]: {
readonly gasPrice: (denom: string) => Promise<GasPriceResponse>;
readonly gasPrices: () => Promise<GasPricesResponse>;
readonly params: () => Promise<ParamsResponse>;
};
};

export const setupFeemarketExtension = (base: QueryClient): FeemarketExtension => {
const rpc = createProtobufRpcClient(base);

const queryService = new QueryClientImpl(rpc);

return {
[defaultFeemarketExtensionKey]: {
gasPrice: async (denom: string) => {
return queryService.GasPrice({ denom });
},
gasPrices: async () => {
return queryService.GasPrices({});
},
params: async () => {
return queryService.Params({});
},
},
};
};

export class FeemarketModule extends AbstractCheqdSDKModule {
// @ts-expect-error underlying type `GeneratedType` is intentionally wider
static readonly registryTypes: Iterable<[string, GeneratedType]> = [
[typeUrlGasPriceResponse, GasPriceResponse],
[typeUrlGasPricesResponse, GasPricesResponse],
[typeUrlParamsResponse, ParamsResponse],
];

static readonly querierExtensionSetup: QueryExtensionSetup<FeemarketExtension> = setupFeemarketExtension;

querier: CheqdQuerier & FeemarketExtension;

constructor(signer: CheqdSigningStargateClient, querier: CheqdQuerier & FeemarketExtension) {
super(signer, querier);
this.querier = querier;
this.methods = {
queryGasPrice: this.queryGasPrice.bind(this),
queryGasPrices: this.queryGasPrices.bind(this),
queryParams: this.queryParams.bind(this),
};
}

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

getQuerierExtensionSetup(): QueryExtensionSetup<FeemarketExtension> {
return FeemarketModule.querierExtensionSetup;
}

async queryGasPrice(denom: string, context?: IContext): Promise<GasPriceResponse> {
if (!this.querier) this.querier = context!.sdk!.querier;

return this.querier[defaultFeemarketExtensionKey].gasPrice(denom);
}

async queryGasPrices(context?: IContext): Promise<GasPricesResponse> {
if (!this.querier) this.querier = context!.sdk!.querier;

return this.querier[defaultFeemarketExtensionKey].gasPrices();
}

async queryParams(context?: IContext): Promise<ParamsResponse> {
if (!this.querier) this.querier = context!.sdk!.querier;

return this.querier[defaultFeemarketExtensionKey].params();
}
}
1 change: 1 addition & 0 deletions src/modules/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const setupResourceExtension = (base: QueryClient): ResourceExtension =>
};

export class ResourceModule extends AbstractCheqdSDKModule {
// @ts-expect-error underlying type `GeneratedType` is intentionally wider
static readonly registryTypes: Iterable<[string, GeneratedType]> = [
[typeUrlMsgCreateResource, MsgCreateResource],
[typeUrlMsgCreateResourceResponse, MsgCreateResourceResponse],
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { QueryClient } from '@cosmjs/stargate';
import { DIDResolutionResult } from 'did-resolver';
import { DidExtension } from './modules/did.js';
import { ResourceExtension } from './modules/resource.js';
import { FeemarketExtension } from './modules/feemarket.js';
export { DIDDocument, VerificationMethod, Service, ServiceEndpoint, JsonWebKey } from 'did-resolver';

export enum CheqdNetwork {
Expand All @@ -22,7 +23,7 @@ export type CheqdExtension<K extends string, V = any> = {
[P in K]: Record<P, V> & Partial<Record<Exclude<K, P>, never>> extends infer O ? { [Q in keyof O]: O[Q] } : never;
}[K];

export type CheqdExtensions = DidExtension | ResourceExtension;
export type CheqdExtensions = DidExtension | ResourceExtension | FeemarketExtension;

export interface IModuleMethod {
(...args: any[]): Promise<any>;
Expand Down
43 changes: 43 additions & 0 deletions tests/modules/feemarket.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { faucet, localnet } from '../testutils.test';
import { CheqdQuerier, CheqdSigningStargateClient, DIDModule } from '../../src';
import { FeemarketExtension, FeemarketModule, setupFeemarketExtension } from '../../src/modules/feemarket';

const defaultAsyncTxTimeout = 30000;

(BigInt.prototype as any).toJSON = function () {
return this.toString();
};

describe('FeemarketModule', () => {
describe('constructor', () => {
it('should instantiate standalone module', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const signer = await CheqdSigningStargateClient.connectWithSigner(localnet.rpcUrl, wallet);
const querier = (await CheqdQuerier.connectWithExtension(
localnet.rpcUrl,
setupFeemarketExtension
)) as CheqdQuerier & FeemarketExtension;
const feemarketModule = new FeemarketModule(signer, querier);
expect(feemarketModule).toBeInstanceOf(FeemarketModule);
});
});

describe('queryGasPrice', () => {
it('should query gas price', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const signer = await CheqdSigningStargateClient.connectWithSigner(localnet.rpcUrl, wallet);
const querier = (await CheqdQuerier.connectWithExtension(
localnet.rpcUrl,
setupFeemarketExtension
)) as CheqdQuerier & FeemarketExtension;
const feemarketModule = new FeemarketModule(signer, querier);
const gasPrice = await feemarketModule.queryGasPrice('ncheq');

expect(gasPrice).toBeDefined();
expect(gasPrice.price).toBeDefined();
expect(gasPrice.price!.denom).toEqual(DIDModule.baseMinimalDenom);
expect(Number(gasPrice.price!.amount)).toBeGreaterThan(0);
});
});
});
1 change: 1 addition & 0 deletions tests/signer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('CheqdSigningStargateClient', () => {
it('can be constructed with cheqd custom registry', async () => {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const registry = new Registry();
// @ts-expect-error underlying type `GeneratedType` is intentionally wider
registry.register(typeUrlMsgCreateDidDoc, MsgCreateDidDoc);
const signer = await CheqdSigningStargateClient.connectWithSigner(localnet.rpcUrl, wallet, { registry });
expect(signer.registry.lookupType(typeUrlMsgCreateDidDoc)).toBe(MsgCreateDidDoc);
Expand Down

0 comments on commit 36936de

Please sign in to comment.