diff --git a/packages/cli/examples/get_akash_vesting_account.ts b/packages/cli/examples/get_akash_vesting_account.ts new file mode 100644 index 00000000..cac9bdf3 --- /dev/null +++ b/packages/cli/examples/get_akash_vesting_account.ts @@ -0,0 +1,9 @@ +import { QueryClient, setupAuthExtension } from "@cosmjs/stargate"; +import { Any } from "@cosmjs/stargate/build/codec/google/protobuf/any"; +import { Tendermint34Client } from "@cosmjs/tendermint-rpc"; + +// https://github.com/ovrclk/net/blob/24ddbb427b0c15/mainnet/rpc-nodes.txt +const tmClient = await Tendermint34Client.connect("http://rpc.akash.forbole.com:80"); +const client = QueryClient.withExtensions(tmClient, setupAuthExtension); +const account = await client.auth.unverified.account("akash1qy0vur3fl2ucztpzcrfea7mc8jwz8xjmvq7qvy"); +console.log(Any.toJSON(account)) diff --git a/packages/stargate/src/accounts.spec.ts b/packages/stargate/src/accounts.spec.ts new file mode 100644 index 00000000..bd93e062 --- /dev/null +++ b/packages/stargate/src/accounts.spec.ts @@ -0,0 +1,27 @@ +import { accountFromAny } from "./accounts"; +import { Any } from "./codec/google/protobuf/any"; + +describe("accounts", () => { + describe("accountFromAny", () => { + it("works for PeriodicVestingAccount", () => { + // Arbitrary entry from https://raw.githubusercontent.com/ovrclk/net/24ddbb427/mainnet/genesis.json + // queried from chain via `packages/cli/examples/get_vesting_account.ts`. + const any = Any.fromJSON({ + typeUrl: "/cosmos.vesting.v1beta1.PeriodicVestingAccount", + value: + "CsMBCnoKLGFrYXNoMXF5MHZ1cjNmbDJ1Y3p0cHpjcmZlYTdtYzhqd3o4eGptdnE3cXZ5EkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/XsdhwSIKU73TltD9STcaS07FNw0szR4a+oDLr6vikaGDggGxIUCgR1YWt0EgwxNjY2NjY2NzAwMDAaEwoEdWFrdBILMzcxOTAzMzAwMDAiFAoEdWFrdBIMMTY2NjY2NjcwMDAwKOC9wZkGEODvt/sFGhoIgOeEDxITCgR1YWt0Egs4MzMzMzMzNTAwMBoaCIC/ugcSEwoEdWFrdBILNDE2NjY2Njc1MDAaGgiAqMoHEhMKBHVha3QSCzQxNjY2NjY3NTAw", + }); + + const account = accountFromAny(any); + expect(account).toEqual({ + address: "akash1qy0vur3fl2ucztpzcrfea7mc8jwz8xjmvq7qvy", + pubkey: { + type: "tendermint/PubKeySecp256k1", + value: "A/XsdhwSIKU73TltD9STcaS07FNw0szR4a+oDLr6vika", + }, + accountNumber: 56, + sequence: 27, + }); + }); + }); +}); diff --git a/packages/stargate/src/accounts.ts b/packages/stargate/src/accounts.ts new file mode 100644 index 00000000..e243c7a4 --- /dev/null +++ b/packages/stargate/src/accounts.ts @@ -0,0 +1,85 @@ +import { PubKey } from "@cosmjs/launchpad"; +import { Uint64 } from "@cosmjs/math"; +import { decodePubkey } from "@cosmjs/proto-signing"; +import { assert } from "@cosmjs/utils"; +import Long from "long"; + +import { BaseAccount, ModuleAccount } from "./codec/cosmos/auth/v1beta1/auth"; +import { + BaseVestingAccount, + ContinuousVestingAccount, + DelayedVestingAccount, + PeriodicVestingAccount, +} from "./codec/cosmos/vesting/v1beta1/vesting"; +import { Any } from "./codec/google/protobuf/any"; + +export interface Account { + /** Bech32 account address */ + readonly address: string; + readonly pubkey: PubKey | null; + readonly accountNumber: number; + readonly sequence: number; +} + +function uint64FromProto(input: number | Long): Uint64 { + return Uint64.fromString(input.toString()); +} + +function accountFromBaseAccount(input: BaseAccount): Account { + const { address, pubKey, accountNumber, sequence } = input; + const pubkey = decodePubkey(pubKey); + return { + address: address, + pubkey: pubkey, + accountNumber: uint64FromProto(accountNumber).toNumber(), + sequence: uint64FromProto(sequence).toNumber(), + }; +} + +/** + * Takes an `Any` encoded account from the chain and extracts some common + * `Account` information from it. This is supposed to support the most relevant + * common Cosmos SDK account types. If you need support for exotix account types, + * you'll need to write your own account decoder. + */ +export function accountFromAny(input: Any): Account { + const { typeUrl, value } = input; + + switch (typeUrl) { + // auth + + case "/cosmos.auth.v1beta1.BaseAccount": + return accountFromBaseAccount(BaseAccount.decode(value)); + case "/cosmos.auth.v1beta1.ModuleAccount": { + const baseAccount = ModuleAccount.decode(value).baseAccount; + assert(baseAccount); + return accountFromBaseAccount(baseAccount); + } + + // vesting + + case "/cosmos.vesting.v1beta1.BaseVestingAccount": { + const baseAccount = BaseVestingAccount.decode(value)?.baseAccount; + assert(baseAccount); + return accountFromBaseAccount(baseAccount); + } + case "/cosmos.vesting.v1beta1.ContinuousVestingAccount": { + const baseAccount = ContinuousVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; + assert(baseAccount); + return accountFromBaseAccount(baseAccount); + } + case "/cosmos.vesting.v1beta1.DelayedVestingAccount": { + const baseAccount = DelayedVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; + assert(baseAccount); + return accountFromBaseAccount(baseAccount); + } + case "/cosmos.vesting.v1beta1.PeriodicVestingAccount": { + const baseAccount = PeriodicVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; + assert(baseAccount); + return accountFromBaseAccount(baseAccount); + } + + default: + throw new Error(`Unsupported type: '${typeUrl}'`); + } +} diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index 6fa057dd..718109f5 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -1,3 +1,4 @@ +export { Account, accountFromAny } from "./accounts"; export { AminoConverter, AminoTypes } from "./aminotypes"; export { parseRawLog } from "./logs"; export { @@ -17,8 +18,6 @@ export { StakingExtension, } from "./queries"; export { - Account, - accountFromAny, assertIsBroadcastTxSuccess, BroadcastTxFailure, BroadcastTxResponse, diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index 99d86263..be1426d6 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -5,30 +5,20 @@ import { isSearchByHeightQuery, isSearchBySentFromOrToQuery, isSearchByTagsQuery, - PubKey, SearchTxFilter, SearchTxQuery, } from "@cosmjs/launchpad"; -import { Uint53, Uint64 } from "@cosmjs/math"; -import { decodePubkey } from "@cosmjs/proto-signing"; +import { Uint53 } from "@cosmjs/math"; import { broadcastTxCommitSuccess, Tendermint34Client, toRfc3339WithNanoseconds, } from "@cosmjs/tendermint-rpc"; -import { assert, assertDefinedAndNotNull } from "@cosmjs/utils"; -import Long from "long"; +import { assertDefinedAndNotNull } from "@cosmjs/utils"; -import { BaseAccount, ModuleAccount } from "./codec/cosmos/auth/v1beta1/auth"; +import { Account, accountFromAny } from "./accounts"; import { MsgData, TxMsgData } from "./codec/cosmos/base/abci/v1beta1/abci"; import { Coin } from "./codec/cosmos/base/v1beta1/coin"; -import { - BaseVestingAccount, - ContinuousVestingAccount, - DelayedVestingAccount, - PeriodicVestingAccount, -} from "./codec/cosmos/vesting/v1beta1/vesting"; -import { Any } from "./codec/google/protobuf/any"; import { AuthExtension, BankExtension, QueryClient, setupAuthExtension, setupBankExtension } from "./queries"; /** A transaction that is indexed as part of the transaction history */ @@ -42,14 +32,6 @@ export interface IndexedTx { readonly tx: Uint8Array; } -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 sequence: number; @@ -93,70 +75,6 @@ export function assertIsBroadcastTxSuccess( } } -function uint64FromProto(input: number | Long | null | undefined): Uint64 { - if (!input) return Uint64.fromNumber(0); - return Uint64.fromString(input.toString()); -} - -function accountFromBaseAccount(input: BaseAccount): Account { - const { address, pubKey, accountNumber, sequence } = input; - const pubkey = decodePubkey(pubKey); - return { - address: address, - pubkey: pubkey, - accountNumber: uint64FromProto(accountNumber).toNumber(), - sequence: uint64FromProto(sequence).toNumber(), - }; -} - -/** - * Takes an `Any` encoded account from the chain and extracts some common - * `Account` information from it. This is supposed to support the most relevant - * common Cosmos SDK account types. If you need support for exotix account types, - * you'll need to write your own account decoder. - */ -export function accountFromAny(input: Any): Account { - const { typeUrl, value } = input; - - switch (typeUrl) { - // auth - - case "/cosmos.auth.v1beta1.BaseAccount": - return accountFromBaseAccount(BaseAccount.decode(value)); - case "/cosmos.auth.v1beta1.ModuleAccount": { - const baseAccount = ModuleAccount.decode(value).baseAccount; - assert(baseAccount); - return accountFromBaseAccount(baseAccount); - } - - // vesting - - case "/cosmos.vesting.v1beta1.BaseVestingAccount": { - const baseAccount = BaseVestingAccount.decode(value)?.baseAccount; - assert(baseAccount); - return accountFromBaseAccount(baseAccount); - } - case "/cosmos.vesting.v1beta1.ContinuousVestingAccount": { - const baseAccount = ContinuousVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; - assert(baseAccount); - return accountFromBaseAccount(baseAccount); - } - case "/cosmos.vesting.v1beta1.DelayedVestingAccount": { - const baseAccount = DelayedVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; - assert(baseAccount); - return accountFromBaseAccount(baseAccount); - } - case "/cosmos.vesting.v1beta1.PeriodicVestingAccount": { - const baseAccount = PeriodicVestingAccount.decode(value)?.baseVestingAccount?.baseAccount; - assert(baseAccount); - return accountFromBaseAccount(baseAccount); - } - - default: - throw new Error(`Unsupported type: '${typeUrl}'`); - } -} - export function coinFromProto(input: Coin): Coin { assertDefinedAndNotNull(input.amount); assertDefinedAndNotNull(input.denom);