Remove contract functionality from sdk38
This commit is contained in:
parent
9d054c6dd3
commit
54cff0367e
@ -76,7 +76,7 @@ describe("CosmosClient", () => {
|
||||
const height1 = await client.getHeight();
|
||||
expect(height1).toBeGreaterThan(0);
|
||||
|
||||
await client.getCodes(); // warm up the client
|
||||
await client.getAccount(guest.address); // warm up the client
|
||||
|
||||
const height2 = await client.getHeight();
|
||||
expect(height2).toBeGreaterThan(0);
|
||||
@ -85,7 +85,7 @@ describe("CosmosClient", () => {
|
||||
expect(height3).toEqual(height2 + 1);
|
||||
|
||||
expect(blockLatestSpy).toHaveBeenCalledTimes(1);
|
||||
expect(authAccountsSpy).toHaveBeenCalledTimes(2);
|
||||
expect(authAccountsSpy).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
@ -232,65 +232,4 @@ describe("CosmosClient", () => {
|
||||
expect(transactionHash).toMatch(/^[0-9A-F]{64}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getContracts", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmosClient(wasmd.endpoint);
|
||||
const result = await client.getContracts(1);
|
||||
expect(result.length).toBeGreaterThanOrEqual(3);
|
||||
const [hash, isa, jade] = result;
|
||||
expect(hash).toEqual({
|
||||
address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5",
|
||||
codeId: 1,
|
||||
creator: faucet.address,
|
||||
label: "HASH",
|
||||
});
|
||||
expect(isa).toEqual({
|
||||
address: "cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd",
|
||||
codeId: 1,
|
||||
creator: faucet.address,
|
||||
label: "ISA",
|
||||
});
|
||||
expect(jade).toEqual({
|
||||
address: "cosmos18r5szma8hm93pvx6lwpjwyxruw27e0k5uw835c",
|
||||
codeId: 1,
|
||||
creator: faucet.address,
|
||||
label: "JADE",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getContract", () => {
|
||||
it("works for HASH instance", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmosClient(wasmd.endpoint);
|
||||
const hash = await client.getContract("cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5");
|
||||
expect(hash).toEqual({
|
||||
address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5",
|
||||
codeId: 1,
|
||||
creator: faucet.address,
|
||||
label: "HASH",
|
||||
initMsg: {
|
||||
decimals: 5,
|
||||
name: "Hash token",
|
||||
symbol: "HASH",
|
||||
initial_balances: jasmine.arrayContaining([
|
||||
{
|
||||
address: faucet.address,
|
||||
amount: "11",
|
||||
},
|
||||
{
|
||||
address: unused.address,
|
||||
amount: "12812345",
|
||||
},
|
||||
{
|
||||
address: guest.address,
|
||||
amount: "22004000000",
|
||||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { Coin } from "./coins";
|
||||
import { Log, parseLogs } from "./logs";
|
||||
import { decodeBech32Pubkey } from "./pubkey";
|
||||
import { BroadcastMode, RestClient } from "./restclient";
|
||||
import { CosmosSdkTx, JsonObject, PubKey, StdTx } from "./types";
|
||||
import { CosmosSdkTx, PubKey, StdTx } from "./types";
|
||||
|
||||
export interface GetNonceResult {
|
||||
readonly accountNumber: number;
|
||||
@ -75,34 +75,6 @@ export interface SearchTxFilter {
|
||||
readonly maxHeight?: number;
|
||||
}
|
||||
|
||||
export interface Code {
|
||||
readonly id: number;
|
||||
/** Bech32 account address */
|
||||
readonly creator: string;
|
||||
/** Hex-encoded sha256 hash of the code stored here */
|
||||
readonly checksum: string;
|
||||
readonly source?: string;
|
||||
readonly builder?: string;
|
||||
}
|
||||
|
||||
export interface CodeDetails extends Code {
|
||||
/** The original wasm bytes */
|
||||
readonly data: Uint8Array;
|
||||
}
|
||||
|
||||
export interface Contract {
|
||||
readonly address: string;
|
||||
readonly codeId: number;
|
||||
/** Bech32 account address */
|
||||
readonly creator: string;
|
||||
readonly label: string;
|
||||
}
|
||||
|
||||
export interface ContractDetails extends Contract {
|
||||
/** Argument passed on initialization of the contract */
|
||||
readonly initMsg: object;
|
||||
}
|
||||
|
||||
/** A transaction that is indexed as part of the transaction history */
|
||||
export interface IndexedTx {
|
||||
readonly height: number;
|
||||
@ -150,7 +122,6 @@ export class CosmosClient {
|
||||
/** Any address the chain considers valid (valid bech32 with proper prefix) */
|
||||
protected anyValidAddress: string | undefined;
|
||||
|
||||
private readonly codesCache = new Map<number, CodeDetails>();
|
||||
private chainId: string | undefined;
|
||||
|
||||
/**
|
||||
@ -318,102 +289,6 @@ export class CosmosClient {
|
||||
};
|
||||
}
|
||||
|
||||
public async getCodes(): Promise<readonly Code[]> {
|
||||
const result = await this.restClient.listCodeInfo();
|
||||
return result.map(
|
||||
(entry): Code => {
|
||||
this.anyValidAddress = entry.creator;
|
||||
return {
|
||||
id: entry.id,
|
||||
creator: entry.creator,
|
||||
checksum: Encoding.toHex(Encoding.fromHex(entry.data_hash)),
|
||||
source: entry.source || undefined,
|
||||
builder: entry.builder || undefined,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async getCodeDetails(codeId: number): Promise<CodeDetails> {
|
||||
const cached = this.codesCache.get(codeId);
|
||||
if (cached) return cached;
|
||||
|
||||
const getCodeResult = await this.restClient.getCode(codeId);
|
||||
const codeDetails: CodeDetails = {
|
||||
id: getCodeResult.id,
|
||||
creator: getCodeResult.creator,
|
||||
checksum: Encoding.toHex(Encoding.fromHex(getCodeResult.data_hash)),
|
||||
source: getCodeResult.source || undefined,
|
||||
builder: getCodeResult.builder || undefined,
|
||||
data: Encoding.fromBase64(getCodeResult.data),
|
||||
};
|
||||
this.codesCache.set(codeId, codeDetails);
|
||||
return codeDetails;
|
||||
}
|
||||
|
||||
public async getContracts(codeId: number): Promise<readonly Contract[]> {
|
||||
const result = await this.restClient.listContractsByCodeId(codeId);
|
||||
return result.map(
|
||||
(entry): Contract => ({
|
||||
address: entry.address,
|
||||
codeId: entry.code_id,
|
||||
creator: entry.creator,
|
||||
label: entry.label,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error if no contract was found at the address
|
||||
*/
|
||||
public async getContract(address: string): Promise<ContractDetails> {
|
||||
const result = await this.restClient.getContractInfo(address);
|
||||
if (!result) throw new Error(`No contract found at address "${address}"`);
|
||||
return {
|
||||
address: result.address,
|
||||
codeId: result.code_id,
|
||||
creator: result.creator,
|
||||
label: result.label,
|
||||
initMsg: result.init_msg,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data at the key if present (raw contract dependent storage data)
|
||||
* or null if no data at this key.
|
||||
*
|
||||
* Promise is rejected when contract does not exist.
|
||||
*/
|
||||
public async queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null> {
|
||||
// just test contract existence
|
||||
const _info = await this.getContract(address);
|
||||
|
||||
return this.restClient.queryContractRaw(address, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a smart query on the contract, returns the parsed JSON document.
|
||||
*
|
||||
* Promise is rejected when contract does not exist.
|
||||
* Promise is rejected for invalid query format.
|
||||
* Promise is rejected for invalid response format.
|
||||
*/
|
||||
public async queryContractSmart(address: string, queryMsg: object): Promise<JsonObject> {
|
||||
try {
|
||||
return await this.restClient.queryContractSmart(address, queryMsg);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
if (error.message.startsWith("not found: contract")) {
|
||||
throw new Error(`No contract found at address "${address}"`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async txsQuery(query: string): Promise<readonly IndexedTx[]> {
|
||||
// TODO: we need proper pagination support
|
||||
const limit = 100;
|
||||
|
||||
@ -8,10 +8,6 @@ export {
|
||||
Account,
|
||||
Block,
|
||||
BlockHeader,
|
||||
Code,
|
||||
CodeDetails,
|
||||
Contract,
|
||||
ContractDetails,
|
||||
CosmosClient,
|
||||
GetNonceResult,
|
||||
IndexedTx,
|
||||
|
||||
@ -2,9 +2,7 @@ import { Encoding, isNonNullObject } from "@iov/encoding";
|
||||
import axios, { AxiosError, AxiosInstance } from "axios";
|
||||
|
||||
import { Coin } from "./coins";
|
||||
import { CosmosSdkTx, JsonObject, Model, parseWasmData, StdTx, WasmData } from "./types";
|
||||
|
||||
const { fromBase64, fromUtf8, toHex, toUtf8 } = Encoding;
|
||||
import { CosmosSdkTx, StdTx } from "./types";
|
||||
|
||||
export interface CosmosSdkAccount {
|
||||
/** Bech32 account address */
|
||||
@ -210,13 +208,6 @@ type RestClientResponse =
|
||||
| WasmResponse<ContractInfo[] | null>
|
||||
| WasmResponse<ContractDetails | null>;
|
||||
|
||||
/** Unfortunately, Cosmos SDK encodes empty arrays as null */
|
||||
type CosmosSdkArray<T> = ReadonlyArray<T> | null;
|
||||
|
||||
function normalizeArray<T>(backend: CosmosSdkArray<T>): ReadonlyArray<T> {
|
||||
return backend || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* The mode used to send transaction
|
||||
*
|
||||
@ -231,17 +222,6 @@ export enum BroadcastMode {
|
||||
Async = "async",
|
||||
}
|
||||
|
||||
function isWasmError<T>(resp: WasmResponse<T>): resp is WasmError {
|
||||
return (resp as WasmError).error !== undefined;
|
||||
}
|
||||
|
||||
function unwrapWasmResponse<T>(response: WasmResponse<T>): T {
|
||||
if (isWasmError(response)) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
return response.result;
|
||||
}
|
||||
|
||||
// We want to get message data from 500 errors
|
||||
// https://stackoverflow.com/questions/56577124/how-to-handle-500-error-message-with-axios
|
||||
// this should be chained to catch one error and throw a more informative one
|
||||
@ -391,67 +371,4 @@ export class RestClient {
|
||||
}
|
||||
return responseData as PostTxsResponse;
|
||||
}
|
||||
|
||||
// The /wasm endpoints
|
||||
|
||||
// wasm rest queries are listed here: https://github.com/cosmwasm/wasmd/blob/master/x/wasm/client/rest/query.go#L19-L27
|
||||
public async listCodeInfo(): Promise<readonly CodeInfo[]> {
|
||||
const path = `/wasm/code`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<CosmosSdkArray<CodeInfo>>;
|
||||
return normalizeArray(unwrapWasmResponse(responseData));
|
||||
}
|
||||
|
||||
// this will download the original wasm bytecode by code id
|
||||
// throws error if no code with this id
|
||||
public async getCode(id: number): Promise<CodeDetails> {
|
||||
const path = `/wasm/code/${id}`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<CodeDetails>;
|
||||
return unwrapWasmResponse(responseData);
|
||||
}
|
||||
|
||||
public async listContractsByCodeId(id: number): Promise<readonly ContractInfo[]> {
|
||||
const path = `/wasm/code/${id}/contracts`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<CosmosSdkArray<ContractInfo>>;
|
||||
return normalizeArray(unwrapWasmResponse(responseData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null when contract was not found at this address.
|
||||
*/
|
||||
public async getContractInfo(address: string): Promise<ContractDetails | null> {
|
||||
const path = `/wasm/contract/${address}`;
|
||||
const response = (await this.get(path)) as WasmResponse<ContractDetails | null>;
|
||||
return unwrapWasmResponse(response);
|
||||
}
|
||||
|
||||
// Returns all contract state.
|
||||
// This is an empty array if no such contract, or contract has no data.
|
||||
public async getAllContractState(address: string): Promise<readonly Model[]> {
|
||||
const path = `/wasm/contract/${address}/state`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<CosmosSdkArray<WasmData>>;
|
||||
return normalizeArray(unwrapWasmResponse(responseData)).map(parseWasmData);
|
||||
}
|
||||
|
||||
// Returns the data at the key if present (unknown decoded json),
|
||||
// or null if no data at this (contract address, key) pair
|
||||
public async queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null> {
|
||||
const hexKey = toHex(key);
|
||||
const path = `/wasm/contract/${address}/raw/${hexKey}?encoding=hex`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<WasmData[]>;
|
||||
const data = unwrapWasmResponse(responseData);
|
||||
return data.length === 0 ? null : fromBase64(data[0].val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a smart query on the contract and parses the reponse as JSON.
|
||||
* Throws error if no such contract exists, the query format is invalid or the response is invalid.
|
||||
*/
|
||||
public async queryContractSmart(address: string, query: object): Promise<JsonObject> {
|
||||
const encoded = toHex(toUtf8(JSON.stringify(query)));
|
||||
const path = `/wasm/contract/${address}/smart/${encoded}?encoding=hex`;
|
||||
const responseData = (await this.get(path)) as WasmResponse<SmartQueryResponse>;
|
||||
const result = unwrapWasmResponse(responseData);
|
||||
// By convention, smart queries must return a valid JSON document (see https://github.com/CosmWasm/cosmwasm/issues/144)
|
||||
return JSON.parse(fromUtf8(fromBase64(result.smart)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import { Coin } from "./coins";
|
||||
|
||||
const { fromBase64, fromHex } = Encoding;
|
||||
|
||||
/** An Amino/Cosmos SDK StdTx */
|
||||
export interface StdTx {
|
||||
readonly msg: ReadonlyArray<Msg>;
|
||||
@ -75,29 +71,3 @@ export const pubkeyType = {
|
||||
};
|
||||
|
||||
export const pubkeyTypes: readonly string[] = [pubkeyType.secp256k1, pubkeyType.ed25519, pubkeyType.sr25519];
|
||||
|
||||
export interface WasmData {
|
||||
// key is hex-encoded
|
||||
readonly key: string;
|
||||
// value is base64 encoded
|
||||
readonly val: string;
|
||||
}
|
||||
|
||||
// Model is a parsed WasmData object
|
||||
export interface Model {
|
||||
readonly key: Uint8Array;
|
||||
readonly val: Uint8Array;
|
||||
}
|
||||
|
||||
export function parseWasmData({ key, val }: WasmData): Model {
|
||||
return {
|
||||
key: fromHex(key),
|
||||
val: fromBase64(val),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing a parsed JSON document. The result of JSON.parse().
|
||||
* This doen't privide any type safety over `any` but expresses intent in the code.
|
||||
*/
|
||||
export type JsonObject = any;
|
||||
|
||||
49
packages/sdk38/types/cosmosclient.d.ts
vendored
49
packages/sdk38/types/cosmosclient.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
import { Coin } from "./coins";
|
||||
import { Log } from "./logs";
|
||||
import { BroadcastMode, RestClient } from "./restclient";
|
||||
import { CosmosSdkTx, JsonObject, PubKey, StdTx } from "./types";
|
||||
import { CosmosSdkTx, PubKey, StdTx } from "./types";
|
||||
export interface GetNonceResult {
|
||||
readonly accountNumber: number;
|
||||
readonly sequence: number;
|
||||
@ -48,30 +48,6 @@ export interface SearchTxFilter {
|
||||
readonly minHeight?: number;
|
||||
readonly maxHeight?: number;
|
||||
}
|
||||
export interface Code {
|
||||
readonly id: number;
|
||||
/** Bech32 account address */
|
||||
readonly creator: string;
|
||||
/** Hex-encoded sha256 hash of the code stored here */
|
||||
readonly checksum: string;
|
||||
readonly source?: string;
|
||||
readonly builder?: string;
|
||||
}
|
||||
export interface CodeDetails extends Code {
|
||||
/** The original wasm bytes */
|
||||
readonly data: Uint8Array;
|
||||
}
|
||||
export interface Contract {
|
||||
readonly address: string;
|
||||
readonly codeId: number;
|
||||
/** Bech32 account address */
|
||||
readonly creator: string;
|
||||
readonly label: string;
|
||||
}
|
||||
export interface ContractDetails extends Contract {
|
||||
/** Argument passed on initialization of the contract */
|
||||
readonly initMsg: object;
|
||||
}
|
||||
/** A transaction that is indexed as part of the transaction history */
|
||||
export interface IndexedTx {
|
||||
readonly height: number;
|
||||
@ -114,7 +90,6 @@ export declare class CosmosClient {
|
||||
protected readonly restClient: RestClient;
|
||||
/** Any address the chain considers valid (valid bech32 with proper prefix) */
|
||||
protected anyValidAddress: string | undefined;
|
||||
private readonly codesCache;
|
||||
private chainId;
|
||||
/**
|
||||
* Creates a new client to interact with a CosmWasm blockchain.
|
||||
@ -149,27 +124,5 @@ export declare class CosmosClient {
|
||||
getBlock(height?: number): Promise<Block>;
|
||||
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
|
||||
postTx(tx: StdTx): Promise<PostTxResult>;
|
||||
getCodes(): Promise<readonly Code[]>;
|
||||
getCodeDetails(codeId: number): Promise<CodeDetails>;
|
||||
getContracts(codeId: number): Promise<readonly Contract[]>;
|
||||
/**
|
||||
* Throws an error if no contract was found at the address
|
||||
*/
|
||||
getContract(address: string): Promise<ContractDetails>;
|
||||
/**
|
||||
* Returns the data at the key if present (raw contract dependent storage data)
|
||||
* or null if no data at this key.
|
||||
*
|
||||
* Promise is rejected when contract does not exist.
|
||||
*/
|
||||
queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null>;
|
||||
/**
|
||||
* Makes a smart query on the contract, returns the parsed JSON document.
|
||||
*
|
||||
* Promise is rejected when contract does not exist.
|
||||
* Promise is rejected for invalid query format.
|
||||
* Promise is rejected for invalid response format.
|
||||
*/
|
||||
queryContractSmart(address: string, queryMsg: object): Promise<JsonObject>;
|
||||
private txsQuery;
|
||||
}
|
||||
|
||||
4
packages/sdk38/types/index.d.ts
vendored
4
packages/sdk38/types/index.d.ts
vendored
@ -6,10 +6,6 @@ export {
|
||||
Account,
|
||||
Block,
|
||||
BlockHeader,
|
||||
Code,
|
||||
CodeDetails,
|
||||
Contract,
|
||||
ContractDetails,
|
||||
CosmosClient,
|
||||
GetNonceResult,
|
||||
IndexedTx,
|
||||
|
||||
16
packages/sdk38/types/restclient.d.ts
vendored
16
packages/sdk38/types/restclient.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import { Coin } from "./coins";
|
||||
import { CosmosSdkTx, JsonObject, Model, StdTx } from "./types";
|
||||
import { CosmosSdkTx, StdTx } from "./types";
|
||||
export interface CosmosSdkAccount {
|
||||
/** Bech32 account address */
|
||||
readonly address: string;
|
||||
@ -213,19 +213,5 @@ export declare class RestClient {
|
||||
* @param tx a signed transaction as StdTx (i.e. not wrapped in type/value container)
|
||||
*/
|
||||
postTx(tx: StdTx): Promise<PostTxsResponse>;
|
||||
listCodeInfo(): Promise<readonly CodeInfo[]>;
|
||||
getCode(id: number): Promise<CodeDetails>;
|
||||
listContractsByCodeId(id: number): Promise<readonly ContractInfo[]>;
|
||||
/**
|
||||
* Returns null when contract was not found at this address.
|
||||
*/
|
||||
getContractInfo(address: string): Promise<ContractDetails | null>;
|
||||
getAllContractState(address: string): Promise<readonly Model[]>;
|
||||
queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null>;
|
||||
/**
|
||||
* Makes a smart query on the contract and parses the reponse as JSON.
|
||||
* Throws error if no such contract exists, the query format is invalid or the response is invalid.
|
||||
*/
|
||||
queryContractSmart(address: string, query: object): Promise<JsonObject>;
|
||||
}
|
||||
export {};
|
||||
|
||||
14
packages/sdk38/types/types.d.ts
vendored
14
packages/sdk38/types/types.d.ts
vendored
@ -48,17 +48,3 @@ export declare const pubkeyType: {
|
||||
sr25519: "tendermint/PubKeySr25519";
|
||||
};
|
||||
export declare const pubkeyTypes: readonly string[];
|
||||
export interface WasmData {
|
||||
readonly key: string;
|
||||
readonly val: string;
|
||||
}
|
||||
export interface Model {
|
||||
readonly key: Uint8Array;
|
||||
readonly val: Uint8Array;
|
||||
}
|
||||
export declare function parseWasmData({ key, val }: WasmData): Model;
|
||||
/**
|
||||
* An object containing a parsed JSON document. The result of JSON.parse().
|
||||
* This doen't privide any type safety over `any` but expresses intent in the code.
|
||||
*/
|
||||
export declare type JsonObject = any;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user