From f8e20921a3d9b7708a40edaed690e525c7e6e27b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 22:55:40 +0100 Subject: [PATCH 01/13] Fix linting issues --- packages/sdk/src/restclient.ts | 7 ------- packages/sdk/src/signingcosmwasmclient.spec.ts | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index b72b7a94..d04c3ade 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -195,13 +195,6 @@ function unwrapWasmResponse(response: WasmResponse): T { return response.result; } -function parseWasmResponse(response: WasmResponse): any { - if (isWasmError(response)) { - throw new Error(response.error); - } - return JSON.parse(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 diff --git a/packages/sdk/src/signingcosmwasmclient.spec.ts b/packages/sdk/src/signingcosmwasmclient.spec.ts index a8abbfeb..defd9806 100644 --- a/packages/sdk/src/signingcosmwasmclient.spec.ts +++ b/packages/sdk/src/signingcosmwasmclient.spec.ts @@ -143,7 +143,7 @@ describe("SigningCosmWasmClient", () => { ); // execute - const result = await client.execute(contractAddress, {release:{}}, undefined); + const result = await client.execute(contractAddress, { release: {} }, undefined); const [firstLog] = result.logs; expect(firstLog.log).toEqual(`released funds to ${beneficiaryAddress}`); From 542939a63e45390946e8a9e8fa0e0ab00f3fbfa6 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:12:57 +0100 Subject: [PATCH 02/13] Adapt code to latest hackatom --- packages/sdk/src/restclient.spec.ts | 2 +- packages/sdk/src/testutils.spec.ts | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 72fd454b..b6c05d02 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -144,7 +144,7 @@ async function executeContract( value: { sender: faucet.address, contract: contractAddress, - msg: {}, + msg: { release: {} }, sent_funds: [], }, }; diff --git a/packages/sdk/src/testutils.spec.ts b/packages/sdk/src/testutils.spec.ts index f9278ec1..2126355c 100644 --- a/packages/sdk/src/testutils.spec.ts +++ b/packages/sdk/src/testutils.spec.ts @@ -27,19 +27,18 @@ export function leb128Encode(uint: number): Uint8Array { export function getRandomizedHackatom(): Uint8Array { const data = Encoding.fromBase64(hackatom.data); - // TODO: this needs to be redone! // The return value of the export function cosmwasm_api_0_6 is unused and // can be randomized for testing. // // Find position of mutable bytes as follows: // $ wasm-objdump -d contract.wasm | grep -F "cosmwasm_api_0_6" -A 1 - // 00e67c func[149] : - // 00e67d: 41 83 0c | i32.const 1539 + // 0136d2 func[198] : + // 0136d3: 41 83 0c | i32.const 1539 // - // In the last line, the addresses 00e67d-00e67f hold a one byte instruction - // (https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#constants-described-here) - // and a two byte value (leb128 encoded 1539) + // In the last line, the addresses [0136d3, 0136d3+1, 0136d3+2] hold a one byte instruction + // and a two byte value (leb128 encoded 1539). See also + // https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#constants-described-here. // Any unsigned integer from 128 to 16383 is encoded to two leb128 bytes const min = 128; @@ -47,8 +46,8 @@ export function getRandomizedHackatom(): Uint8Array { const random = Math.floor(Math.random() * (max - min)) + min; const bytes = leb128Encode(random); - data[0x00e67d + 1] = bytes[0]; - data[0x00e67d + 2] = bytes[1]; + data[0x0136d3 + 1] = bytes[0]; + data[0x0136d3 + 2] = bytes[1]; return data; } From 9f44e296cda49e94f47de7363b6ee10d0be09326 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:28:13 +0100 Subject: [PATCH 03/13] Adapt handling of logs/attributes/events for wasm --- packages/sdk/src/logs.ts | 15 +++++++++++++-- packages/sdk/src/restclient.spec.ts | 12 +++++++++--- packages/sdk/src/signingcosmwasmclient.spec.ts | 9 +++++++-- packages/sdk/types/logs.d.ts | 4 +++- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/sdk/src/logs.ts b/packages/sdk/src/logs.ts index 79d7b915..496fe2ca 100644 --- a/packages/sdk/src/logs.ts +++ b/packages/sdk/src/logs.ts @@ -1,13 +1,22 @@ /* eslint-disable @typescript-eslint/camelcase */ import { isNonNullObject } from "@iov/encoding"; +const supportedEventTypes: readonly string[] = ["message", "transfer", "wasm"]; + +export type SupportedEventType = "message" | "transfer" | "wasm"; + +export function isSupportedEventType(data: any): data is SupportedEventType { + if (typeof data !== "string") return false; + return supportedEventTypes.includes(data); +} + export interface Attribute { readonly key: string; readonly value: string; } export interface Event { - readonly type: "message" | "transfer"; + readonly type: SupportedEventType; readonly attributes: readonly Attribute[]; } @@ -34,7 +43,9 @@ export function parseAttribute(input: unknown): Attribute { export function parseEvent(input: unknown): Event { if (!isNonNullObject(input)) throw new Error("Event must be a non-null object"); const { type, attributes } = input as any; - if (type !== "message" && type !== "transfer") throw new Error("Event must be of type message or transfer"); + if (!isSupportedEventType(type)) { + throw new Error(`Event type must be one of ${supportedEventTypes.join(", ")}; got ${type}`); + } if (!Array.isArray(attributes)) throw new Error("Event's attributes must be an array"); return { type: type, diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index b6c05d02..5aa6884a 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -581,9 +581,15 @@ describe("RestClient", () => { { const result = await executeContract(client, pen, contractAddress); expect(result.code).toBeFalsy(); - // console.log("Raw log:", result.raw_log); - const [firstLog] = parseLogs(result.logs); - expect(firstLog.log).toEqual(`released funds to ${beneficiaryAddress}`); + // console.log("Raw log:", result.logs); + const logs = parseLogs(result.logs); + const wasmEvent = logs.find(() => true)?.events.find(e => e.type === "wasm"); + assert(wasmEvent, "Event of type wasm expected"); + expect(wasmEvent.attributes).toContain({ key: "action", value: "release" }); + expect(wasmEvent.attributes).toContain({ + key: "destination", + value: beneficiaryAddress, + }); // Verify token transfer from contract to beneficiary const beneficiaryBalance = (await client.authAccounts(beneficiaryAddress)).result.value.coins; diff --git a/packages/sdk/src/signingcosmwasmclient.spec.ts b/packages/sdk/src/signingcosmwasmclient.spec.ts index defd9806..6a4208ea 100644 --- a/packages/sdk/src/signingcosmwasmclient.spec.ts +++ b/packages/sdk/src/signingcosmwasmclient.spec.ts @@ -144,8 +144,13 @@ describe("SigningCosmWasmClient", () => { // execute const result = await client.execute(contractAddress, { release: {} }, undefined); - const [firstLog] = result.logs; - expect(firstLog.log).toEqual(`released funds to ${beneficiaryAddress}`); + const wasmEvent = result.logs.find(() => true)?.events.find(e => e.type === "wasm"); + assert(wasmEvent, "Event of type wasm expected"); + expect(wasmEvent.attributes).toContain({ key: "action", value: "release" }); + expect(wasmEvent.attributes).toContain({ + key: "destination", + value: beneficiaryAddress, + }); // Verify token transfer from contract to beneficiary const rest = new RestClient(httpUrl); diff --git a/packages/sdk/types/logs.d.ts b/packages/sdk/types/logs.d.ts index 9a9e92c7..a84e8276 100644 --- a/packages/sdk/types/logs.d.ts +++ b/packages/sdk/types/logs.d.ts @@ -1,9 +1,11 @@ +export declare type SupportedEventType = "message" | "transfer" | "wasm"; +export declare function isSupportedEventType(data: any): data is SupportedEventType; export interface Attribute { readonly key: string; readonly value: string; } export interface Event { - readonly type: "message" | "transfer"; + readonly type: SupportedEventType; readonly attributes: readonly Attribute[]; } export interface Log { From b821ea786c01894678596dc326fb99dd0def0087 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:41:37 +0100 Subject: [PATCH 04/13] Fix instance order --- packages/sdk/src/cosmwasmclient.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index 3efb45cb..f33a6075 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -430,7 +430,7 @@ describe("CosmWasmClient", () => { const client = new CosmWasmClient(httpUrl); const result = await client.getContracts(1); expect(result.length).toBeGreaterThanOrEqual(3); - const [jade, hash, isa] = result; + const [hash, isa, jade] = result; expect(hash).toEqual({ address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", codeId: 1, From 8674d6815bbe9596d803fde26c1dc25f0cb8e020 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:42:10 +0100 Subject: [PATCH 05/13] Adapt config representation of hackatom --- packages/sdk/src/cosmwasmclient.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index f33a6075..72f4a58c 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -20,7 +20,7 @@ import { } from "./testutils.spec"; import { CosmosSdkTx, MsgSend, StdFee } from "./types"; -const { fromAscii, fromHex, fromUtf8, toAscii } = Encoding; +const { fromAscii, fromHex, fromUtf8, toAscii, toBase64 } = Encoding; const httpUrl = "http://localhost:1317"; @@ -506,9 +506,9 @@ describe("CosmWasmClient", () => { const raw = await client.queryContractRaw(contract.address, configKey); assert(raw, "must get result"); expect(JSON.parse(fromUtf8(raw))).toEqual({ - verifier: Array.from(Bech32.decode(contract.initMsg.verifier).data), - beneficiary: Array.from(Bech32.decode(contract.initMsg.beneficiary).data), - funder: Array.from(Bech32.decode(faucet.address).data), + verifier: toBase64(Bech32.decode(contract.initMsg.verifier).data), + beneficiary: toBase64(Bech32.decode(contract.initMsg.beneficiary).data), + funder: toBase64(Bech32.decode(faucet.address).data), }); }); From 836e6a6c5e8cc1acd14254b1438f67355829c26b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:53:52 +0100 Subject: [PATCH 06/13] Let RestClient.getContractInfo return null for missing contract --- packages/sdk/src/cosmwasmclient.ts | 8 ++++-- packages/sdk/src/restclient.spec.ts | 6 ++-- packages/sdk/src/restclient.ts | 39 ++++++++++++++++++-------- packages/sdk/types/cosmwasmclient.d.ts | 3 ++ packages/sdk/types/restclient.d.ts | 5 +++- 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 4aa21619..8ad2ff11 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -220,8 +220,12 @@ export class CosmWasmClient { })); } + /** + * Throws an error if no contract was found at the address + */ public async getContract(address: string): Promise { 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, @@ -238,7 +242,7 @@ export class CosmWasmClient { */ public async queryContractRaw(address: string, key: Uint8Array): Promise { // just test contract existence - const _info = await this.restClient.getContractInfo(address); + const _info = await this.getContract(address); return this.restClient.queryContractRaw(address, key); } @@ -254,7 +258,7 @@ export class CosmWasmClient { return await this.restClient.queryContractSmart(address, queryMsg); } catch (error) { if (error instanceof Error) { - if (error.message === "not found: contract") { + if (error.message.startsWith("not found: contract")) { throw new Error(`No contract found at address "${address}"`); } else { throw error; diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 5aa6884a..db3b5471 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -684,16 +684,14 @@ describe("RestClient", () => { // check out info const myInfo = await client.getContractInfo(myAddress); + assert(myInfo); expect(myInfo.code_id).toEqual(codeId); expect(myInfo.creator).toEqual(faucet.address); expect((myInfo.init_msg as any).beneficiary).toEqual(beneficiaryAddress); // make sure random addresses don't give useful info const nonExistentAddress = makeRandomAddress(); - await client - .getContractInfo(nonExistentAddress) - .then(() => fail("this shouldn't succeed")) - .catch(error => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`)); + expect(await client.getContractInfo(nonExistentAddress)).toBeNull(); }); describe("contract state", () => { diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index d04c3ade..15d3aa3e 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -198,18 +198,20 @@ function unwrapWasmResponse(response: WasmResponse): T { // 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 -function parseAxios500error(err: AxiosError): never { +function parseAxiosError(err: AxiosError): never { // use the error message sent from server, not default 500 msg if (err.response?.data) { + let errorText: string; const data = err.response.data; // expect { error: string }, but otherwise dump - if (data.error) { - throw new Error(data.error); + if (data.error && typeof data.error === "string") { + errorText = data.error; } else if (typeof data === "string") { - throw new Error(data); + errorText = data; } else { - throw new Error(JSON.stringify(data)); + errorText = JSON.stringify(data); } + throw new Error(`${errorText} (HTTP ${err.response.status})`); } else { throw err; } @@ -231,7 +233,7 @@ export class RestClient { } public async get(path: string): Promise { - const { data } = await this.client.get(path).catch(parseAxios500error); + const { data } = await this.client.get(path).catch(parseAxiosError); if (data === null) { throw new Error("Received null response from server"); } @@ -239,7 +241,7 @@ export class RestClient { } public async post(path: string, params: PostTxsParams): Promise { - const { data } = await this.client.post(path, params).catch(parseAxios500error); + const { data } = await this.client.post(path, params).catch(parseAxiosError); if (data === null) { throw new Error("Received null response from server"); } @@ -355,11 +357,26 @@ export class RestClient { return unwrapWasmResponse(responseData) || []; } - // throws error if no contract at this address - public async getContractInfo(address: string): Promise { + /** + * Returns null when contract was not found at this address. + */ + public async getContractInfo(address: string): Promise { const path = `/wasm/contract/${address}`; - const responseData = (await this.get(path)) as WasmResponse; - return unwrapWasmResponse(responseData); + + try { + const response = (await this.get(path)) as WasmResponse; + return unwrapWasmResponse(response); + } catch (error) { + if (error instanceof Error) { + if (error.message.startsWith("unknown address:")) { + return null; + } else { + throw error; + } + } else { + throw error; + } + } } // Returns all contract state. diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index 6ff632dc..37d21d10 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -76,6 +76,9 @@ export declare class CosmWasmClient { getCodes(): Promise; getCodeDetails(codeId: number): Promise; getContracts(codeId: number): Promise; + /** + * Throws an error if no contract was found at the address + */ getContract(address: string): Promise; /** * Returns the data at the key if present (raw contract dependent storage data) diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index d38a44fa..f3a7ad7b 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -165,7 +165,10 @@ export declare class RestClient { listCodeInfo(): Promise; getCode(id: number): Promise; listContractsByCodeId(id: number): Promise; - getContractInfo(address: string): Promise; + /** + * Returns null when contract was not found at this address. + */ + getContractInfo(address: string): Promise; getAllContractState(address: string): Promise; queryContractRaw(address: string, key: Uint8Array): Promise; queryContractSmart(address: string, query: object): Promise; From 09afd8e00dc48f0836c146cf35fa26454b9d7aac Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 27 Feb 2020 23:55:03 +0100 Subject: [PATCH 07/13] Adapt BCP tests --- packages/bcp/src/cosmwasmconnection.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bcp/src/cosmwasmconnection.spec.ts b/packages/bcp/src/cosmwasmconnection.spec.ts index 55db4b2e..4355fd57 100644 --- a/packages/bcp/src/cosmwasmconnection.spec.ts +++ b/packages/bcp/src/cosmwasmconnection.spec.ts @@ -425,7 +425,7 @@ describe("CosmWasmConnection", () => { assert(isConfirmedTransaction(getResponse), "Expected transaction to succeed"); assert(getResponse.log, "Log must be available"); const [firstLog] = JSON.parse(getResponse.log); - expect(firstLog.events.length).toEqual(1); + expect(firstLog.events.length).toEqual(2); const { transaction, signatures } = getResponse; assert(isSendTransaction(transaction), "Expected send transaction"); From b2ee1aa860f742f1d414e686cbda4d7fe002fc94 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 09:48:39 +0100 Subject: [PATCH 08/13] Add return types to map callbacks for stricter type safety --- packages/sdk/src/cosmwasmclient.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 8ad2ff11..2849b601 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -195,13 +195,15 @@ export class CosmWasmClient { public async getCodes(): Promise { 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, - })); + return result.map( + (entry): Code => ({ + id: entry.id, + creator: entry.creator, + checksum: Encoding.toHex(Encoding.fromHex(entry.code_hash)), + source: entry.source || undefined, + builder: entry.builder || undefined, + }), + ); } public async getCodeDetails(codeId: number): Promise { @@ -213,11 +215,13 @@ export class CosmWasmClient { public async getContracts(codeId: number): Promise { const result = await this.restClient.listContractsByCodeId(codeId); - return result.map(entry => ({ - address: entry.address, - codeId: entry.code_id, - creator: entry.creator, - })); + return result.map( + (entry): Contract => ({ + address: entry.address, + codeId: entry.code_id, + creator: entry.creator, + }), + ); } /** From d1c069d9a749a0a241a9bcb0b3edeb9b234ce5e0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 09:55:26 +0100 Subject: [PATCH 09/13] v0.7.0-alpha.0 --- lerna.json | 2 +- packages/bcp/package.json | 4 ++-- packages/cli/package.json | 4 ++-- packages/faucet/package.json | 6 +++--- packages/sdk/package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lerna.json b/lerna.json index 9c5bb81c..cc7bdefd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.0.8", + "version": "0.7.0-alpha.0", "useWorkspaces": true, "npmClient": "yarn" } diff --git a/packages/bcp/package.json b/packages/bcp/package.json index e7a129fb..534747e0 100644 --- a/packages/bcp/package.json +++ b/packages/bcp/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/bcp", - "version": "0.0.8", + "version": "0.7.0-alpha.0", "description": "Transaction codec and client to communicate with any wasmd blockchain", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmwasm/sdk": "^0.0.8", + "@cosmwasm/sdk": "^0.7.0-alpha.0", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index d4c5763b..31e62afb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/cli", - "version": "0.0.8", + "version": "0.7.0-alpha.0", "description": "Command line interface", "contributors": [ "IOV SAS ", @@ -36,7 +36,7 @@ "!**/testdata/" ], "dependencies": { - "@cosmwasm/sdk": "^0.0.8", + "@cosmwasm/sdk": "^0.7.0-alpha.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", "@iov/utils": "^2.0.2", diff --git a/packages/faucet/package.json b/packages/faucet/package.json index cdfa2398..b0dda64d 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/faucet", - "version": "0.0.8", + "version": "0.7.0-alpha.0", "description": "The faucet", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -35,10 +35,10 @@ "test": "yarn build-or-skip && yarn test-node" }, "dependencies": { - "@cosmwasm/bcp": "^0.0.8", + "@cosmwasm/bcp": "^0.7.0-alpha.0", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", - "@iov/encoding":"^2.1.0", + "@iov/encoding": "^2.1.0", "@iov/keycontrol": "^2.1.0", "@iov/utils": "^2.0.2", "@koa/cors": "^3.0.0", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index de09ac68..4374c25d 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/sdk", - "version": "0.0.8", + "version": "0.7.0-alpha.0", "description": "CosmWasm SDK", "author": "Ethan Frey ", "license": "Apache-2.0", From 7e7c0ff89687f970b98ddddfa74979dc6d33ccf8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 10:57:43 +0100 Subject: [PATCH 10/13] Expose instance labels of contracts --- packages/sdk/src/cosmwasmclient.spec.ts | 4 ++++ packages/sdk/src/cosmwasmclient.ts | 3 +++ packages/sdk/src/restclient.spec.ts | 17 +++++++++++++++-- packages/sdk/src/restclient.ts | 1 + packages/sdk/src/testutils.spec.ts | 3 +++ packages/sdk/types/cosmwasmclient.d.ts | 1 + packages/sdk/types/restclient.d.ts | 1 + 7 files changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index 72f4a58c..de277060 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -435,16 +435,19 @@ describe("CosmWasmClient", () => { 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", }); }); }); @@ -458,6 +461,7 @@ describe("CosmWasmClient", () => { address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", codeId: 1, creator: faucet.address, + label: "HASH", initMsg: { decimals: 5, name: "Hash token", diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 2849b601..411df6d4 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -68,6 +68,7 @@ export interface Contract { readonly codeId: number; /** Bech32 account address */ readonly creator: string; + readonly label: string; } export interface ContractDetails extends Contract { @@ -220,6 +221,7 @@ export class CosmWasmClient { address: entry.address, codeId: entry.code_id, creator: entry.creator, + label: entry.label, }), ); } @@ -234,6 +236,7 @@ export class CosmWasmClient { address: result.address, codeId: result.code_id, creator: result.creator, + label: result.label, initMsg: result.init_msg, }; } diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index db3b5471..82fa3d66 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -12,6 +12,7 @@ import { PostTxsResponse, RestClient, TxsResponse } from "./restclient"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import cosmoshub from "./testdata/cosmoshub.json"; import { + bech32AddressMatcher, getRandomizedHackatom, makeRandomAddress, pendingWithoutWasmd, @@ -670,7 +671,12 @@ describe("RestClient", () => { // create new instance and compare before and after const existingContractsByCode = await client.listContractsByCodeId(codeId); - existingContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId)); + for (const contract of existingContractsByCode) { + expect(contract.address).toMatch(bech32AddressMatcher); + expect(contract.code_id).toEqual(codeId); + expect(contract.creator).toMatch(bech32AddressMatcher); + expect(contract.label).toMatch(/^.+$/); + } const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount); expect(result.code).toBeFalsy(); @@ -679,8 +685,15 @@ describe("RestClient", () => { const myAddress = contractAddressAttr.value; const newContractsByCode = await client.listContractsByCodeId(codeId); - newContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId)); expect(newContractsByCode.length).toEqual(existingContractsByCode.length + 1); + const newContract = newContractsByCode[newContractsByCode.length - 1]; + expect(newContract).toEqual( + jasmine.objectContaining({ + code_id: codeId, + creator: faucet.address, + label: "my escrow", + }), + ); // check out info const myInfo = await client.getContractInfo(myAddress); diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index 15d3aa3e..da4ad80c 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -139,6 +139,7 @@ export interface ContractInfo { readonly code_id: number; /** Bech32 account address */ readonly creator: string; + readonly label: string; } export interface ContractDetails extends ContractInfo { diff --git a/packages/sdk/src/testutils.spec.ts b/packages/sdk/src/testutils.spec.ts index 2126355c..f72d4636 100644 --- a/packages/sdk/src/testutils.spec.ts +++ b/packages/sdk/src/testutils.spec.ts @@ -60,6 +60,9 @@ export const tendermintIdMatcher = /^[0-9A-F]{64}$/; export const tendermintOptionalIdMatcher = /^([0-9A-F]{64}|)$/; export const tendermintAddressMatcher = /^[0-9A-F]{40}$/; +// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 +export const bech32AddressMatcher = /^[\x21-\x7e]{1,83}1[02-9ac-hj-np-z]{38}$/; + export function wasmdEnabled(): boolean { return !!process.env.WASMD_ENABLED; } diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index 37d21d10..f614a726 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -43,6 +43,7 @@ export interface Contract { readonly codeId: number; /** Bech32 account address */ readonly creator: string; + readonly label: string; } export interface ContractDetails extends Contract { /** Argument passed on initialization of the contract */ diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index f3a7ad7b..7c3ab410 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -106,6 +106,7 @@ export interface ContractInfo { readonly code_id: number; /** Bech32 account address */ readonly creator: string; + readonly label: string; } export interface ContractDetails extends ContractInfo { /** Argument passed on initialization of the contract */ From 195057baf45f3123e47d2e50293f9336af9d7e2f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 11:01:24 +0100 Subject: [PATCH 11/13] v0.7.0-alpha.1 --- lerna.json | 2 +- packages/bcp/package.json | 4 ++-- packages/cli/package.json | 4 ++-- packages/faucet/package.json | 4 ++-- packages/sdk/package.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lerna.json b/lerna.json index cc7bdefd..dcef3ef7 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.7.0-alpha.0", + "version": "0.7.0-alpha.1", "useWorkspaces": true, "npmClient": "yarn" } diff --git a/packages/bcp/package.json b/packages/bcp/package.json index 534747e0..ab0aca66 100644 --- a/packages/bcp/package.json +++ b/packages/bcp/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/bcp", - "version": "0.7.0-alpha.0", + "version": "0.7.0-alpha.1", "description": "Transaction codec and client to communicate with any wasmd blockchain", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmwasm/sdk": "^0.7.0-alpha.0", + "@cosmwasm/sdk": "^0.7.0-alpha.1", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 31e62afb..ca5c0eb1 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/cli", - "version": "0.7.0-alpha.0", + "version": "0.7.0-alpha.1", "description": "Command line interface", "contributors": [ "IOV SAS ", @@ -36,7 +36,7 @@ "!**/testdata/" ], "dependencies": { - "@cosmwasm/sdk": "^0.7.0-alpha.0", + "@cosmwasm/sdk": "^0.7.0-alpha.1", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", "@iov/utils": "^2.0.2", diff --git a/packages/faucet/package.json b/packages/faucet/package.json index b0dda64d..548796fe 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/faucet", - "version": "0.7.0-alpha.0", + "version": "0.7.0-alpha.1", "description": "The faucet", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "test": "yarn build-or-skip && yarn test-node" }, "dependencies": { - "@cosmwasm/bcp": "^0.7.0-alpha.0", + "@cosmwasm/bcp": "^0.7.0-alpha.1", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 4374c25d..4e1c0c0e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/sdk", - "version": "0.7.0-alpha.0", + "version": "0.7.0-alpha.1", "description": "CosmWasm SDK", "author": "Ethan Frey ", "license": "Apache-2.0", From 3ffe5597a1ae36c2b8627ec1eecfcade6f3c5f4f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 12:49:40 +0100 Subject: [PATCH 12/13] Let CodeDetails extend Code --- packages/sdk/src/cosmwasmclient.spec.ts | 17 ++++++++++++++--- packages/sdk/src/cosmwasmclient.ts | 14 ++++++++++---- packages/sdk/types/cosmwasmclient.d.ts | 4 ++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index de277060..5f130e65 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -4,7 +4,7 @@ import { Bech32, Encoding } from "@iov/encoding"; import { assert, sleep } from "@iov/utils"; import { ReadonlyDate } from "readonly-date"; -import { CosmWasmClient } from "./cosmwasmclient"; +import { Code, CosmWasmClient } from "./cosmwasmclient"; import { makeSignBytes } from "./encoding"; import { findAttribute } from "./logs"; import { Secp256k1Pen } from "./pen"; @@ -419,8 +419,19 @@ describe("CosmWasmClient", () => { pendingWithoutWasmd(); const client = new CosmWasmClient(httpUrl); const result = await client.getCodeDetails(1); - const checksum = new Sha256(result.wasm).digest(); - expect(checksum).toEqual(fromHex("aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae")); + + const expectedInfo: Code = { + id: 1, + checksum: "aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae", + source: undefined, + builder: undefined, + creator: faucet.address, + }; + + // check info + expect(result).toEqual(jasmine.objectContaining(expectedInfo)); + // check data + expect(new Sha256(result.data).digest()).toEqual(fromHex(expectedInfo.checksum)); }); }); diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 411df6d4..0ea8ef77 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -58,9 +58,9 @@ export interface Code { readonly builder?: string; } -export interface CodeDetails { +export interface CodeDetails extends Code { /** The original wasm bytes */ - readonly wasm: Uint8Array; + readonly data: Uint8Array; } export interface Contract { @@ -208,9 +208,15 @@ export class CosmWasmClient { } public async getCodeDetails(codeId: number): Promise { - const result = await this.restClient.getCode(codeId); + // TODO: implement as one request when https://github.com/cosmwasm/wasmd/issues/90 is done + const [codeInfos, getCodeResult] = await Promise.all([this.getCodes(), this.restClient.getCode(codeId)]); + + const codeInfo = codeInfos.find(code => code.id === codeId); + if (!codeInfo) throw new Error("No code info found"); + return { - wasm: result, + ...codeInfo, + data: getCodeResult, }; } diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index f614a726..d001e6df 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -34,9 +34,9 @@ export interface Code { readonly source?: string; readonly builder?: string; } -export interface CodeDetails { +export interface CodeDetails extends Code { /** The original wasm bytes */ - readonly wasm: Uint8Array; + readonly data: Uint8Array; } export interface Contract { readonly address: string; From 8ed69a57678fd558c6ff304e0540c39bdbe302ec Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 28 Feb 2020 12:52:27 +0100 Subject: [PATCH 13/13] v0.7.0-alpha.2 --- lerna.json | 2 +- packages/bcp/package.json | 4 ++-- packages/cli/package.json | 4 ++-- packages/faucet/package.json | 4 ++-- packages/sdk/package.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lerna.json b/lerna.json index dcef3ef7..25c5ae3e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "useWorkspaces": true, "npmClient": "yarn" } diff --git a/packages/bcp/package.json b/packages/bcp/package.json index ab0aca66..71be60a2 100644 --- a/packages/bcp/package.json +++ b/packages/bcp/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/bcp", - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "description": "Transaction codec and client to communicate with any wasmd blockchain", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, "dependencies": { - "@cosmwasm/sdk": "^0.7.0-alpha.1", + "@cosmwasm/sdk": "^0.7.0-alpha.2", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index ca5c0eb1..7aa0f7c5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/cli", - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "description": "Command line interface", "contributors": [ "IOV SAS ", @@ -36,7 +36,7 @@ "!**/testdata/" ], "dependencies": { - "@cosmwasm/sdk": "^0.7.0-alpha.1", + "@cosmwasm/sdk": "^0.7.0-alpha.2", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", "@iov/utils": "^2.0.2", diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 548796fe..08604ac3 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/faucet", - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "description": "The faucet", "author": "Ethan Frey ", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "test": "yarn build-or-skip && yarn test-node" }, "dependencies": { - "@cosmwasm/bcp": "^0.7.0-alpha.1", + "@cosmwasm/bcp": "^0.7.0-alpha.2", "@iov/bcp": "^2.1.0", "@iov/crypto": "^2.1.0", "@iov/encoding": "^2.1.0", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 4e1c0c0e..dfbdcff0 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@cosmwasm/sdk", - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "description": "CosmWasm SDK", "author": "Ethan Frey ", "license": "Apache-2.0",