From c414aad30427dec9b748557b6c42acecd141ffa6 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Tue, 30 Mar 2021 18:00:30 +0200 Subject: [PATCH 1/4] stargate: Rearrange bank query extension --- packages/stargate/src/queries/bank.spec.ts | 198 +++++++++--------- packages/stargate/src/queries/bank.ts | 64 +++--- .../src/signingstargateclient.spec.ts | 10 +- packages/stargate/src/stargateclient.spec.ts | 20 +- packages/stargate/src/stargateclient.ts | 6 +- 5 files changed, 155 insertions(+), 143 deletions(-) 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 { From 253494d29dc62573c318038810fff3f9d2cb016d Mon Sep 17 00:00:00 2001 From: willclarktech Date: Tue, 30 Mar 2021 18:04:52 +0200 Subject: [PATCH 2/4] cosmwasm-stargate: Update for bank extension change --- packages/cosmwasm-stargate/src/cosmwasmclient.ts | 2 +- .../src/signingcosmwasmclient.spec.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.ts index b6d57e64..f6abd719 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.ts @@ -150,7 +150,7 @@ export class CosmWasmClient { }; } - public async getBalance(address: string, searchDenom: string): Promise { + public async getBalance(address: string, searchDenom: string): Promise { return this.forceGetQueryClient().bank.balance(address, searchDenom); } diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts index 6cc493a1..0398b8e1 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts @@ -498,7 +498,10 @@ describe("SigningCosmWasmClient", () => { // 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(alice.address0, beneficiaryAddress, transferAmount, memo); @@ -523,7 +526,10 @@ describe("SigningCosmWasmClient", () => { // 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(alice.address0, beneficiaryAddress, transferAmount, memo); From bb3265b70c4fc366d7c8f83962fcf630a6655cea Mon Sep 17 00:00:00 2001 From: willclarktech Date: Tue, 30 Mar 2021 18:05:02 +0200 Subject: [PATCH 3/4] Update CHANGELOG for bank query changes --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aea3304..fdb20285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,8 +77,8 @@ and this project adheres to `Bech32.encode(prefix, rawSecp256k1PubkeyToRawAddress(pubkeyRaw))` with `rawSecp256k1PubkeyToRawAddress` from @cosmjs/amino. - @cosmjs/stargate: `parseRawLog` is now nested under the `logs` export. -- @cosmjs/stargate: `auth` extension now has unverified queries at the root and - verified queries nested under `.verified`. +- @cosmjs/stargate: `auth` and `bank` extensions now have unverified queries at + the root and verified queries nested under `.verified`. - @cosmjs/stargate: `StargateClient.getAccount` now uses an unverified query and `StargateClient.getAccountUnverified` has been removed. `StargateClient.getAccountVerified` has been added, which performs a verified @@ -89,8 +89,14 @@ and this project adheres to query. - @cosmjs/stargate: `StargateClient.getSequence` now rejects if the account is not found, instead of returning null. +- @cosmjs/stargate: `StargateClient.getBalance` now returns a 0 balance instead + of null. +- @cosmjs/stargate: `StargateClient.getAllBalancesUnverified` has been renamed + `.getAllBalances`. - @cosmjs/cosmwasm-stargate: `CosmWasmClient.getSequence` now rejects if the account is not found, instead of returning null. +- @cosmjs/cosmwasm-stargate: `CosmWasmClient.getBalance` now returns a 0 balance + instead of null. ### Deprecated From 45d5e1417a657cb779fb4c32106857b1233affd0 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 31 Mar 2021 11:28:54 +0200 Subject: [PATCH 4/4] faucet: Update for bank extension change --- packages/faucet/src/faucet.spec.ts | 14 ++++++-------- packages/faucet/src/faucet.ts | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/faucet/src/faucet.spec.ts b/packages/faucet/src/faucet.spec.ts index 10494efd..14f285ad 100644 --- a/packages/faucet/src/faucet.spec.ts +++ b/packages/faucet/src/faucet.spec.ts @@ -321,7 +321,7 @@ describe("Faucet", () => { }); const readOnlyClient = await StargateClient.connect(apiUrl); - const account = await readOnlyClient.getAllBalancesUnverified(recipient); + const account = await readOnlyClient.getAllBalances(recipient); assert(account); expect(account).toEqual([ { @@ -345,9 +345,7 @@ describe("Faucet", () => { ); await faucet.refill(); const readOnlyClient = await StargateClient.connect(apiUrl); - const distributorBalance = await readOnlyClient.getAllBalancesUnverified( - faucet.distributorAddresses[0], - ); + const distributorBalance = await readOnlyClient.getAllBalances(faucet.distributorAddresses[0]); assert(distributorBalance); expect(distributorBalance).toEqual([ jasmine.objectContaining({ @@ -377,7 +375,7 @@ describe("Faucet", () => { await faucet.credit(recipient, "ucosm"); const readOnlyClient = await StargateClient.connect(apiUrl); - const balance = await readOnlyClient.getAllBalancesUnverified(recipient); + const balance = await readOnlyClient.getAllBalances(recipient); assert(balance); expect(balance).toEqual([ { @@ -401,7 +399,7 @@ describe("Faucet", () => { await faucet.credit(recipient, "ustake"); const readOnlyClient = await StargateClient.connect(apiUrl); - const balance = await readOnlyClient.getAllBalancesUnverified(recipient); + const balance = await readOnlyClient.getAllBalances(recipient); assert(balance); expect(balance).toEqual([ { @@ -442,8 +440,8 @@ describe("Faucet", () => { const accounts = await faucet.loadAccounts(); const readOnlyClient = await StargateClient.connect(apiUrl); - const expectedHolderBalance = await readOnlyClient.getAllBalancesUnverified(faucet.holderAddress); - const expectedDistributorBalance = await readOnlyClient.getAllBalancesUnverified( + const expectedHolderBalance = await readOnlyClient.getAllBalances(faucet.holderAddress); + const expectedDistributorBalance = await readOnlyClient.getAllBalances( faucet.distributorAddresses[0], ); assert(expectedHolderBalance); diff --git a/packages/faucet/src/faucet.ts b/packages/faucet/src/faucet.ts index c61a9890..8df97e29 100644 --- a/packages/faucet/src/faucet.ts +++ b/packages/faucet/src/faucet.ts @@ -114,7 +114,7 @@ export class Faucet { const balance = this.readOnlyClient instanceof CosmosClient ? (await this.readOnlyClient.getAccount(address))?.balance ?? [] - : await this.readOnlyClient.getAllBalancesUnverified(address); + : await this.readOnlyClient.getAllBalances(address); return { address: address,