Merge pull request #94 from confio/cosm-get-account

Add getAccount to CosmWasmClient
This commit is contained in:
merge-when-green[bot] 2020-02-17 11:42:42 +00:00 committed by GitHub
commit d3bcee9dd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 29 deletions

View File

@ -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:

View File

@ -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<CosmWasmConnection> {
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<ChainId> {
@ -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);
@ -154,12 +147,9 @@ export class CosmWasmConnection implements BlockchainConnection {
public async getAccount(query: AccountQuery): Promise<Account | undefined> {
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 +169,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,

View File

@ -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;

View File

@ -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;

View File

@ -73,6 +73,40 @@ describe("CosmWasmClient", () => {
sequence: 0,
});
});
it("throws for missing accounts", async () => {
pendingWithoutCosmos();
const client = CosmWasmClient.makeReadOnly(httpUrl);
const missing = makeRandomAddress();
await client.getNonce(missing).then(
() => fail("this must not succeed"),
error => expect(error).toMatch(/account does not exist on chain/i),
);
});
});
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" },
],
});
});
it("returns undefined for missing accounts", async () => {
pendingWithoutCosmos();
const client = CosmWasmClient.makeReadOnly(httpUrl);
const missing = makeRandomAddress();
expect(await client.getAccount(missing)).toBeUndefined();
});
});
describe("getBlock", () => {

View File

@ -6,6 +6,7 @@ import { findAttribute, Log, parseLogs } from "./logs";
import { BlockResponse, RestClient, TxsResponse } from "./restclient";
import {
Coin,
CosmosSdkAccount,
CosmosSdkTx,
MsgExecuteContract,
MsgInstantiateContract,
@ -147,16 +148,29 @@ 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<GetNonceResult> {
const account = (await this.restClient.authAccounts(address || this.senderAddress)).result.value;
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_number,
sequence: account.sequence,
};
}
public async getAccount(address?: string): Promise<CosmosSdkAccount | undefined> {
const account = await this.restClient.authAccounts(address || this.senderAddress);
const value = account.result.value;
return value.address === "" ? undefined : value;
}
/**
* Gets block header and meta
*

View File

@ -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", () => {

View File

@ -1,6 +1,6 @@
import { Log } from "./logs";
import { BlockResponse, TxsResponse } from "./restclient";
import { Coin, CosmosSdkTx, StdSignature } from "./types";
import { Coin, CosmosSdkAccount, CosmosSdkTx, StdSignature } from "./types";
export interface SigningCallback {
(signBytes: Uint8Array): Promise<StdSignature>;
}
@ -43,9 +43,12 @@ 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<GetNonceResult>;
getAccount(address?: string): Promise<CosmosSdkAccount | undefined>;
/**
* Gets block header and meta
*