diff --git a/packages/stargate/src/queries/bank.spec.ts b/packages/stargate/src/queries/bank.spec.ts index 8806fa3d..e6fdc1c9 100644 --- a/packages/stargate/src/queries/bank.spec.ts +++ b/packages/stargate/src/queries/bank.spec.ts @@ -37,39 +37,125 @@ describe("BankExtension", () => { tmClient.disconnect(); }); - it("returns null for non-existent balance", async () => { + it("returns zero for non-existent balance", async () => { pendingWithoutSimapp(); const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); const response = await client.bank.balance(unused.address, "gintonic"); - expect(response).toBeNull(); + expect(response).toEqual({ + amount: "0", + denom: "gintonic", + }); tmClient.disconnect(); }); - it("returns null for non-existent address", async () => { + it("returns zero for non-existent address", async () => { pendingWithoutSimapp(); const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); const response = await client.bank.balance(nonExistentAddress, simapp.denomFee); - expect(response).toBeNull(); + expect(response).toEqual({ + amount: "0", + denom: simapp.denomFee, + }); tmClient.disconnect(); }); }); - describe("unverified", () => { + describe("allBalances", () => { + it("returns all balances for unused account", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); + + const balances = await client.bank.allBalances(unused.address); + expect(balances).toEqual([ + { + amount: unused.balanceFee, + denom: simapp.denomFee, + }, + { + amount: unused.balanceStaking, + denom: simapp.denomStaking, + }, + ]); + + tmClient.disconnect(); + }); + + it("returns an empty list for non-existent account", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); + + const balances = await client.bank.allBalances(nonExistentAddress); + expect(balances).toEqual([]); + + tmClient.disconnect(); + }); + }); + + describe("totalSupply", () => { + it("works", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); + + const response = await client.bank.totalSupply(); + expect(response).toEqual([ + { + amount: simapp.totalSupply.toString(), + denom: simapp.denomFee, + }, + { + amount: jasmine.stringMatching(nonNegativeIntegerMatcher), + denom: simapp.denomStaking, + }, + ]); + + tmClient.disconnect(); + }); + }); + + describe("supplyOf", () => { + it("works for existing denom", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); + + const response = await client.bank.supplyOf(simapp.denomFee); + expect(response).toEqual({ + amount: simapp.totalSupply.toString(), + denom: simapp.denomFee, + }); + + tmClient.disconnect(); + }); + + it("returns zero for non-existent denom", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); + + const response = await client.bank.supplyOf("gintonic"); + expect(response).toEqual({ + amount: "0", + denom: "gintonic", + }); + + tmClient.disconnect(); + }); + }); + + describe("verified", () => { describe("balance", () => { it("works for different existing balances", async () => { pendingWithoutSimapp(); const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - const response1 = await client.bank.unverified.balance(unused.address, simapp.denomFee); + const response1 = await client.bank.verified.balance(unused.address, simapp.denomFee); expect(response1).toEqual({ amount: unused.balanceFee, denom: simapp.denomFee, }); - const response2 = await client.bank.unverified.balance(unused.address, simapp.denomStaking); + const response2 = await client.bank.verified.balance(unused.address, simapp.denomStaking); expect(response2).toEqual({ amount: unused.balanceStaking, denom: simapp.denomStaking, @@ -78,108 +164,22 @@ describe("BankExtension", () => { tmClient.disconnect(); }); - it("returns zero for non-existent balance", async () => { + it("returns null for non-existent balance", async () => { pendingWithoutSimapp(); const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - const response = await client.bank.unverified.balance(unused.address, "gintonic"); - expect(response).toEqual({ - amount: "0", - denom: "gintonic", - }); + const response = await client.bank.verified.balance(unused.address, "gintonic"); + expect(response).toBeNull(); tmClient.disconnect(); }); - it("returns zero for non-existent address", async () => { + it("returns null for non-existent address", async () => { pendingWithoutSimapp(); const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - const response = await client.bank.unverified.balance(nonExistentAddress, simapp.denomFee); - expect(response).toEqual({ - amount: "0", - denom: simapp.denomFee, - }); - - tmClient.disconnect(); - }); - }); - - describe("allBalances", () => { - it("returns all balances for unused account", async () => { - pendingWithoutSimapp(); - const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - - const balances = await client.bank.unverified.allBalances(unused.address); - expect(balances).toEqual([ - { - amount: unused.balanceFee, - denom: simapp.denomFee, - }, - { - amount: unused.balanceStaking, - denom: simapp.denomStaking, - }, - ]); - - tmClient.disconnect(); - }); - - it("returns an empty list for non-existent account", async () => { - pendingWithoutSimapp(); - const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - - const balances = await client.bank.unverified.allBalances(nonExistentAddress); - expect(balances).toEqual([]); - - tmClient.disconnect(); - }); - }); - - describe("totalSupply", () => { - it("works", async () => { - pendingWithoutSimapp(); - const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - - const response = await client.bank.unverified.totalSupply(); - expect(response).toEqual([ - { - amount: simapp.totalSupply.toString(), - denom: simapp.denomFee, - }, - { - amount: jasmine.stringMatching(nonNegativeIntegerMatcher), - denom: simapp.denomStaking, - }, - ]); - - tmClient.disconnect(); - }); - }); - - describe("supplyOf", () => { - it("works for existing denom", async () => { - pendingWithoutSimapp(); - const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - - const response = await client.bank.unverified.supplyOf(simapp.denomFee); - expect(response).toEqual({ - amount: simapp.totalSupply.toString(), - denom: simapp.denomFee, - }); - - tmClient.disconnect(); - }); - - it("returns zero for non-existent denom", async () => { - pendingWithoutSimapp(); - const [client, tmClient] = await makeClientWithBank(simapp.tendermintUrl); - - const response = await client.bank.unverified.supplyOf("gintonic"); - expect(response).toEqual({ - amount: "0", - denom: "gintonic", - }); + const response = await client.bank.verified.balance(nonExistentAddress, simapp.denomFee); + expect(response).toBeNull(); tmClient.disconnect(); }); diff --git a/packages/stargate/src/queries/bank.ts b/packages/stargate/src/queries/bank.ts index 0537b3f5..2b684778 100644 --- a/packages/stargate/src/queries/bank.ts +++ b/packages/stargate/src/queries/bank.ts @@ -9,12 +9,12 @@ import { createProtobufRpcClient, toAccAddress } from "./utils"; export interface BankExtension { readonly bank: { - readonly balance: (address: string, denom: string) => Promise; - readonly unverified: { - readonly balance: (address: string, denom: string) => Promise; - readonly allBalances: (address: string) => Promise; - readonly totalSupply: () => Promise; - readonly supplyOf: (denom: string) => Promise; + readonly balance: (address: string, denom: string) => Promise; + readonly allBalances: (address: string) => Promise; + readonly totalSupply: () => Promise; + readonly supplyOf: (denom: string) => Promise; + readonly verified: { + readonly balance: (address: string, denom: string) => Promise; }; }; } @@ -28,34 +28,34 @@ export function setupBankExtension(base: QueryClient): BankExtension { return { bank: { balance: async (address: string, denom: string) => { - // balance key is a bit tricker, using some prefix stores - // https://github.com/cosmwasm/cosmos-sdk/blob/80f7ff62f79777a487d0c7a53c64b0f7e43c47b9/x/bank/keeper/view.go#L74-L77 - // ("balances", binAddress, denom) - // it seem like prefix stores just do a dumb concat with the keys (no tricks to avoid overlap) - // https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L61-L64 - // https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L37-L43 - const key = Uint8Array.from([...toAscii("balances"), ...toAccAddress(address), ...toAscii(denom)]); - const responseData = await base.queryVerified("bank", key); - return responseData.length ? Coin.decode(responseData) : null; + const { balance } = await queryService.Balance({ address: address, denom: denom }); + assert(balance); + return balance; }, - unverified: { + allBalances: async (address: string) => { + const { balances } = await queryService.AllBalances({ address: address }); + return balances; + }, + totalSupply: async () => { + const { supply } = await queryService.TotalSupply({}); + return supply; + }, + supplyOf: async (denom: string) => { + const { amount } = await queryService.SupplyOf({ denom: denom }); + assert(amount); + return amount; + }, + verified: { balance: async (address: string, denom: string) => { - const { balance } = await queryService.Balance({ address: address, denom: denom }); - assert(balance); - return balance; - }, - allBalances: async (address: string) => { - const { balances } = await queryService.AllBalances({ address: address }); - return balances; - }, - totalSupply: async () => { - const { supply } = await queryService.TotalSupply({}); - return supply; - }, - supplyOf: async (denom: string) => { - const { amount } = await queryService.SupplyOf({ denom: denom }); - assert(amount); - return amount; + // balance key is a bit tricker, using some prefix stores + // https://github.com/cosmwasm/cosmos-sdk/blob/80f7ff62f79777a487d0c7a53c64b0f7e43c47b9/x/bank/keeper/view.go#L74-L77 + // ("balances", binAddress, denom) + // it seem like prefix stores just do a dumb concat with the keys (no tricks to avoid overlap) + // https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L61-L64 + // https://github.com/cosmos/cosmos-sdk/blob/2879c0702c87dc9dd828a8c42b9224dc054e28ad/store/prefix/store.go#L37-L43 + const key = Uint8Array.from([...toAscii("balances"), ...toAccAddress(address), ...toAscii(denom)]); + const responseData = await base.queryVerified("bank", key); + return responseData.length ? Coin.decode(responseData) : null; }, }, }, diff --git a/packages/stargate/src/signingstargateclient.spec.ts b/packages/stargate/src/signingstargateclient.spec.ts index 7caaa979..4d79a1b6 100644 --- a/packages/stargate/src/signingstargateclient.spec.ts +++ b/packages/stargate/src/signingstargateclient.spec.ts @@ -241,7 +241,10 @@ describe("SigningStargateClient", () => { // no tokens here const before = await client.getBalance(beneficiaryAddress, "ucosm"); - expect(before).toBeNull(); + expect(before).toEqual({ + denom: "ucosm", + amount: "0", + }); // send const result = await client.sendTokens(faucet.address0, beneficiaryAddress, transferAmount, memo); @@ -265,7 +268,10 @@ describe("SigningStargateClient", () => { // no tokens here const before = await client.getBalance(beneficiaryAddress, "ucosm"); - expect(before).toBeNull(); + expect(before).toEqual({ + denom: "ucosm", + amount: "0", + }); // send const result = await client.sendTokens(faucet.address0, beneficiaryAddress, transferAmount, memo); diff --git a/packages/stargate/src/stargateclient.spec.ts b/packages/stargate/src/stargateclient.spec.ts index e8791532..7e42e103 100644 --- a/packages/stargate/src/stargateclient.spec.ts +++ b/packages/stargate/src/stargateclient.spec.ts @@ -213,33 +213,39 @@ describe("StargateClient", () => { client.disconnect(); }); - it("returns null for non-existent balance", async () => { + it("returns 0 for non-existent balance", async () => { pendingWithoutSimapp(); const client = await StargateClient.connect(simapp.tendermintUrl); const response = await client.getBalance(unused.address, "gintonic"); - expect(response).toBeNull(); + expect(response).toEqual({ + denom: "gintonic", + amount: "0", + }); client.disconnect(); }); - it("returns null for non-existent address", async () => { + it("returns 0 for non-existent address", async () => { pendingWithoutSimapp(); const client = await StargateClient.connect(simapp.tendermintUrl); const response = await client.getBalance(nonExistentAddress, simapp.denomFee); - expect(response).toBeNull(); + expect(response).toEqual({ + denom: simapp.denomFee, + amount: "0", + }); client.disconnect(); }); }); - describe("getAllBalancesUnverified", () => { + describe("getAllBalances", () => { it("returns all balances for unused account", async () => { pendingWithoutSimapp(); const client = await StargateClient.connect(simapp.tendermintUrl); - const balances = await client.getAllBalancesUnverified(unused.address); + const balances = await client.getAllBalances(unused.address); expect(balances).toEqual([ { amount: unused.balanceFee, @@ -258,7 +264,7 @@ describe("StargateClient", () => { pendingWithoutSimapp(); const client = await StargateClient.connect(simapp.tendermintUrl); - const balances = await client.getAllBalancesUnverified(nonExistentAddress); + const balances = await client.getAllBalances(nonExistentAddress); expect(balances).toEqual([]); client.disconnect(); diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index 7cf1e2b8..36f69b2a 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -207,7 +207,7 @@ export class StargateClient { }; } - public async getBalance(address: string, searchDenom: string): Promise { + public async getBalance(address: string, searchDenom: string): Promise { return this.forceGetQueryClient().bank.balance(address, searchDenom); } @@ -217,8 +217,8 @@ export class StargateClient { * Uses the grpc queries (which iterates over the store internally), and we cannot get * proofs from such a method. */ - public async getAllBalancesUnverified(address: string): Promise { - return this.forceGetQueryClient().bank.unverified.allBalances(address); + public async getAllBalances(address: string): Promise { + return this.forceGetQueryClient().bank.allBalances(address); } public async getTx(id: string): Promise {