diff --git a/packages/proto-signing/src/accounts.ts b/packages/proto-signing/src/accounts.ts
new file mode 100644
index 00000000..2e359a94
--- /dev/null
+++ b/packages/proto-signing/src/accounts.ts
@@ -0,0 +1,20 @@
+/* eslint-disable @typescript-eslint/naming-convention */
+import { Message } from "protobufjs";
+
+import { cosmosField, cosmosMessage } from "./decorator";
+import { defaultRegistry } from "./msgs";
+
+@cosmosMessage(defaultRegistry, "/cosmos.auth.BaseAccount")
+export class BaseAccount extends Message {
+ @cosmosField.bytes(1)
+ public readonly address?: Uint8Array;
+
+ @cosmosField.bytes(2)
+ public readonly pub_key?: Uint8Array;
+
+ @cosmosField.uint64(3)
+ public readonly account_number?: Long | number;
+
+ @cosmosField.uint64(4)
+ public readonly sequence?: Long | number;
+}
diff --git a/packages/proto-signing/src/index.ts b/packages/proto-signing/src/index.ts
index 73ae35c4..c279effd 100644
--- a/packages/proto-signing/src/index.ts
+++ b/packages/proto-signing/src/index.ts
@@ -1 +1,2 @@
+export { BaseAccount } from "./accounts";
export { decodeAny } from "./any";
diff --git a/packages/proto-signing/types/accounts.d.ts b/packages/proto-signing/types/accounts.d.ts
new file mode 100644
index 00000000..2c888633
--- /dev/null
+++ b/packages/proto-signing/types/accounts.d.ts
@@ -0,0 +1,8 @@
+///
+import { Message } from "protobufjs";
+export declare class BaseAccount extends Message {
+ readonly address?: Uint8Array;
+ readonly pub_key?: Uint8Array;
+ readonly account_number?: Long | number;
+ readonly sequence?: Long | number;
+}
diff --git a/packages/proto-signing/types/index.d.ts b/packages/proto-signing/types/index.d.ts
index 73ae35c4..c279effd 100644
--- a/packages/proto-signing/types/index.d.ts
+++ b/packages/proto-signing/types/index.d.ts
@@ -1 +1,2 @@
+export { BaseAccount } from "./accounts";
export { decodeAny } from "./any";
diff --git a/packages/stargate/package.json b/packages/stargate/package.json
index a26e5fe4..d9393348 100644
--- a/packages/stargate/package.json
+++ b/packages/stargate/package.json
@@ -38,7 +38,9 @@
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
},
"dependencies": {
+ "@cosmjs/encoding": "^0.22.0",
"@cosmjs/proto-signing": "^0.22.0",
- "@cosmjs/tendermint-rpc": "^0.22.0"
+ "@cosmjs/tendermint-rpc": "^0.22.0",
+ "@cosmjs/utils": "^0.22.0"
}
}
diff --git a/packages/stargate/src/stargateclient.spec.ts b/packages/stargate/src/stargateclient.spec.ts
index da09f08a..6956aa71 100644
--- a/packages/stargate/src/stargateclient.spec.ts
+++ b/packages/stargate/src/stargateclient.spec.ts
@@ -1,5 +1,5 @@
import { StargateClient } from "./stargateclient";
-import { pendingWithoutSimapp, simapp } from "./testutils.spec";
+import { pendingWithoutSimapp, simapp, unused } from "./testutils.spec";
describe("StargateClient", () => {
describe("connect", () => {
@@ -10,4 +10,17 @@ describe("StargateClient", () => {
client.disconnect();
});
});
+
+ describe("getSequence", () => {
+ it("works for unused account", async () => {
+ pendingWithoutSimapp();
+ const client = await StargateClient.connect(simapp.tendermintUrl);
+
+ const { accountNumber, sequence } = await client.getSequence(unused.address);
+ expect(accountNumber).toEqual(unused.accountNumber);
+ expect(sequence).toEqual(unused.sequence);
+
+ client.disconnect();
+ });
+ });
});
diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts
index 40ea0342..3affe0fc 100644
--- a/packages/stargate/src/stargateclient.ts
+++ b/packages/stargate/src/stargateclient.ts
@@ -1,4 +1,13 @@
+/* eslint-disable @typescript-eslint/naming-convention */
+import { Bech32 } from "@cosmjs/encoding";
+import { BaseAccount, decodeAny } from "@cosmjs/proto-signing";
import { Client as TendermintClient } from "@cosmjs/tendermint-rpc";
+import { assert } from "@cosmjs/utils";
+
+export interface GetSequenceResult {
+ readonly accountNumber: number;
+ readonly sequence: number;
+}
export class StargateClient {
private readonly tmClient: TendermintClient;
@@ -12,6 +21,38 @@ export class StargateClient {
this.tmClient = tmClient;
}
+ public async getSequence(address: string): Promise {
+ const binAddress = Bech32.decode(address).data;
+
+ // https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L29-L32
+ const accountKey = Uint8Array.from([0x01, ...binAddress]);
+
+ const response = await this.tmClient.abciQuery({
+ // we need the StoreKey for the module, not the module name
+ // https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L12
+ path: "/store/acc/key",
+ data: accountKey,
+ prove: false,
+ });
+
+ const { typeUrl, value } = decodeAny(response.value);
+
+ switch (typeUrl) {
+ case "/cosmos.auth.BaseAccount": {
+ const { account_number, sequence } = BaseAccount.decode(value);
+ assert(account_number !== undefined);
+ assert(sequence !== undefined);
+ return {
+ accountNumber: typeof account_number === "number" ? account_number : account_number.toNumber(),
+ sequence: typeof sequence === "number" ? sequence : sequence.toNumber(),
+ };
+ }
+
+ default:
+ throw new Error(`Unsupported type: ${typeUrl}`);
+ }
+ }
+
public disconnect(): void {
this.tmClient.disconnect();
}
diff --git a/packages/stargate/src/testutils.spec.ts b/packages/stargate/src/testutils.spec.ts
index b02e5526..cfe1a60e 100644
--- a/packages/stargate/src/testutils.spec.ts
+++ b/packages/stargate/src/testutils.spec.ts
@@ -8,3 +8,14 @@ export const simapp = {
tendermintUrl: "localhost:26657",
chainId: "simd-testing",
};
+
+/** Unused account */
+export const unused = {
+ pubkey: {
+ type: "tendermint/PubKeySecp256k1",
+ value: "ArkCaFUJ/IH+vKBmNRCdUVl3mCAhbopk9jjW4Ko4OfRQ",
+ },
+ address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
+ accountNumber: 16,
+ sequence: 0,
+};
diff --git a/packages/stargate/types/stargateclient.d.ts b/packages/stargate/types/stargateclient.d.ts
index f65d2e29..7b5269d6 100644
--- a/packages/stargate/types/stargateclient.d.ts
+++ b/packages/stargate/types/stargateclient.d.ts
@@ -1,6 +1,11 @@
+export interface GetSequenceResult {
+ readonly accountNumber: number;
+ readonly sequence: number;
+}
export declare class StargateClient {
private readonly tmClient;
static connect(endpoint: string): Promise;
private constructor();
+ getSequence(address: string): Promise;
disconnect(): void;
}