Create query client
This commit is contained in:
parent
0dc22c2525
commit
01506951e7
183
packages/stargate/src/queryclient.ts
Normal file
183
packages/stargate/src/queryclient.ts
Normal file
@ -0,0 +1,183 @@
|
||||
/* eslint-disable no-dupe-class-members, @typescript-eslint/ban-types, @typescript-eslint/naming-convention */
|
||||
import { toHex } from "@cosmjs/encoding";
|
||||
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
||||
import { arrayContentEquals, assert, isNonNullObject } from "@cosmjs/utils";
|
||||
|
||||
type QueryExtensionSetup<P> = (base: QueryClient) => P;
|
||||
|
||||
export class QueryClient {
|
||||
/** Constructs a QueryClient with 0 extensions */
|
||||
public static withExtensions(tmClient: TendermintClient): QueryClient;
|
||||
|
||||
/** Constructs a QueryClient with 1 extension */
|
||||
public static withExtensions<A extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
): QueryClient & A;
|
||||
|
||||
/** Constructs a QueryClient with 2 extensions */
|
||||
public static withExtensions<A extends object, B extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
): QueryClient & A & B;
|
||||
|
||||
/** Constructs a QueryClient with 3 extensions */
|
||||
public static withExtensions<A extends object, B extends object, C extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
): QueryClient & A & B & C;
|
||||
|
||||
/** Constructs a QueryClient with 4 extensions */
|
||||
public static withExtensions<A extends object, B extends object, C extends object, D extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
): QueryClient & A & B & C & D;
|
||||
|
||||
/** Constructs a QueryClient with 5 extensions */
|
||||
public static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
): QueryClient & A & B & C & D & E;
|
||||
|
||||
/** Constructs a QueryClient with 6 extensions */
|
||||
public static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
): QueryClient & A & B & C & D & E & F;
|
||||
|
||||
/** Constructs a QueryClient with 7 extensions */
|
||||
public static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object,
|
||||
G extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
setupExtensionG: QueryExtensionSetup<G>,
|
||||
): QueryClient & A & B & C & D & E & F & G;
|
||||
|
||||
/** Constructs a QueryClient with 8 extensions */
|
||||
public static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object,
|
||||
G extends object,
|
||||
H extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
setupExtensionG: QueryExtensionSetup<G>,
|
||||
setupExtensionH: QueryExtensionSetup<H>,
|
||||
): QueryClient & A & B & C & D & E & F & G & H;
|
||||
|
||||
public static withExtensions(
|
||||
tmClient: TendermintClient,
|
||||
...extensionSetups: Array<QueryExtensionSetup<object>>
|
||||
): any {
|
||||
const client = new QueryClient(tmClient);
|
||||
const extensions = extensionSetups.map((setupExtension) => setupExtension(client));
|
||||
for (const extension of extensions) {
|
||||
assert(isNonNullObject(extension), `Extension must be a non-null object`);
|
||||
for (const [moduleKey, moduleValue] of Object.entries(extension)) {
|
||||
assert(
|
||||
isNonNullObject(moduleValue),
|
||||
`Module must be a non-null object. Found type ${typeof moduleValue} for module "${moduleKey}".`,
|
||||
);
|
||||
const current = (client as any)[moduleKey] || {};
|
||||
(client as any)[moduleKey] = {
|
||||
...current,
|
||||
...moduleValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
private readonly tmClient: TendermintClient;
|
||||
|
||||
public constructor(tmClient: TendermintClient) {
|
||||
this.tmClient = tmClient;
|
||||
}
|
||||
|
||||
public async queryVerified(store: string, key: Uint8Array): Promise<Uint8Array> {
|
||||
const response = await this.tmClient.abciQuery({
|
||||
// we need the StoreKey for the module, not the module name
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L12
|
||||
path: `/store/${store}/key`,
|
||||
data: key,
|
||||
prove: true,
|
||||
});
|
||||
|
||||
if (response.code) {
|
||||
throw new Error(`Query failed with (${response.code}): ${response.log}`);
|
||||
}
|
||||
|
||||
if (!arrayContentEquals(response.key, key)) {
|
||||
throw new Error(`Response key ${toHex(response.key)} doesn't match query key ${toHex(key)}`);
|
||||
}
|
||||
|
||||
// TODO: implement proof verification
|
||||
// https://github.com/CosmWasm/cosmjs/issues/347
|
||||
|
||||
return response.value;
|
||||
}
|
||||
|
||||
public async queryUnverified(path: string, request: Uint8Array): Promise<Uint8Array> {
|
||||
const response = await this.tmClient.abciQuery({
|
||||
path: path,
|
||||
data: request,
|
||||
prove: false,
|
||||
});
|
||||
|
||||
if (response.code) {
|
||||
throw new Error(`Query failed with (${response.code}): ${response.log}`);
|
||||
}
|
||||
|
||||
return response.value;
|
||||
}
|
||||
}
|
||||
@ -13,10 +13,11 @@ import {
|
||||
import { Uint53, Uint64 } from "@cosmjs/math";
|
||||
import { decodeAny } from "@cosmjs/proto-signing";
|
||||
import { broadcastTxCommitSuccess, Client as TendermintClient, QueryString } from "@cosmjs/tendermint-rpc";
|
||||
import { arrayContentEquals, assert, assertDefined } from "@cosmjs/utils";
|
||||
import { assert, assertDefined } from "@cosmjs/utils";
|
||||
import Long from "long";
|
||||
|
||||
import { cosmos } from "./generated/codecimpl";
|
||||
import { QueryClient } from "./queryclient";
|
||||
|
||||
/** A transaction that is indexed as part of the transaction history */
|
||||
export interface IndexedTx {
|
||||
@ -114,6 +115,7 @@ export interface PrivateStargateClient {
|
||||
|
||||
export class StargateClient {
|
||||
private readonly tmClient: TendermintClient;
|
||||
private readonly queryClient: QueryClient;
|
||||
private chainId: string | undefined;
|
||||
|
||||
public static async connect(endpoint: string): Promise<StargateClient> {
|
||||
@ -123,6 +125,7 @@ export class StargateClient {
|
||||
|
||||
private constructor(tmClient: TendermintClient) {
|
||||
this.tmClient = tmClient;
|
||||
this.queryClient = QueryClient.withExtensions(tmClient);
|
||||
}
|
||||
|
||||
public async getChainId(): Promise<string> {
|
||||
@ -145,7 +148,7 @@ export class StargateClient {
|
||||
const { prefix, data: binAddress } = Bech32.decode(searchAddress);
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L29-L32
|
||||
const accountKey = Uint8Array.from([0x01, ...binAddress]);
|
||||
const responseData = await this.queryVerified("acc", accountKey);
|
||||
const responseData = await this.queryClient.queryVerified("acc", accountKey);
|
||||
|
||||
if (responseData.length === 0) return null;
|
||||
|
||||
@ -198,7 +201,7 @@ export class StargateClient {
|
||||
const binAddress = Bech32.decode(address).data;
|
||||
const bankKey = Uint8Array.from([...toAscii("balances"), ...binAddress, ...toAscii(searchDenom)]);
|
||||
|
||||
const responseData = await this.queryVerified("bank", bankKey);
|
||||
const responseData = await this.queryClient.queryVerified("bank", bankKey);
|
||||
const { amount, denom } = cosmos.Coin.decode(responseData);
|
||||
if (denom === "") {
|
||||
return null;
|
||||
@ -221,7 +224,7 @@ export class StargateClient {
|
||||
const request = cosmos.bank.QueryAllBalancesRequest.encode({
|
||||
address: Bech32.decode(address).data,
|
||||
}).finish();
|
||||
const responseData = await this.queryUnverified(path, request);
|
||||
const responseData = await this.queryClient.queryUnverified(path, request);
|
||||
const response = cosmos.bank.QueryAllBalancesResponse.decode(responseData);
|
||||
return response.balances.map(coinFromProto);
|
||||
}
|
||||
@ -280,43 +283,6 @@ export class StargateClient {
|
||||
};
|
||||
}
|
||||
|
||||
private async queryVerified(store: string, key: Uint8Array): Promise<Uint8Array> {
|
||||
const response = await this.tmClient.abciQuery({
|
||||
// we need the StoreKey for the module, not the module name
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L12
|
||||
path: `/store/${store}/key`,
|
||||
data: key,
|
||||
prove: true,
|
||||
});
|
||||
|
||||
if (response.code) {
|
||||
throw new Error(`Query failed with (${response.code}): ${response.log}`);
|
||||
}
|
||||
|
||||
if (!arrayContentEquals(response.key, key)) {
|
||||
throw new Error(`Response key ${toHex(response.key)} doesn't match query key ${toHex(key)}`);
|
||||
}
|
||||
|
||||
// TODO: implement proof verification
|
||||
// https://github.com/CosmWasm/cosmjs/issues/347
|
||||
|
||||
return response.value;
|
||||
}
|
||||
|
||||
private async queryUnverified(path: string, request: Uint8Array): Promise<Uint8Array> {
|
||||
const response = await this.tmClient.abciQuery({
|
||||
path: path,
|
||||
data: request,
|
||||
prove: false,
|
||||
});
|
||||
|
||||
if (response.code) {
|
||||
throw new Error(`Query failed with (${response.code}): ${response.log}`);
|
||||
}
|
||||
|
||||
return response.value;
|
||||
}
|
||||
|
||||
private async txsQuery(query: string): Promise<readonly IndexedTx[]> {
|
||||
const params = {
|
||||
query: query as QueryString,
|
||||
|
||||
109
packages/stargate/types/queryclient.d.ts
vendored
Normal file
109
packages/stargate/types/queryclient.d.ts
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
||||
declare type QueryExtensionSetup<P> = (base: QueryClient) => P;
|
||||
export declare class QueryClient {
|
||||
/** Constructs a QueryClient with 0 extensions */
|
||||
static withExtensions(tmClient: TendermintClient): QueryClient;
|
||||
/** Constructs a QueryClient with 1 extension */
|
||||
static withExtensions<A extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
): QueryClient & A;
|
||||
/** Constructs a QueryClient with 2 extensions */
|
||||
static withExtensions<A extends object, B extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
): QueryClient & A & B;
|
||||
/** Constructs a QueryClient with 3 extensions */
|
||||
static withExtensions<A extends object, B extends object, C extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
): QueryClient & A & B & C;
|
||||
/** Constructs a QueryClient with 4 extensions */
|
||||
static withExtensions<A extends object, B extends object, C extends object, D extends object>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
): QueryClient & A & B & C & D;
|
||||
/** Constructs a QueryClient with 5 extensions */
|
||||
static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
): QueryClient & A & B & C & D & E;
|
||||
/** Constructs a QueryClient with 6 extensions */
|
||||
static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
): QueryClient & A & B & C & D & E & F;
|
||||
/** Constructs a QueryClient with 7 extensions */
|
||||
static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object,
|
||||
G extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
setupExtensionG: QueryExtensionSetup<G>,
|
||||
): QueryClient & A & B & C & D & E & F & G;
|
||||
/** Constructs a QueryClient with 8 extensions */
|
||||
static withExtensions<
|
||||
A extends object,
|
||||
B extends object,
|
||||
C extends object,
|
||||
D extends object,
|
||||
E extends object,
|
||||
F extends object,
|
||||
G extends object,
|
||||
H extends object
|
||||
>(
|
||||
tmClient: TendermintClient,
|
||||
setupExtensionA: QueryExtensionSetup<A>,
|
||||
setupExtensionB: QueryExtensionSetup<B>,
|
||||
setupExtensionC: QueryExtensionSetup<C>,
|
||||
setupExtensionD: QueryExtensionSetup<D>,
|
||||
setupExtensionE: QueryExtensionSetup<E>,
|
||||
setupExtensionF: QueryExtensionSetup<F>,
|
||||
setupExtensionG: QueryExtensionSetup<G>,
|
||||
setupExtensionH: QueryExtensionSetup<H>,
|
||||
): QueryClient & A & B & C & D & E & F & G & H;
|
||||
private readonly tmClient;
|
||||
constructor(tmClient: TendermintClient);
|
||||
queryVerified(store: string, key: Uint8Array): Promise<Uint8Array>;
|
||||
queryUnverified(path: string, request: Uint8Array): Promise<Uint8Array>;
|
||||
}
|
||||
export {};
|
||||
3
packages/stargate/types/stargateclient.d.ts
vendored
3
packages/stargate/types/stargateclient.d.ts
vendored
@ -49,6 +49,7 @@ export interface PrivateStargateClient {
|
||||
}
|
||||
export declare class StargateClient {
|
||||
private readonly tmClient;
|
||||
private readonly queryClient;
|
||||
private chainId;
|
||||
static connect(endpoint: string): Promise<StargateClient>;
|
||||
private constructor();
|
||||
@ -68,7 +69,5 @@ export declare class StargateClient {
|
||||
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
|
||||
disconnect(): void;
|
||||
broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse>;
|
||||
private queryVerified;
|
||||
private queryUnverified;
|
||||
private txsQuery;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user