Merge pull request #94 from confio/cosm-get-account
Add getAccount to CosmWasmClient
This commit is contained in:
commit
d3bcee9dd4
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
9
packages/bcp/types/address.d.ts
vendored
9
packages/bcp/types/address.d.ts
vendored
@ -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;
|
||||
|
||||
2
packages/bcp/types/cosmwasmconnection.d.ts
vendored
2
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -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;
|
||||
|
||||
@ -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", () => {
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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", () => {
|
||||
|
||||
5
packages/sdk/types/cosmwasmclient.d.ts
vendored
5
packages/sdk/types/cosmwasmclient.d.ts
vendored
@ -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
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user