Merge pull request #121 from confio/code-and-contracts

Add code and contract getters to CosmWasmClient
This commit is contained in:
Simon Warta 2020-02-24 13:50:55 +01:00 committed by GitHub
commit 19f73b432d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 266 additions and 59 deletions

View File

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
import { Sha256 } from "@iov/crypto";
import { Bech32, Encoding } from "@iov/encoding";
import { assert, sleep } from "@iov/utils";
import { ReadonlyDate } from "readonly-date";
@ -19,7 +20,7 @@ import {
} from "./testutils.spec";
import { CosmosSdkTx, MsgSend, StdFee } from "./types";
const { fromAscii, fromUtf8, toAscii } = Encoding;
const { fromAscii, fromHex, fromUtf8, toAscii } = Encoding;
const httpUrl = "http://localhost:1317";
@ -33,10 +34,14 @@ const faucet = {
address: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
};
const unusedAccount = {
const unused = {
address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
};
const guest = {
address: "cosmos17d0jcz59jf68g52vq38tuuncmwwjk42u6mcxej",
};
interface HackatomInstance {
readonly initMsg: {
readonly verifier: string;
@ -65,7 +70,7 @@ describe("CosmWasmClient", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
expect(await client.getNonce(unusedAccount.address)).toEqual({
expect(await client.getNonce(unused.address)).toEqual({
accountNumber: 5,
sequence: 0,
});
@ -86,8 +91,8 @@ describe("CosmWasmClient", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
expect(await client.getAccount(unusedAccount.address)).toEqual({
address: unusedAccount.address,
expect(await client.getAccount(unused.address)).toEqual({
address: unused.address,
account_number: 5,
sequence: 0,
public_key: "",
@ -392,6 +397,135 @@ describe("CosmWasmClient", () => {
});
});
describe("getCodes", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
const result = await client.getCodes();
expect(result.length).toBeGreaterThanOrEqual(1);
const [first] = result;
expect(first).toEqual({
id: 1,
checksum: "b26861a6aa9858585ed905a590272735bd4fe8177c708940236224e8c9ff73ca",
source: undefined,
builder: undefined,
creator: faucet.address,
});
});
});
describe("getCodeDetails", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
const result = await client.getCodeDetails(1);
const checksum = new Sha256(result.wasm).digest();
expect(checksum).toEqual(fromHex("b26861a6aa9858585ed905a590272735bd4fe8177c708940236224e8c9ff73ca"));
});
});
describe("getContracts", () => {
it("works", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
const result = await client.getContracts(1);
expect(result.length).toBeGreaterThanOrEqual(3);
const [jade, hash, isa] = result;
expect(hash).toEqual({
codeId: 1,
creator: faucet.address,
initMsg: {
decimals: 5,
name: "Hash token",
symbol: "HASH",
initial_balances: [
{
address: faucet.address,
amount: "11",
},
{
address: unused.address,
amount: "12812345",
},
{
address: guest.address,
amount: "22004000000",
},
],
},
});
expect(isa).toEqual({
codeId: 1,
creator: faucet.address,
initMsg: {
decimals: 0,
name: "Isa Token",
symbol: "ISA",
initial_balances: [
{
address: faucet.address,
amount: "999999999",
},
{
address: unused.address,
amount: "42",
},
],
},
});
expect(jade).toEqual({
codeId: 1,
creator: faucet.address,
initMsg: {
decimals: 18,
name: "Jade Token",
symbol: "JADE",
initial_balances: [
{
address: faucet.address,
amount: "189189189000000000000000000", // 189189189 JADE
},
{
address: guest.address,
amount: "189500000000000000000", // 189.5 JADE
},
],
},
});
});
});
describe("getContract", () => {
it("works for HASH instance", async () => {
pendingWithoutWasmd();
const client = new CosmWasmClient(httpUrl);
const hash = await client.getContract("cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5");
expect(hash).toEqual({
codeId: 1,
creator: faucet.address,
initMsg: {
decimals: 5,
name: "Hash token",
symbol: "HASH",
initial_balances: [
{
address: faucet.address,
amount: "11",
},
{
address: unused.address,
amount: "12812345",
},
{
address: guest.address,
amount: "22004000000",
},
],
},
});
});
});
describe("queryContractRaw", () => {
const configKey = toAscii("config");
const otherKey = toAscii("this_does_not_exist");

View File

@ -48,6 +48,30 @@ 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 {
/** The original wasm bytes */
readonly wasm: Uint8Array;
}
export interface Contract {
// TODO: add contract address (https://github.com/cosmwasm/wasmd/issues/75)
readonly codeId: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly initMsg: object;
}
export class CosmWasmClient {
protected readonly restClient: RestClient;
@ -166,6 +190,42 @@ export class CosmWasmClient {
};
}
public async getCodes(): Promise<readonly Code[]> {
const result = await this.restClient.listCodeInfo();
return result.map(r => ({
id: r.id,
creator: r.creator,
checksum: Encoding.toHex(Encoding.fromHex(r.code_hash)),
source: r.source || undefined,
builder: r.builder || undefined,
}));
}
public async getCodeDetails(codeId: number): Promise<CodeDetails> {
const result = await this.restClient.getCode(codeId);
return {
wasm: result,
};
}
public async getContracts(codeId: number): Promise<readonly Contract[]> {
const result = await this.restClient.listContractsByCodeId(codeId);
return result.map(r => ({
codeId: r.code_id,
creator: r.creator,
initMsg: r.init_msg,
}));
}
public async getContract(address: string): Promise<Contract> {
const result = await this.restClient.getContractInfo(address);
return {
codeId: result.code_id,
creator: result.creator,
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.

View File

@ -7,6 +7,9 @@ export { unmarshalTx } from "./decoding";
export { makeSignBytes, marshalTx } from "./encoding";
export { BroadcastMode, RestClient, TxsResponse } from "./restclient";
export {
Code,
CodeDetails,
Contract,
CosmWasmClient,
GetNonceResult,
PostTxResult,

View File

@ -1,16 +1,7 @@
import { Encoding } from "@iov/encoding";
import axios, { AxiosError, AxiosInstance } from "axios";
import {
CodeInfo,
ContractInfo,
CosmosSdkAccount,
CosmosSdkTx,
Model,
parseWasmData,
StdTx,
WasmData,
} from "./types";
import { CosmosSdkAccount, CosmosSdkTx, Model, parseWasmData, StdTx, WasmData } from "./types";
const { fromBase64, toHex, toUtf8 } = Encoding;
@ -131,6 +122,25 @@ interface EncodeTxResponse {
readonly tx: string;
}
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly code_hash: string;
// TODO: these are not supported in current wasmd
readonly source?: string;
readonly builder?: string;
}
export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly init_msg: object;
}
interface GetCodeResult {
// base64 encoded wasm
readonly code: string;

View File

@ -160,30 +160,6 @@ export interface CosmosSdkAccount {
readonly sequence: number;
}
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly code_hash: string;
// TODO: these are not supported in current wasmd
readonly source?: string;
readonly builder?: string;
}
export interface CodeDetails {
// TODO: this should be base64 encoded string with content - not in current stack
readonly code: string;
}
export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly init_msg: object;
}
export interface WasmData {
// key is hex-encoded
readonly key: string;

View File

@ -25,6 +25,26 @@ 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 {
/** The original wasm bytes */
readonly wasm: Uint8Array;
}
export interface Contract {
readonly codeId: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly initMsg: object;
}
export declare class CosmWasmClient {
protected readonly restClient: RestClient;
constructor(url: string, broadcastMode?: BroadcastMode);
@ -50,6 +70,10 @@ export declare class CosmWasmClient {
getBlock(height?: number): Promise<BlockResponse>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly TxsResponse[]>;
postTx(tx: StdTx): Promise<PostTxResult>;
getCodes(): Promise<readonly Code[]>;
getCodeDetails(codeId: number): Promise<CodeDetails>;
getContracts(codeId: number): Promise<readonly Contract[]>;
getContract(address: string): Promise<Contract>;
/**
* Returns the data at the key if present (raw contract dependent storage data)
* or null if no data at this key.

View File

@ -6,6 +6,9 @@ export { unmarshalTx } from "./decoding";
export { makeSignBytes, marshalTx } from "./encoding";
export { BroadcastMode, RestClient, TxsResponse } from "./restclient";
export {
Code,
CodeDetails,
Contract,
CosmWasmClient,
GetNonceResult,
PostTxResult,

View File

@ -1,4 +1,4 @@
import { CodeInfo, ContractInfo, CosmosSdkAccount, CosmosSdkTx, Model, StdTx } from "./types";
import { CosmosSdkAccount, CosmosSdkTx, Model, StdTx } from "./types";
interface NodeInfo {
readonly network: string;
}
@ -92,6 +92,22 @@ export interface PostTxsResponse {
interface EncodeTxResponse {
readonly tx: string;
}
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly code_hash: string;
readonly source?: string;
readonly builder?: string;
}
export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly init_msg: object;
}
interface GetCodeResult {
readonly code: string;
}

View File

@ -116,25 +116,6 @@ export interface CosmosSdkAccount {
readonly account_number: number;
readonly sequence: number;
}
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly code_hash: string;
readonly source?: string;
readonly builder?: string;
}
export interface CodeDetails {
readonly code: string;
}
export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Argument passed on initialization of the contract */
readonly init_msg: object;
}
export interface WasmData {
readonly key: string;
readonly val: string;