diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index 13b44308..e114e219 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -1,10 +1,18 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { Coin, coins, CosmosSdkTx, isMsgSend, makeSignBytes, MsgSend, Secp256k1Pen } from "@cosmjs/sdk38"; +import { + Coin, + coins, + CosmosSdkTx, + isMsgSend, + LcdClient, + makeSignBytes, + MsgSend, + Secp256k1Pen, +} from "@cosmjs/sdk38"; import { assert, sleep } from "@cosmjs/utils"; import { CosmWasmClient, isPostTxFailure } from "./cosmwasmclient"; import { isMsgExecuteContract, isMsgInstantiateContract } from "./msgs"; -import { RestClient } from "./restclient"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import { alice, @@ -50,7 +58,7 @@ describe("CosmWasmClient.searchTx", () => { const transferAmount = coins(1234567, "ucosm"); const result = await client.sendTokens(recipient, transferAmount); await sleep(75); // wait until tx is indexed - const txDetails = await new RestClient(wasmd.endpoint).txById(result.transactionHash); + const txDetails = await new LcdClient(wasmd.endpoint).txById(result.transactionHash); sendSuccessful = { sender: alice.address0, recipient: recipient, @@ -68,7 +76,7 @@ describe("CosmWasmClient.searchTx", () => { }; const result = await client.sendTokens(recipient, [transferAmount]); await sleep(75); // wait until tx is indexed - const txDetails = await new RestClient(wasmd.endpoint).txById(result.transactionHash); + const txDetails = await new LcdClient(wasmd.endpoint).txById(result.transactionHash); sendSelfSuccessful = { sender: alice.address0, recipient: recipient, @@ -132,7 +140,7 @@ describe("CosmWasmClient.searchTx", () => { }; const result = await client.execute(hashInstance, msg); await sleep(75); // wait until tx is indexed - const txDetails = await new RestClient(wasmd.endpoint).txById(result.transactionHash); + const txDetails = await new LcdClient(wasmd.endpoint).txById(result.transactionHash); execute = { sender: alice.address0, contract: hashInstance, diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index 0d176f63..3928a075 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -54,7 +54,7 @@ describe("CosmWasmClient", () => { pendingWithoutWasmd(); const client = new CosmWasmClient(wasmd.endpoint); const openedClient = (client as unknown) as PrivateCosmWasmClient; - const getCodeSpy = spyOn(openedClient.restClient, "nodeInfo").and.callThrough(); + const getCodeSpy = spyOn(openedClient.lcdClient, "nodeInfo").and.callThrough(); expect(await client.getChainId()).toEqual(wasmd.chainId); // from network expect(await client.getChainId()).toEqual(wasmd.chainId); // from cache @@ -68,7 +68,7 @@ describe("CosmWasmClient", () => { pendingWithoutWasmd(); const client = new CosmWasmClient(wasmd.endpoint); const openedClient = (client as unknown) as PrivateCosmWasmClient; - const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough(); + const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough(); const height1 = await client.getHeight(); expect(height1).toBeGreaterThan(0); @@ -85,8 +85,8 @@ describe("CosmWasmClient", () => { const client = new CosmWasmClient(wasmd.endpoint); const openedClient = (client as unknown) as PrivateCosmWasmClient; - const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough(); - const authAccountsSpy = spyOn(openedClient.restClient, "authAccounts").and.callThrough(); + const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough(); + const authAccountsSpy = spyOn(openedClient.lcdClient.auth, "account").and.callThrough(); const height1 = await client.getHeight(); expect(height1).toBeGreaterThan(0); @@ -292,7 +292,7 @@ describe("CosmWasmClient", () => { pendingWithoutWasmd(); const client = new CosmWasmClient(wasmd.endpoint); const openedClient = (client as unknown) as PrivateCosmWasmClient; - const getCodeSpy = spyOn(openedClient.restClient, "getCode").and.callThrough(); + const getCodeSpy = spyOn(openedClient.lcdClient.wasm, "getCode").and.callThrough(); const result1 = await client.getCodeDetails(deployedErc20.codeId); // from network const result2 = await client.getCodeDetails(deployedErc20.codeId); // from cache diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index 1df52b9f..66bd2286 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -2,17 +2,20 @@ import { Sha256 } from "@cosmjs/crypto"; import { fromBase64, fromHex, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { + AuthExtension, BroadcastMode, Coin, CosmosSdkTx, decodeBech32Pubkey, IndexedTx, + LcdClient, PubKey, + setupAuthExtension, StdTx, } from "@cosmjs/sdk38"; +import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; import { Log, parseLogs } from "./logs"; -import { RestClient } from "./restclient"; import { JsonObject } from "./types"; export interface GetNonceResult { @@ -160,11 +163,11 @@ export interface Block { /** Use for testing only */ export interface PrivateCosmWasmClient { - readonly restClient: RestClient; + readonly lcdClient: LcdClient & AuthExtension & WasmExtension; } export class CosmWasmClient { - protected readonly restClient: RestClient; + protected readonly lcdClient: LcdClient & AuthExtension & WasmExtension; /** Any address the chain considers valid (valid bech32 with proper prefix) */ protected anyValidAddress: string | undefined; @@ -181,12 +184,16 @@ export class CosmWasmClient { * @param broadcastMode Defines at which point of the transaction processing the postTx method (i.e. transaction broadcasting) returns */ public constructor(apiUrl: string, broadcastMode = BroadcastMode.Block) { - this.restClient = new RestClient(apiUrl, broadcastMode); + this.lcdClient = LcdClient.withExtensions( + { apiUrl: apiUrl, broadcastMode: broadcastMode }, + setupAuthExtension, + setupWasmExtension, + ); } public async getChainId(): Promise { if (!this.chainId) { - const response = await this.restClient.nodeInfo(); + const response = await this.lcdClient.nodeInfo(); const chainId = response.node_info.network; if (!chainId) throw new Error("Chain ID must not be empty"); this.chainId = chainId; @@ -197,12 +204,12 @@ export class CosmWasmClient { public async getHeight(): Promise { if (this.anyValidAddress) { - const { height } = await this.restClient.authAccounts(this.anyValidAddress); + const { height } = await this.lcdClient.auth.account(this.anyValidAddress); return parseInt(height, 10); } else { // Note: this gets inefficient when blocks contain a lot of transactions since it // requires downloading and deserializing all transactions in the block. - const latest = await this.restClient.blocksLatest(); + const latest = await this.lcdClient.blocksLatest(); return parseInt(latest.block.header.height, 10); } } @@ -212,7 +219,7 @@ export class CosmWasmClient { */ public async getIdentifier(tx: CosmosSdkTx): Promise { // We consult the REST API because we don't have a local amino encoder - const response = await this.restClient.encodeTx(tx); + const response = await this.lcdClient.encodeTx(tx); const hash = new Sha256(fromBase64(response.tx)).digest(); return toHex(hash).toUpperCase(); } @@ -238,7 +245,7 @@ export class CosmWasmClient { } public async getAccount(address: string): Promise { - const account = await this.restClient.authAccounts(address); + const account = await this.lcdClient.auth.account(address); const value = account.result.value; if (value.address === "") { return undefined; @@ -261,7 +268,7 @@ export class CosmWasmClient { */ public async getBlock(height?: number): Promise { const response = - height !== undefined ? await this.restClient.blocks(height) : await this.restClient.blocksLatest(); + height !== undefined ? await this.lcdClient.blocks(height) : await this.lcdClient.blocksLatest(); return { id: response.block_id.hash, @@ -333,7 +340,7 @@ export class CosmWasmClient { } public async postTx(tx: StdTx): Promise { - const result = await this.restClient.postTx(tx); + const result = await this.lcdClient.postTx(tx); if (!result.txhash.match(/^([0-9A-F][0-9A-F])+$/)) { throw new Error("Received ill-formatted txhash. Must be non-empty upper-case hex"); } @@ -354,7 +361,7 @@ export class CosmWasmClient { } public async getCodes(): Promise { - const result = await this.restClient.listCodeInfo(); + const result = await this.lcdClient.wasm.listCodeInfo(); return result.map( (entry): Code => { this.anyValidAddress = entry.creator; @@ -373,7 +380,7 @@ export class CosmWasmClient { const cached = this.codesCache.get(codeId); if (cached) return cached; - const getCodeResult = await this.restClient.getCode(codeId); + const getCodeResult = await this.lcdClient.wasm.getCode(codeId); const codeDetails: CodeDetails = { id: getCodeResult.id, creator: getCodeResult.creator, @@ -387,7 +394,7 @@ export class CosmWasmClient { } public async getContracts(codeId: number): Promise { - const result = await this.restClient.listContractsByCodeId(codeId); + const result = await this.lcdClient.wasm.listContractsByCodeId(codeId); return result.map( (entry): Contract => ({ address: entry.address, @@ -403,7 +410,7 @@ 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); + const result = await this.lcdClient.wasm.getContractInfo(address); if (!result) throw new Error(`No contract found at address "${address}"`); return { address: result.address, @@ -425,7 +432,7 @@ export class CosmWasmClient { // just test contract existence const _info = await this.getContract(address); - return this.restClient.queryContractRaw(address, key); + return this.lcdClient.wasm.queryContractRaw(address, key); } /** @@ -437,7 +444,7 @@ export class CosmWasmClient { */ public async queryContractSmart(address: string, queryMsg: object): Promise { try { - return await this.restClient.queryContractSmart(address, queryMsg); + return await this.lcdClient.wasm.queryContractSmart(address, queryMsg); } catch (error) { if (error instanceof Error) { if (error.message.startsWith("not found: contract")) { @@ -454,7 +461,7 @@ export class CosmWasmClient { private async txsQuery(query: string): Promise { // TODO: we need proper pagination support const limit = 100; - const result = await this.restClient.txsQuery(`${query}&limit=${limit}`); + const result = await this.lcdClient.txsQuery(`${query}&limit=${limit}`); const pages = parseInt(result.page_total, 10); if (pages > 1) { throw new Error( diff --git a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts index b828edde..b1e71f07 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts @@ -1,15 +1,19 @@ import { Sha256 } from "@cosmjs/crypto"; import { toHex } from "@cosmjs/encoding"; -import { coin, coins, Secp256k1Pen } from "@cosmjs/sdk38"; +import { AuthExtension, coin, coins, LcdClient, Secp256k1Pen, setupAuthExtension } from "@cosmjs/sdk38"; import { assert } from "@cosmjs/utils"; import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient"; -import { RestClient } from "./restclient"; +import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient"; import { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd, unused } from "./testutils.spec"; const httpUrl = "http://localhost:1317"; +function makeWasmClient(apiUrl: string): LcdClient & AuthExtension & WasmExtension { + return LcdClient.withExtensions({ apiUrl }, setupAuthExtension, setupWasmExtension); +} + describe("SigningCosmWasmClient", () => { describe("makeReadOnly", () => { it("can be constructed", async () => { @@ -26,8 +30,8 @@ describe("SigningCosmWasmClient", () => { const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes)); const openedClient = (client as unknown) as PrivateCosmWasmClient; - const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough(); - const authAccountsSpy = spyOn(openedClient.restClient, "authAccounts").and.callThrough(); + const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough(); + const authAccountsSpy = spyOn(openedClient.lcdClient.auth, "account").and.callThrough(); const height = await client.getHeight(); expect(height).toBeGreaterThan(0); @@ -97,8 +101,8 @@ describe("SigningCosmWasmClient", () => { }, ); - const rest = new RestClient(httpUrl); - const balance = (await rest.authAccounts(contractAddress)).result.value.coins; + const lcdClient = makeWasmClient(httpUrl); + const balance = (await lcdClient.auth.account(contractAddress)).result.value.coins; expect(balance).toEqual(transferAmount); }); @@ -119,8 +123,8 @@ describe("SigningCosmWasmClient", () => { { admin: unused.address }, ); - const rest = new RestClient(httpUrl); - const contract = await rest.getContractInfo(contractAddress); + const lcdClient = makeWasmClient(httpUrl); + const contract = await lcdClient.wasm.getContractInfo(contractAddress); assert(contract); expect(contract.admin).toEqual(unused.address); }); @@ -171,14 +175,14 @@ describe("SigningCosmWasmClient", () => { }, ); - const rest = new RestClient(httpUrl); - const state1 = await rest.getContractInfo(contractAddress); + const lcdClient = makeWasmClient(httpUrl); + const state1 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state1); expect(state1.admin).toEqual(alice.address0); await client.updateAdmin(contractAddress, unused.address); - const state2 = await rest.getContractInfo(contractAddress); + const state2 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state2); expect(state2.admin).toEqual(unused.address); }); @@ -204,14 +208,14 @@ describe("SigningCosmWasmClient", () => { }, ); - const rest = new RestClient(httpUrl); - const state1 = await rest.getContractInfo(contractAddress); + const lcdClient = makeWasmClient(httpUrl); + const state1 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state1); expect(state1.admin).toEqual(alice.address0); await client.clearAdmin(contractAddress); - const state2 = await rest.getContractInfo(contractAddress); + const state2 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state2); expect(state2.admin).toBeUndefined(); }); @@ -238,15 +242,15 @@ describe("SigningCosmWasmClient", () => { }, ); - const rest = new RestClient(httpUrl); - const state1 = await rest.getContractInfo(contractAddress); + const lcdClient = makeWasmClient(httpUrl); + const state1 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state1); expect(state1.admin).toEqual(alice.address0); const newVerifier = makeRandomAddress(); await client.migrate(contractAddress, codeId2, { verifier: newVerifier }); - const state2 = await rest.getContractInfo(contractAddress); + const state2 = await lcdClient.wasm.getContractInfo(contractAddress); assert(state2); expect(state2).toEqual({ ...state1, @@ -289,10 +293,10 @@ describe("SigningCosmWasmClient", () => { }); // Verify token transfer from contract to beneficiary - const rest = new RestClient(httpUrl); - const beneficiaryBalance = (await rest.authAccounts(beneficiaryAddress)).result.value.coins; + const lcdClient = makeWasmClient(httpUrl); + const beneficiaryBalance = (await lcdClient.auth.account(beneficiaryAddress)).result.value.coins; expect(beneficiaryBalance).toEqual(transferAmount); - const contractBalance = (await rest.authAccounts(contractAddress)).result.value.coins; + const contractBalance = (await lcdClient.auth.account(contractAddress)).result.value.coins; expect(contractBalance).toEqual([]); }); }); diff --git a/packages/cosmwasm/types/cosmwasmclient.d.ts b/packages/cosmwasm/types/cosmwasmclient.d.ts index 82eecb72..c72cdc17 100644 --- a/packages/cosmwasm/types/cosmwasmclient.d.ts +++ b/packages/cosmwasm/types/cosmwasmclient.d.ts @@ -1,6 +1,15 @@ -import { BroadcastMode, Coin, CosmosSdkTx, IndexedTx, PubKey, StdTx } from "@cosmjs/sdk38"; +import { + AuthExtension, + BroadcastMode, + Coin, + CosmosSdkTx, + IndexedTx, + LcdClient, + PubKey, + StdTx, +} from "@cosmjs/sdk38"; +import { WasmExtension } from "./lcdapi/wasm"; import { Log } from "./logs"; -import { RestClient } from "./restclient"; import { JsonObject } from "./types"; export interface GetNonceResult { readonly accountNumber: number; @@ -114,10 +123,10 @@ export interface Block { } /** Use for testing only */ export interface PrivateCosmWasmClient { - readonly restClient: RestClient; + readonly lcdClient: LcdClient & AuthExtension & WasmExtension; } export declare class CosmWasmClient { - protected readonly restClient: RestClient; + protected readonly lcdClient: LcdClient & AuthExtension & WasmExtension; /** Any address the chain considers valid (valid bech32 with proper prefix) */ protected anyValidAddress: string | undefined; private readonly codesCache;