diff --git a/packages/stargate/package.json b/packages/stargate/package.json index 732e2325..26ed5950 100644 --- a/packages/stargate/package.json +++ b/packages/stargate/package.json @@ -26,7 +26,7 @@ "format-text": "prettier --write --prose-wrap always --print-width 80 \"./*.md\"", "lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"", "lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix", - "move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts", + "move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts && shx rm ./types/**/*.spec.d.ts", "format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"", "prebuild": "shx rm -rf ./build", "build": "tsc && shx mkdir -p build/generated && shx cp ./src/generated/*.js ./build/generated && shx mkdir -p ./build/types/generated && shx cp ./src/generated/*.d.ts ./build/types/generated", diff --git a/packages/stargate/src/queries/bank.spec.ts b/packages/stargate/src/queries/bank.spec.ts new file mode 100644 index 00000000..bb50bcd3 --- /dev/null +++ b/packages/stargate/src/queries/bank.spec.ts @@ -0,0 +1,47 @@ +import { Client as TendermintClient } from "@cosmjs/tendermint-rpc"; + +import { QueryClient } from "../queryclient"; +import { nonExistentAddress, pendingWithoutSimapp, simapp, unused } from "../testutils.spec"; +import { BankExtension, setupBankExtension } from "./bank"; + +async function makeBankClient(rpcUrl: string): Promise { + // TODO: tmClient is not owned by QueryClient but should be disconnected somehow (once we use WebSockets) + const tmClient = await TendermintClient.connect(rpcUrl); + return QueryClient.withExtensions(tmClient, setupBankExtension); +} + +describe("BankExtension", () => { + describe("balance", () => { + it("works for different existing balances", async () => { + pendingWithoutSimapp(); + const client = await makeBankClient(simapp.tendermintUrl); + + const response1 = await client.bank.balance(unused.address, simapp.denomFee); + expect(response1).toEqual({ + amount: unused.balanceFee, + denom: simapp.denomFee, + }); + const response2 = await client.bank.balance(unused.address, simapp.denomStaking); + expect(response2).toEqual({ + amount: unused.balanceStaking, + denom: simapp.denomStaking, + }); + }); + + it("returns null for non-existent balance", async () => { + pendingWithoutSimapp(); + const client = await makeBankClient(simapp.tendermintUrl); + + const response = await client.bank.balance(unused.address, "gintonic"); + expect(response).toBeNull(); + }); + + it("returns null for non-existent address", async () => { + pendingWithoutSimapp(); + const client = await makeBankClient(simapp.tendermintUrl); + + const response = await client.bank.balance(nonExistentAddress, simapp.denomFee); + expect(response).toBeNull(); + }); + }); +}); diff --git a/packages/stargate/src/queries/bank.ts b/packages/stargate/src/queries/bank.ts index 29f4629d..b6a93a0d 100644 --- a/packages/stargate/src/queries/bank.ts +++ b/packages/stargate/src/queries/bank.ts @@ -3,9 +3,17 @@ import { Bech32, toAscii } from "@cosmjs/encoding"; import { cosmos } from "../generated/codecimpl"; import { QueryClient } from "../queryclient"; +/** + * Use this to convert a protobuf.js class to the interface (e.g. Coin to ICoin) + * in a ways that makes Jasmine's toEqual happy. + */ +function toObject(thing: I): O { + return { ...thing }; +} + export interface BankExtension { readonly bank: { - readonly balance: (address: string, denom: string) => Promise; + readonly balance: (address: string, denom: string) => Promise; readonly unverified: { readonly balances: (address: string) => Promise; }; @@ -36,7 +44,7 @@ export function setupBankExtension(base: QueryClient): BankExtension { const binAddress = Bech32.decode(address).data; const bankKey = Uint8Array.from([...toAscii("balances"), ...binAddress, ...toAscii(denom)]); const responseData = await base.queryVerified("bank", bankKey); - return cosmos.Coin.decode(responseData); + return responseData.length ? toObject(cosmos.Coin.decode(responseData)) : null; }, unverified: { balances: async (address: string) => { diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index 6354e302..9cf168f6 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -194,11 +194,7 @@ export class StargateClient { public async getBalance(address: string, searchDenom: string): Promise { const balance = await this.queryClient.bank.balance(address, searchDenom); - if (!balance?.denom) { - return null; - } else { - return coinFromProto(balance); - } + return balance ? coinFromProto(balance) : null; } /** diff --git a/packages/stargate/types/queries/bank.d.ts b/packages/stargate/types/queries/bank.d.ts index 4e626954..48cabf7d 100644 --- a/packages/stargate/types/queries/bank.d.ts +++ b/packages/stargate/types/queries/bank.d.ts @@ -2,7 +2,7 @@ import { cosmos } from "../generated/codecimpl"; import { QueryClient } from "../queryclient"; export interface BankExtension { readonly bank: { - readonly balance: (address: string, denom: string) => Promise; + readonly balance: (address: string, denom: string) => Promise; readonly unverified: { readonly balances: (address: string) => Promise; };