diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 7e2cecbf..e9ca24be 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -421,6 +421,8 @@ describe("RestClient", () => { // create new instance and compare before and after const existingContracts = await client.listContractAddresses(); + const existingContractsByCode = await client.listContractsByCodeId(codeId); + existingContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId)); const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount); expect(result.code).toBeFalsy(); @@ -437,6 +439,11 @@ describe("RestClient", () => { const lastContract = diff[0]; expect(lastContract).toEqual(myAddress); + // also by codeID list + const newContractsByCode = await client.listContractsByCodeId(codeId); + newContractsByCode.forEach(ctc => expect(ctc.code_id).toEqual(codeId)); + expect(newContractsByCode.length).toEqual(existingContractsByCode.length + 1); + // check out info const myInfo = await client.getContractInfo(myAddress); expect(myInfo.code_id).toEqual(codeId); @@ -514,18 +521,14 @@ describe("RestClient", () => { // invalid query syntax throws an error await client.queryContractSmart(contractAddress, { nosuchkey: {} }).then( () => fail("shouldn't succeed"), - error => expect(error).toBeTruthy(), + error => expect(error).toMatch("Error parsing QueryMsg"), ); - // TODO: debug rest server. I expect a 'Parse Error', but get - // Request failed with status code 500 to match 'Parse Error:' // invalid address throws an error await client.queryContractSmart(noContract, { verifier: {} }).then( () => fail("shouldn't succeed"), - error => expect(error).toBeTruthy(), + error => expect(error).toMatch("not found"), ); - // TODO: debug rest server. I expect a 'not found', but get - // Request failed with status code 500 to match 'Parse Error:' }); }); }); diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index 91b4647e..cd128366 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -1,5 +1,5 @@ import { Encoding } from "@iov/encoding"; -import axios, { AxiosInstance } from "axios"; +import axios, { AxiosError, AxiosInstance } from "axios"; import { AminoTx, CodeInfo, ContractInfo, CosmosSdkAccount, isAminoStdTx, StdTx, WasmData } from "./types"; @@ -128,6 +128,26 @@ function parseWasmResponse(response: WasmResponse): any { 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 +function parseAxios500error(err: AxiosError): never { + // use the error message sent from server, not default 500 msg + if (err.response?.data) { + const data = err.response.data; + // expect { error: string }, but otherwise dump + if (data.error) { + throw new Error(data.error); + } else if (typeof data === "string") { + throw new Error(data); + } else { + throw new Error(JSON.stringify(data)); + } + } else { + throw err; + } +} + export class RestClient { private readonly client: AxiosInstance; // From https://cosmos.network/rpc/#/ICS0/post_txs @@ -146,7 +166,7 @@ export class RestClient { } public async get(path: string): Promise { - const { data } = await this.client.get(path); + const { data } = await this.client.get(path).catch(parseAxios500error); if (data === null) { throw new Error("Received null response from server"); } @@ -154,7 +174,7 @@ export class RestClient { } public async post(path: string, params: PostTxsParams): Promise { - const { data } = await this.client.post(path, params); + const { data } = await this.client.post(path, params).catch(parseAxios500error); if (data === null) { throw new Error("Received null response from server"); } @@ -264,6 +284,14 @@ export class RestClient { return addresses || []; } + public async listContractsByCodeId(id: number): Promise { + const path = `/wasm/code/${id}/contracts`; + const responseData = await this.get(path); + // answer may be null (go's encoding of empty array) + const contracts: ContractInfo[] | null = parseWasmResponse(responseData as WasmResponse); + return contracts || []; + } + // throws error if no contract at this address public async getContractInfo(address: string): Promise { const path = `/wasm/contract/${address}`; diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index d560856f..d8a23d42 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -100,6 +100,7 @@ export declare class RestClient { listCodeInfo(): Promise; getCode(id: number): Promise; listContractAddresses(): Promise; + listContractsByCodeId(id: number): Promise; getContractInfo(address: string): Promise; getAllContractState(address: string): Promise; queryContractRaw(address: string, key: Uint8Array): Promise;