From b39a54211b4fc7318ad8dd10a897d6656b6c74a1 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Sun, 16 Feb 2020 19:08:16 +0100 Subject: [PATCH 1/8] Add getAccount to CosmWasmClient --- packages/sdk/src/cosmwasmclient.spec.ts | 19 +++++++++++++++++++ packages/sdk/src/cosmwasmclient.ts | 8 +++++++- packages/sdk/types/cosmwasmclient.d.ts | 3 ++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index b2098969..2994e3b9 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -73,6 +73,25 @@ describe("CosmWasmClient", () => { sequence: 0, }); }); + + + }); + + describe("getAccount", () => { + it("works", async () => { + pendingWithoutCosmos(); + const client = CosmWasmClient.makeReadOnly(httpUrl); + expect(await client.getAccount(unusedAccount.address)).toEqual({ + address: unusedAccount.address, + account_number: 5, + sequence: 0, + public_key: "", + coins: [ + {denom: 'ucosm', amount: '1000000000'}, + {denom: 'ustake', amount: '1000000000'}, + ], + }); + }); }); describe("getBlock", () => { diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index b80e86f8..55335904 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -12,6 +12,7 @@ import { MsgStoreCode, StdFee, StdSignature, + CosmosSdkAccount, } from "./types"; const defaultUploadFee: StdFee = { @@ -150,13 +151,18 @@ export class CosmWasmClient { * @param address returns data for this address. When unset, the client's sender adddress is used. */ public async getNonce(address?: string): Promise { - const account = (await this.restClient.authAccounts(address || this.senderAddress)).result.value; + const account = await this.getAccount(address); return { accountNumber: account.account_number, sequence: account.sequence, }; } + public async getAccount(address?: string): Promise { + const account = await this.restClient.authAccounts(address || this.senderAddress); + return account.result.value; + } + /** * Gets block header and meta * diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index bd66f743..da430498 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -1,6 +1,6 @@ import { Log } from "./logs"; import { BlockResponse, TxsResponse } from "./restclient"; -import { Coin, CosmosSdkTx, StdSignature } from "./types"; +import { Coin, CosmosSdkTx, StdSignature, CosmosSdkAccount } from "./types"; export interface SigningCallback { (signBytes: Uint8Array): Promise; } @@ -46,6 +46,7 @@ export declare class CosmWasmClient { * @param address returns data for this address. When unset, the client's sender adddress is used. */ getNonce(address?: string): Promise; + getAccount(address?: string): Promise; /** * Gets block header and meta * From d079f7673a669650b83dc371972db30ad6e2a273 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Sun, 16 Feb 2020 19:13:53 +0100 Subject: [PATCH 2/8] getAccount returns undefined when address not found --- packages/sdk/src/cosmwasmclient.spec.ts | 21 ++++++++++++++++++--- packages/sdk/src/cosmwasmclient.ts | 9 +++++---- packages/sdk/types/cosmwasmclient.d.ts | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index 2994e3b9..29628d49 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -74,7 +74,15 @@ describe("CosmWasmClient", () => { }); }); - + it("returns zeros for missing accounts", async () => { + pendingWithoutCosmos(); + const client = CosmWasmClient.makeReadOnly(httpUrl); + const missing = makeRandomAddress(); + expect(await client.getNonce(missing)).toEqual({ + accountNumber: 0, + sequence: 0, + }); + }); }); describe("getAccount", () => { @@ -87,11 +95,18 @@ describe("CosmWasmClient", () => { sequence: 0, public_key: "", coins: [ - {denom: 'ucosm', amount: '1000000000'}, - {denom: 'ustake', amount: '1000000000'}, + { denom: "ucosm", amount: "1000000000" }, + { denom: "ustake", amount: "1000000000" }, ], }); }); + + it("returns undefined for missing accounts", async () => { + pendingWithoutCosmos(); + const client = CosmWasmClient.makeReadOnly(httpUrl); + const missing = makeRandomAddress(); + expect(await client.getAccount(missing)).toBeUndefined(); + }); }); describe("getBlock", () => { diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 55335904..f7c58231 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -153,14 +153,15 @@ export class CosmWasmClient { public async getNonce(address?: string): Promise { const account = await this.getAccount(address); return { - accountNumber: account.account_number, - sequence: account.sequence, + accountNumber: account ? account.account_number : 0, + sequence: account ? account.sequence : 0, }; } - public async getAccount(address?: string): Promise { + public async getAccount(address?: string): Promise { const account = await this.restClient.authAccounts(address || this.senderAddress); - return account.result.value; + const value = account.result.value; + return value.address === "" ? undefined : value; } /** diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index da430498..70e07e10 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -46,7 +46,7 @@ export declare class CosmWasmClient { * @param address returns data for this address. When unset, the client's sender adddress is used. */ getNonce(address?: string): Promise; - getAccount(address?: string): Promise; + getAccount(address?: string): Promise; /** * Gets block header and meta * From 7bc76bd59b9c5a5e21bdceea923a78e39fa4b50f Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Sun, 16 Feb 2020 19:15:52 +0100 Subject: [PATCH 3/8] Fix linter warnings --- packages/sdk/src/cosmwasmclient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index f7c58231..d15fbedb 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -6,13 +6,13 @@ import { findAttribute, Log, parseLogs } from "./logs"; import { BlockResponse, RestClient, TxsResponse } from "./restclient"; import { Coin, + CosmosSdkAccount, CosmosSdkTx, MsgExecuteContract, MsgInstantiateContract, MsgStoreCode, StdFee, StdSignature, - CosmosSdkAccount, } from "./types"; const defaultUploadFee: StdFee = { From 03f01f54d682e1f71fd90df04f06c024b76c07ad Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Feb 2020 12:31:41 +0100 Subject: [PATCH 4/8] Test empty address in RestClient.authAccounts --- packages/sdk/src/restclient.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 09ca66b5..1e45b8e9 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -290,6 +290,18 @@ describe("RestClient", () => { }), ); }); + + // This property is used by CosmWasmClient.getAccount + it("returns empty address for non-existent account", async () => { + pendingWithoutCosmos(); + const client = new RestClient(httpUrl); + const nonExistentAccount = makeRandomAddress(); + const { result } = await client.authAccounts(nonExistentAccount); + expect(result).toEqual({ + type: "cosmos-sdk/Account", + value: jasmine.objectContaining({ address: "" }), + }); + }); }); describe("encodeTx", () => { From 28ee35217e9b6fa0cc4eae6968a5264220add09c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Feb 2020 12:31:59 +0100 Subject: [PATCH 5/8] Let CosmWasmClient.getNonce throw --- packages/sdk/src/cosmwasmclient.spec.ts | 10 +++++----- packages/sdk/src/cosmwasmclient.ts | 11 +++++++++-- packages/sdk/types/cosmwasmclient.d.ts | 4 +++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index 29628d49..319610a8 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -74,14 +74,14 @@ describe("CosmWasmClient", () => { }); }); - it("returns zeros for missing accounts", async () => { + it("throws for missing accounts", async () => { pendingWithoutCosmos(); const client = CosmWasmClient.makeReadOnly(httpUrl); const missing = makeRandomAddress(); - expect(await client.getNonce(missing)).toEqual({ - accountNumber: 0, - sequence: 0, - }); + await client.getNonce(missing).then( + () => fail("this must not succeed"), + error => expect(error).toMatch(/account does not exist on chain/i), + ); }); }); diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index d15fbedb..be66846d 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -148,13 +148,20 @@ export class CosmWasmClient { /** * Returns account number and sequence. * + * Throws if the account does not exist on chain. + * * @param address returns data for this address. When unset, the client's sender adddress is used. */ public async getNonce(address?: string): Promise { const account = await this.getAccount(address); + if (!account) { + throw new Error( + "Account does not exist on chain. Send some tokens there before trying to query nonces.", + ); + } return { - accountNumber: account ? account.account_number : 0, - sequence: account ? account.sequence : 0, + accountNumber: account.account_number, + sequence: account.sequence, }; } diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index 70e07e10..93fd5216 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -1,6 +1,6 @@ import { Log } from "./logs"; import { BlockResponse, TxsResponse } from "./restclient"; -import { Coin, CosmosSdkTx, StdSignature, CosmosSdkAccount } from "./types"; +import { Coin, CosmosSdkAccount, CosmosSdkTx, StdSignature } from "./types"; export interface SigningCallback { (signBytes: Uint8Array): Promise; } @@ -43,6 +43,8 @@ export declare class CosmWasmClient { /** * Returns account number and sequence. * + * Throws if the account does not exist on chain. + * * @param address returns data for this address. When unset, the client's sender adddress is used. */ getNonce(address?: string): Promise; From f8051b93dc3c5ac9bfd480dd4eae4c7e4c6cc2a1 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Feb 2020 12:36:55 +0100 Subject: [PATCH 6/8] Use BCP type in decodeCosmosPubkey --- packages/bcp/src/address.ts | 4 +--- packages/bcp/types/address.d.ts | 9 ++------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/bcp/src/address.ts b/packages/bcp/src/address.ts index c702edea..82046fdf 100644 --- a/packages/bcp/src/address.ts +++ b/packages/bcp/src/address.ts @@ -5,9 +5,7 @@ import { Encoding } from "@iov/encoding"; const { fromBase64, toBase64 } = Encoding; -export function decodeCosmosPubkey( - encodedPubkey: string, -): { readonly algo: Algorithm; readonly data: PubkeyBytes } { +export function decodeCosmosPubkey(encodedPubkey: string): PubkeyBundle { const sdkPubKey = decodeBech32Pubkey(encodedPubkey); switch (sdkPubKey.type) { case types.pubkeyType.secp256k1: diff --git a/packages/bcp/types/address.d.ts b/packages/bcp/types/address.d.ts index 7a2c395c..10e6c57a 100644 --- a/packages/bcp/types/address.d.ts +++ b/packages/bcp/types/address.d.ts @@ -1,9 +1,4 @@ import { CosmosAddressBech32Prefix } from "@cosmwasm/sdk"; -import { Address, Algorithm, PubkeyBundle, PubkeyBytes } from "@iov/bcp"; -export declare function decodeCosmosPubkey( - encodedPubkey: string, -): { - readonly algo: Algorithm; - readonly data: PubkeyBytes; -}; +import { Address, PubkeyBundle } from "@iov/bcp"; +export declare function decodeCosmosPubkey(encodedPubkey: string): PubkeyBundle; export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: CosmosAddressBech32Prefix): Address; From fa0fe7e22e59df8439e9f4165a3e21b9f0ceb7f0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Feb 2020 12:38:13 +0100 Subject: [PATCH 7/8] Use cosmWasmClient.getAccount in BCP --- packages/bcp/src/cosmwasmconnection.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/bcp/src/cosmwasmconnection.ts b/packages/bcp/src/cosmwasmconnection.ts index 25122b27..4bacadb1 100644 --- a/packages/bcp/src/cosmwasmconnection.ts +++ b/packages/bcp/src/cosmwasmconnection.ts @@ -154,12 +154,9 @@ export class CosmWasmConnection implements BlockchainConnection { public async getAccount(query: AccountQuery): Promise { const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address; - // tslint:disable-next-line: deprecation - const { result } = await this.restClient.authAccounts(address); - const bankAccount = result.value; - const hasBankAccount = !!bankAccount.address; + const bankAccount = await this.cosmWasmClient.getAccount(address); - const supportedBankCoins = bankAccount.coins.filter(({ denom }) => + const supportedBankCoins = (bankAccount?.coins || []).filter(({ denom }) => this.bankTokens.find(token => token.denom === denom), ); const erc20Amounts = await Promise.all( @@ -179,14 +176,14 @@ export class CosmWasmConnection implements BlockchainConnection { ); const nonZeroErc20Amounts = erc20Amounts.filter(amount => amount.quantity !== "0"); - if (!hasBankAccount && nonZeroErc20Amounts.length === 0) { + if (!bankAccount && nonZeroErc20Amounts.length === 0) { return undefined; } else { const balance = [ ...supportedBankCoins.map(coin => decodeAmount(this.bankTokens, coin)), ...nonZeroErc20Amounts, ].sort((a, b) => a.tokenTicker.localeCompare(b.tokenTicker)); - const pubkey = !bankAccount.public_key ? undefined : decodeCosmosPubkey(bankAccount.public_key); + const pubkey = bankAccount?.public_key ? decodeCosmosPubkey(bankAccount.public_key) : undefined; return { address: address, balance: balance, From 87b6556710d080811936b3a6ff3d509ed32c82ff Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Feb 2020 12:39:38 +0100 Subject: [PATCH 8/8] Remove restClient from CosmWasmConnection --- packages/bcp/src/cosmwasmconnection.ts | 9 +-------- packages/bcp/types/cosmwasmconnection.d.ts | 2 -- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/bcp/src/cosmwasmconnection.ts b/packages/bcp/src/cosmwasmconnection.ts index 4bacadb1..afd6ea70 100644 --- a/packages/bcp/src/cosmwasmconnection.ts +++ b/packages/bcp/src/cosmwasmconnection.ts @@ -3,7 +3,6 @@ import { CosmosAddressBech32Prefix, CosmWasmClient, findSequenceForSignedTx, - RestClient, TxsResponse, types, } from "@cosmwasm/sdk"; @@ -74,10 +73,9 @@ export class CosmWasmConnection implements BlockchainConnection { addressPrefix: CosmosAddressBech32Prefix, tokens: TokenConfiguration, ): Promise { - const restClient = new RestClient(url); const cosmWasmClient = CosmWasmClient.makeReadOnly(url); const chainData = await this.initialize(cosmWasmClient); - return new CosmWasmConnection(restClient, cosmWasmClient, chainData, addressPrefix, tokens); + return new CosmWasmConnection(cosmWasmClient, chainData, addressPrefix, tokens); } private static async initialize(cosmWasmClient: CosmWasmClient): Promise { @@ -88,8 +86,6 @@ export class CosmWasmConnection implements BlockchainConnection { public readonly chainId: ChainId; public readonly codec: TxCodec; - /** @deprecated everything we use from RestClient should be available in CosmWasmClient */ - private readonly restClient: RestClient; private readonly cosmWasmClient: CosmWasmClient; private readonly addressPrefix: CosmosAddressBech32Prefix; private readonly bankTokens: readonly BankToken[]; @@ -100,14 +96,11 @@ export class CosmWasmConnection implements BlockchainConnection { private readonly supportedTokens: readonly Token[]; private constructor( - restClient: RestClient, cosmWasmClient: CosmWasmClient, chainId: ChainId, addressPrefix: CosmosAddressBech32Prefix, tokens: TokenConfiguration, ) { - // tslint:disable-next-line: deprecation - this.restClient = restClient; this.cosmWasmClient = cosmWasmClient; this.chainId = chainId; this.codec = new CosmWasmCodec(addressPrefix, tokens.bankTokens, tokens.erc20Tokens); diff --git a/packages/bcp/types/cosmwasmconnection.d.ts b/packages/bcp/types/cosmwasmconnection.d.ts index 0274f4c8..dff506c5 100644 --- a/packages/bcp/types/cosmwasmconnection.d.ts +++ b/packages/bcp/types/cosmwasmconnection.d.ts @@ -47,8 +47,6 @@ export declare class CosmWasmConnection implements BlockchainConnection { private static initialize; readonly chainId: ChainId; readonly codec: TxCodec; - /** @deprecated everything we use from RestClient should be available in CosmWasmClient */ - private readonly restClient; private readonly cosmWasmClient; private readonly addressPrefix; private readonly bankTokens;