mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-11 14:09:15 +00:00
Merge pull request #361 from CosmWasm/getAccount-query
Add StargateClient.getAccount
This commit is contained in:
commit
fcd917d2c7
@ -84,7 +84,7 @@ export {
|
|||||||
uint64ToString,
|
uint64ToString,
|
||||||
} from "./lcdapi";
|
} from "./lcdapi";
|
||||||
export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs";
|
export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs";
|
||||||
export { decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey";
|
export { decodeAminoPubkey, decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey";
|
||||||
export { findSequenceForSignedTx } from "./sequence";
|
export { findSequenceForSignedTx } from "./sequence";
|
||||||
export { encodeSecp256k1Signature, decodeSignature } from "./signature";
|
export { encodeSecp256k1Signature, decodeSignature } from "./signature";
|
||||||
export { FeeTable, SigningCosmosClient } from "./signingcosmosclient";
|
export { FeeTable, SigningCosmosClient } from "./signingcosmosclient";
|
||||||
|
@ -21,9 +21,7 @@ const pubkeyAminoPrefixEd25519 = fromHex("1624de6420");
|
|||||||
const pubkeyAminoPrefixSr25519 = fromHex("0dfb1005");
|
const pubkeyAminoPrefixSr25519 = fromHex("0dfb1005");
|
||||||
const pubkeyAminoPrefixLength = pubkeyAminoPrefixSecp256k1.length;
|
const pubkeyAminoPrefixLength = pubkeyAminoPrefixSecp256k1.length;
|
||||||
|
|
||||||
export function decodeBech32Pubkey(bechEncoded: string): PubKey {
|
export function decodeAminoPubkey(data: Uint8Array): PubKey {
|
||||||
const { data } = Bech32.decode(bechEncoded);
|
|
||||||
|
|
||||||
const aminoPrefix = data.slice(0, pubkeyAminoPrefixLength);
|
const aminoPrefix = data.slice(0, pubkeyAminoPrefixLength);
|
||||||
const rest = data.slice(pubkeyAminoPrefixLength);
|
const rest = data.slice(pubkeyAminoPrefixLength);
|
||||||
if (equal(aminoPrefix, pubkeyAminoPrefixSecp256k1)) {
|
if (equal(aminoPrefix, pubkeyAminoPrefixSecp256k1)) {
|
||||||
@ -55,6 +53,11 @@ export function decodeBech32Pubkey(bechEncoded: string): PubKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function decodeBech32Pubkey(bechEncoded: string): PubKey {
|
||||||
|
const { data } = Bech32.decode(bechEncoded);
|
||||||
|
return decodeAminoPubkey(data);
|
||||||
|
}
|
||||||
|
|
||||||
export function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string {
|
export function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string {
|
||||||
let aminoPrefix: Uint8Array;
|
let aminoPrefix: Uint8Array;
|
||||||
switch (pubkey.type) {
|
switch (pubkey.type) {
|
||||||
|
2
packages/launchpad/types/index.d.ts
vendored
2
packages/launchpad/types/index.d.ts
vendored
@ -82,7 +82,7 @@ export {
|
|||||||
uint64ToString,
|
uint64ToString,
|
||||||
} from "./lcdapi";
|
} from "./lcdapi";
|
||||||
export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs";
|
export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs";
|
||||||
export { decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey";
|
export { decodeAminoPubkey, decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey";
|
||||||
export { findSequenceForSignedTx } from "./sequence";
|
export { findSequenceForSignedTx } from "./sequence";
|
||||||
export { encodeSecp256k1Signature, decodeSignature } from "./signature";
|
export { encodeSecp256k1Signature, decodeSignature } from "./signature";
|
||||||
export { FeeTable, SigningCosmosClient } from "./signingcosmosclient";
|
export { FeeTable, SigningCosmosClient } from "./signingcosmosclient";
|
||||||
|
1
packages/launchpad/types/pubkey.d.ts
vendored
1
packages/launchpad/types/pubkey.d.ts
vendored
@ -1,4 +1,5 @@
|
|||||||
import { PubKey } from "./types";
|
import { PubKey } from "./types";
|
||||||
export declare function encodeSecp256k1Pubkey(pubkey: Uint8Array): PubKey;
|
export declare function encodeSecp256k1Pubkey(pubkey: Uint8Array): PubKey;
|
||||||
|
export declare function decodeAminoPubkey(data: Uint8Array): PubKey;
|
||||||
export declare function decodeBech32Pubkey(bechEncoded: string): PubKey;
|
export declare function decodeBech32Pubkey(bechEncoded: string): PubKey;
|
||||||
export declare function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string;
|
export declare function encodeBech32Pubkey(pubkey: PubKey, prefix: string): string;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import { assert } from "@cosmjs/utils";
|
||||||
|
|
||||||
import { StargateClient } from "./stargateclient";
|
import { StargateClient } from "./stargateclient";
|
||||||
import { nonExistentAddress, pendingWithoutSimapp, simapp, unused } from "./testutils.spec";
|
import { nonExistentAddress, pendingWithoutSimapp, simapp, unused, validator } from "./testutils.spec";
|
||||||
|
|
||||||
describe("StargateClient", () => {
|
describe("StargateClient", () => {
|
||||||
describe("connect", () => {
|
describe("connect", () => {
|
||||||
@ -11,14 +13,71 @@ describe("StargateClient", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getAccount", () => {
|
||||||
|
it("works for unused account", async () => {
|
||||||
|
pendingWithoutSimapp();
|
||||||
|
const client = await StargateClient.connect(simapp.tendermintUrl);
|
||||||
|
|
||||||
|
const account = await client.getAccount(unused.address);
|
||||||
|
assert(account);
|
||||||
|
expect(account).toEqual({
|
||||||
|
address: unused.address,
|
||||||
|
pubkey: null,
|
||||||
|
accountNumber: unused.accountNumber,
|
||||||
|
sequence: unused.sequence,
|
||||||
|
});
|
||||||
|
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for account with pubkey and non-zero sequence", async () => {
|
||||||
|
pendingWithoutSimapp();
|
||||||
|
const client = await StargateClient.connect(simapp.tendermintUrl);
|
||||||
|
|
||||||
|
const account = await client.getAccount(validator.address);
|
||||||
|
assert(account);
|
||||||
|
expect(account).toEqual({
|
||||||
|
address: validator.address,
|
||||||
|
pubkey: validator.pubkey,
|
||||||
|
accountNumber: validator.accountNumber,
|
||||||
|
sequence: validator.sequence,
|
||||||
|
});
|
||||||
|
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns null for non-existent address", async () => {
|
||||||
|
pendingWithoutSimapp();
|
||||||
|
const client = await StargateClient.connect(simapp.tendermintUrl);
|
||||||
|
|
||||||
|
const account = await client.getAccount(nonExistentAddress);
|
||||||
|
expect(account).toBeNull();
|
||||||
|
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("getSequence", () => {
|
describe("getSequence", () => {
|
||||||
it("works for unused account", async () => {
|
it("works for unused account", async () => {
|
||||||
pendingWithoutSimapp();
|
pendingWithoutSimapp();
|
||||||
const client = await StargateClient.connect(simapp.tendermintUrl);
|
const client = await StargateClient.connect(simapp.tendermintUrl);
|
||||||
|
|
||||||
const { accountNumber, sequence } = await client.getSequence(unused.address);
|
const account = await client.getSequence(unused.address);
|
||||||
expect(accountNumber).toEqual(unused.accountNumber);
|
assert(account);
|
||||||
expect(sequence).toEqual(unused.sequence);
|
expect(account).toEqual({
|
||||||
|
accountNumber: unused.accountNumber,
|
||||||
|
sequence: unused.sequence,
|
||||||
|
});
|
||||||
|
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns null for non-existent address", async () => {
|
||||||
|
pendingWithoutSimapp();
|
||||||
|
const client = await StargateClient.connect(simapp.tendermintUrl);
|
||||||
|
|
||||||
|
const account = await client.getSequence(nonExistentAddress);
|
||||||
|
expect(account).toBeNull();
|
||||||
|
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { Bech32, toAscii, toHex } from "@cosmjs/encoding";
|
import { Bech32, toAscii, toHex } from "@cosmjs/encoding";
|
||||||
import { Coin } from "@cosmjs/launchpad";
|
import { Coin, decodeAminoPubkey, PubKey } from "@cosmjs/launchpad";
|
||||||
import { Uint64 } from "@cosmjs/math";
|
import { Uint64 } from "@cosmjs/math";
|
||||||
import { decodeAny } from "@cosmjs/proto-signing";
|
import { decodeAny } from "@cosmjs/proto-signing";
|
||||||
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
||||||
@ -9,7 +9,15 @@ import Long from "long";
|
|||||||
|
|
||||||
import { cosmos } from "./generated/codecimpl";
|
import { cosmos } from "./generated/codecimpl";
|
||||||
|
|
||||||
export interface GetSequenceResult {
|
export interface Account {
|
||||||
|
/** Bech32 account address */
|
||||||
|
readonly address: string;
|
||||||
|
readonly pubkey: PubKey | null;
|
||||||
|
readonly accountNumber: number;
|
||||||
|
readonly sequence: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SequenceResponse {
|
||||||
readonly accountNumber: number;
|
readonly accountNumber: number;
|
||||||
readonly sequence: number;
|
readonly sequence: number;
|
||||||
}
|
}
|
||||||
@ -18,6 +26,18 @@ function uint64FromProto(input: number | Long): Uint64 {
|
|||||||
return Uint64.fromString(input.toString());
|
return Uint64.fromString(input.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decodeBaseAccount(data: Uint8Array, prefix: string): Account {
|
||||||
|
const { address, pubKey, accountNumber, sequence } = cosmos.auth.BaseAccount.decode(data);
|
||||||
|
// Pubkey is still Amino-encoded in BaseAccount (https://github.com/cosmos/cosmos-sdk/issues/6886)
|
||||||
|
const pubkey = pubKey.length ? decodeAminoPubkey(pubKey) : null;
|
||||||
|
return {
|
||||||
|
address: Bech32.encode(prefix, address),
|
||||||
|
pubkey: pubkey,
|
||||||
|
accountNumber: uint64FromProto(accountNumber).toNumber(),
|
||||||
|
sequence: uint64FromProto(sequence).toNumber(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function coinFromProto(input: cosmos.ICoin): Coin {
|
function coinFromProto(input: cosmos.ICoin): Coin {
|
||||||
assertDefined(input.amount);
|
assertDefined(input.amount);
|
||||||
assertDefined(input.denom);
|
assertDefined(input.denom);
|
||||||
@ -41,23 +61,33 @@ export class StargateClient {
|
|||||||
this.tmClient = tmClient;
|
this.tmClient = tmClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSequence(address: string): Promise<GetSequenceResult> {
|
public async getAccount(searchAddress: string): Promise<Account | null> {
|
||||||
const binAddress = Bech32.decode(address).data;
|
const { prefix, data: binAddress } = Bech32.decode(searchAddress);
|
||||||
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L29-L32
|
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L29-L32
|
||||||
const accountKey = Uint8Array.from([0x01, ...binAddress]);
|
const accountKey = Uint8Array.from([0x01, ...binAddress]);
|
||||||
const responseData = await this.queryVerified("acc", accountKey);
|
const responseData = await this.queryVerified("acc", accountKey);
|
||||||
|
|
||||||
|
if (responseData.length === 0) return null;
|
||||||
|
|
||||||
const { typeUrl, value } = decodeAny(responseData);
|
const { typeUrl, value } = decodeAny(responseData);
|
||||||
switch (typeUrl) {
|
switch (typeUrl) {
|
||||||
case "/cosmos.auth.BaseAccount": {
|
case "/cosmos.auth.BaseAccount": {
|
||||||
const { accountNumber, sequence } = cosmos.auth.BaseAccount.decode(value);
|
return decodeBaseAccount(value, prefix);
|
||||||
return {
|
|
||||||
accountNumber: uint64FromProto(accountNumber).toNumber(),
|
|
||||||
sequence: uint64FromProto(sequence).toNumber(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported type: ${typeUrl}`);
|
throw new Error(`Unsupported type: '${typeUrl}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSequence(address: string): Promise<SequenceResponse | null> {
|
||||||
|
const account = await this.getAccount(address);
|
||||||
|
if (account) {
|
||||||
|
return {
|
||||||
|
accountNumber: account.accountNumber,
|
||||||
|
sequence: account.sequence,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,4 +24,16 @@ export const unused = {
|
|||||||
balanceFee: "1000000000", // 1000 COSM
|
balanceFee: "1000000000", // 1000 COSM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const validator = {
|
||||||
|
/** From first gentx's auth_info.signer_infos in scripts/simapp/template/.simapp/config/genesis.json */
|
||||||
|
pubkey: {
|
||||||
|
type: "tendermint/PubKeySecp256k1",
|
||||||
|
value: "AnFadRAdh6Fl7robHe8jywDMKSWQQjB7SlpoqGsX9Ghw",
|
||||||
|
},
|
||||||
|
/** delegator_address from /cosmos.staking.MsgCreateValidator in scripts/simapp/template/.simapp/config/genesis.json */
|
||||||
|
address: "cosmos12gm9sa666hywxu9nzzmp7hyl7a55hvg769w2kz",
|
||||||
|
accountNumber: 0,
|
||||||
|
sequence: 1,
|
||||||
|
};
|
||||||
|
|
||||||
export const nonExistentAddress = "cosmos1p79apjaufyphcmsn4g07cynqf0wyjuezqu84hd";
|
export const nonExistentAddress = "cosmos1p79apjaufyphcmsn4g07cynqf0wyjuezqu84hd";
|
||||||
|
14
packages/stargate/types/stargateclient.d.ts
vendored
14
packages/stargate/types/stargateclient.d.ts
vendored
@ -1,5 +1,12 @@
|
|||||||
import { Coin } from "@cosmjs/launchpad";
|
import { Coin, PubKey } from "@cosmjs/launchpad";
|
||||||
export interface GetSequenceResult {
|
export interface Account {
|
||||||
|
/** Bech32 account address */
|
||||||
|
readonly address: string;
|
||||||
|
readonly pubkey: PubKey | null;
|
||||||
|
readonly accountNumber: number;
|
||||||
|
readonly sequence: number;
|
||||||
|
}
|
||||||
|
export interface SequenceResponse {
|
||||||
readonly accountNumber: number;
|
readonly accountNumber: number;
|
||||||
readonly sequence: number;
|
readonly sequence: number;
|
||||||
}
|
}
|
||||||
@ -7,7 +14,8 @@ export declare class StargateClient {
|
|||||||
private readonly tmClient;
|
private readonly tmClient;
|
||||||
static connect(endpoint: string): Promise<StargateClient>;
|
static connect(endpoint: string): Promise<StargateClient>;
|
||||||
private constructor();
|
private constructor();
|
||||||
getSequence(address: string): Promise<GetSequenceResult>;
|
getAccount(searchAddress: string): Promise<Account | null>;
|
||||||
|
getSequence(address: string): Promise<SequenceResponse | null>;
|
||||||
getBalance(address: string, searchDenom: string): Promise<Coin | null>;
|
getBalance(address: string, searchDenom: string): Promise<Coin | null>;
|
||||||
/**
|
/**
|
||||||
* Queries all balances for all denoms that belong to this address.
|
* Queries all balances for all denoms that belong to this address.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user