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;