diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index aa408871..183d086a 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -2,6 +2,7 @@ import { Sha256 } from "@cosmjs/crypto"; import { Bech32, fromAscii, fromBase64, fromHex, toAscii, toBase64, toHex } from "@cosmjs/encoding"; import { + AuthModule, Coin, coin, coins, @@ -10,6 +11,7 @@ import { Pen, PostTxsResponse, Secp256k1Pen, + setupAuthModule, StdFee, } from "@cosmjs/sdk38"; import { assert } from "@cosmjs/utils"; @@ -37,10 +39,10 @@ import { } from "../testutils.spec"; import { setupWasmModule, WasmModule } from "./wasm"; -type WasmClient = LcdClient & WasmModule; +type WasmClient = LcdClient & AuthModule & WasmModule; function makeWasmClient(apiUrl: string): WasmClient { - return LcdClient.withModules({ apiUrl }, setupWasmModule); + return LcdClient.withModules({ apiUrl }, setupAuthModule, setupWasmModule); } async function uploadContract( diff --git a/packages/sdk38/src/cosmosclient.ts b/packages/sdk38/src/cosmosclient.ts index 5ab8b2b2..bcdfdc63 100644 --- a/packages/sdk38/src/cosmosclient.ts +++ b/packages/sdk38/src/cosmosclient.ts @@ -3,7 +3,7 @@ import { fromBase64, fromHex, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { Coin } from "./coins"; -import { BroadcastMode, LcdClient } from "./lcdapi"; +import { AuthModule, BroadcastMode, LcdClient, setupAuthModule } from "./lcdapi"; import { Log, parseLogs } from "./logs"; import { decodeBech32Pubkey } from "./pubkey"; import { CosmosSdkTx, PubKey, StdTx } from "./types"; @@ -130,11 +130,11 @@ export interface Block { /** Use for testing only */ export interface PrivateCosmWasmClient { - readonly lcdClient: LcdClient; + readonly lcdClient: LcdClient & AuthModule; } export class CosmosClient { - protected readonly lcdClient: LcdClient; + protected readonly lcdClient: LcdClient & AuthModule; /** Any address the chain considers valid (valid bech32 with proper prefix) */ protected anyValidAddress: string | undefined; @@ -150,7 +150,7 @@ export class CosmosClient { * @param broadcastMode Defines at which point of the transaction processing the postTx method (i.e. transaction broadcasting) returns */ public constructor(apiUrl: string, broadcastMode = BroadcastMode.Block) { - this.lcdClient = new LcdClient(apiUrl, broadcastMode); + this.lcdClient = LcdClient.withModules({ apiUrl: apiUrl, broadcastMode: broadcastMode }, setupAuthModule); } public async getChainId(): Promise { diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index d55d2149..55d6360d 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -22,6 +22,7 @@ export { export { makeSignBytes } from "./encoding"; export { AuthAccountsResponse, + AuthModule, BlockResponse, BroadcastMode, EncodeTxResponse, @@ -32,6 +33,9 @@ export { normalizeLcdApiArray, PostTxsResponse, SearchTxsResponse, + setupAuthModule, + setupSupplyModule, + SupplyModule, TxsResponse, } from "./lcdapi"; export { RestClient } from "./restclient"; diff --git a/packages/sdk38/src/lcdapi/auth.spec.ts b/packages/sdk38/src/lcdapi/auth.spec.ts new file mode 100644 index 00000000..2aabe9c1 --- /dev/null +++ b/packages/sdk38/src/lcdapi/auth.spec.ts @@ -0,0 +1,68 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import { encodeBech32Pubkey } from "../pubkey"; +import { + faucet, + makeRandomAddress, + nonNegativeIntegerMatcher, + pendingWithoutWasmd, + unused, + wasmd, +} from "../testutils.spec"; +import { AuthModule, setupAuthModule } from "./auth"; +import { LcdClient } from "./lcdclient"; + +function makeAuthClient(apiUrl: string): LcdClient & AuthModule { + return LcdClient.withModules({ apiUrl }, setupAuthModule); +} + +describe("auth", () => { + it("works for unused account without pubkey", async () => { + pendingWithoutWasmd(); + const client = makeAuthClient(wasmd.endpoint); + const { height, result } = await client.authAccounts(unused.address); + expect(height).toMatch(nonNegativeIntegerMatcher); + expect(result).toEqual({ + type: "cosmos-sdk/Account", + value: { + address: unused.address, + public_key: "", // not known to the chain + coins: [ + { + amount: "1000000000", + denom: "ucosm", + }, + { + amount: "1000000000", + denom: "ustake", + }, + ], + account_number: unused.accountNumber, + sequence: 0, + }, + }); + }); + + // This fails in the first test run if you forget to run `./scripts/wasmd/init.sh` + it("has correct pubkey for faucet", async () => { + pendingWithoutWasmd(); + const client = makeAuthClient(wasmd.endpoint); + const { result } = await client.authAccounts(faucet.address); + expect(result.value).toEqual( + jasmine.objectContaining({ + public_key: encodeBech32Pubkey(faucet.pubkey, "cosmospub"), + }), + ); + }); + + // This property is used by CosmWasmClient.getAccount + it("returns empty address for non-existent account", async () => { + pendingWithoutWasmd(); + const client = makeAuthClient(wasmd.endpoint); + const nonExistentAccount = makeRandomAddress(); + const { result } = await client.authAccounts(nonExistentAccount); + expect(result).toEqual({ + type: "cosmos-sdk/Account", + value: jasmine.objectContaining({ address: "" }), + }); + }); +}); diff --git a/packages/sdk38/src/lcdapi/auth.ts b/packages/sdk38/src/lcdapi/auth.ts new file mode 100644 index 00000000..497f834f --- /dev/null +++ b/packages/sdk38/src/lcdapi/auth.ts @@ -0,0 +1,37 @@ +import { Coin } from "../coins"; +import { LcdClient, LcdModule } from "./lcdclient"; + +export interface CosmosSdkAccount { + /** Bech32 account address */ + readonly address: string; + readonly coins: readonly Coin[]; + /** Bech32 encoded pubkey */ + readonly public_key: string; + readonly account_number: number; + readonly sequence: number; +} + +export interface AuthAccountsResponse { + readonly height: string; + readonly result: { + readonly type: "cosmos-sdk/Account"; + readonly value: CosmosSdkAccount; + }; +} + +export interface AuthModule extends LcdModule { + readonly authAccounts: (address: string) => Promise; +} + +export function setupAuthModule(base: LcdClient): AuthModule { + return { + authAccounts: async (address: string) => { + const path = `/auth/accounts/${address}`; + const responseData = await base.get(path); + if (responseData.result.type !== "cosmos-sdk/Account") { + throw new Error("Unexpected response data format"); + } + return responseData as AuthAccountsResponse; + }, + }; +} diff --git a/packages/sdk38/src/lcdapi/base.ts b/packages/sdk38/src/lcdapi/base.ts index bcf457cf..45f46e0f 100644 --- a/packages/sdk38/src/lcdapi/base.ts +++ b/packages/sdk38/src/lcdapi/base.ts @@ -1,4 +1,3 @@ -import { Coin } from "../coins"; import { CosmosSdkTx } from "../types"; /** @@ -100,24 +99,6 @@ export interface BlockResponse { readonly block: Block; } -export interface CosmosSdkAccount { - /** Bech32 account address */ - readonly address: string; - readonly coins: readonly Coin[]; - /** Bech32 encoded pubkey */ - readonly public_key: string; - readonly account_number: number; - readonly sequence: number; -} - -export interface AuthAccountsResponse { - readonly height: string; - readonly result: { - readonly type: "cosmos-sdk/Account"; - readonly value: CosmosSdkAccount; - }; -} - export interface TxsResponse { readonly height: string; readonly txhash: string; diff --git a/packages/sdk38/src/lcdapi/index.ts b/packages/sdk38/src/lcdapi/index.ts index 2dfbd914..19876b9d 100644 --- a/packages/sdk38/src/lcdapi/index.ts +++ b/packages/sdk38/src/lcdapi/index.ts @@ -2,14 +2,14 @@ // Standard modules (see tracking issue https://github.com/CosmWasm/cosmjs/issues/276) // -export { SupplyModule, TotalSupplyAllReponse, TotalSupplyReponse } from "./supply"; +export { AuthModule, AuthAccountsResponse, setupAuthModule } from "./auth"; +export { setupSupplyModule, SupplyModule, TotalSupplyAllReponse, TotalSupplyReponse } from "./supply"; // // Base types // export { - AuthAccountsResponse, BlockResponse, BroadcastMode, EncodeTxResponse, diff --git a/packages/sdk38/src/lcdapi/lcdclient.spec.ts b/packages/sdk38/src/lcdapi/lcdclient.spec.ts index a8e0951d..7ec00c0c 100644 --- a/packages/sdk38/src/lcdapi/lcdclient.spec.ts +++ b/packages/sdk38/src/lcdapi/lcdclient.spec.ts @@ -21,6 +21,7 @@ import { wasmdEnabled, } from "../testutils.spec"; import { StdFee } from "../types"; +import { setupAuthModule } from "./auth"; import { TxsResponse } from "./base"; import { LcdApiArray, LcdClient, normalizeLcdApiArray } from "./lcdclient"; @@ -523,7 +524,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value; const signBytes = makeSignBytes([theMsg], fee, wasmd.chainId, memo, account_number, sequence); @@ -576,7 +577,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number: an1, sequence: sequence1 } = (await client.authAccounts(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.authAccounts(address2)).result.value; const { account_number: an3, sequence: sequence3 } = (await client.authAccounts(address3)).result.value; @@ -641,7 +642,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number, sequence } = (await client.authAccounts(address1)).result.value; const signBytes = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); @@ -701,7 +702,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number: an1, sequence: sequence1 } = (await client.authAccounts(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.authAccounts(address2)).result.value; @@ -769,7 +770,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number: an1, sequence: sequence1 } = (await client.authAccounts(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.authAccounts(address2)).result.value; @@ -832,7 +833,7 @@ describe("LcdClient", () => { gas: "890000", }; - const client = new LcdClient(wasmd.endpoint); + const client = LcdClient.withModules({ apiUrl: wasmd.endpoint }, setupAuthModule); const { account_number: an1, sequence: sequence1 } = (await client.authAccounts(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.authAccounts(address2)).result.value; diff --git a/packages/sdk38/src/lcdapi/lcdclient.ts b/packages/sdk38/src/lcdapi/lcdclient.ts index f0889396..cbe1e4ab 100644 --- a/packages/sdk38/src/lcdapi/lcdclient.ts +++ b/packages/sdk38/src/lcdapi/lcdclient.ts @@ -4,7 +4,6 @@ import axios, { AxiosError, AxiosInstance } from "axios"; import { CosmosSdkTx, StdTx } from "../types"; import { - AuthAccountsResponse, BlockResponse, BroadcastMode, EncodeTxResponse, @@ -263,17 +262,6 @@ export class LcdClient { return data; } - // The /auth endpoints - - public async authAccounts(address: string): Promise { - const path = `/auth/accounts/${address}`; - const responseData = await this.get(path); - if (responseData.result.type !== "cosmos-sdk/Account") { - throw new Error("Unexpected response data format"); - } - return responseData as AuthAccountsResponse; - } - // The /blocks endpoints public async blocksLatest(): Promise { diff --git a/packages/sdk38/types/cosmosclient.d.ts b/packages/sdk38/types/cosmosclient.d.ts index f5f31bc6..3232ba75 100644 --- a/packages/sdk38/types/cosmosclient.d.ts +++ b/packages/sdk38/types/cosmosclient.d.ts @@ -1,5 +1,5 @@ import { Coin } from "./coins"; -import { BroadcastMode, LcdClient } from "./lcdapi"; +import { AuthModule, BroadcastMode, LcdClient } from "./lcdapi"; import { Log } from "./logs"; import { CosmosSdkTx, PubKey, StdTx } from "./types"; export interface GetNonceResult { @@ -94,10 +94,10 @@ export interface Block { } /** Use for testing only */ export interface PrivateCosmWasmClient { - readonly lcdClient: LcdClient; + readonly lcdClient: LcdClient & AuthModule; } export declare class CosmosClient { - protected readonly lcdClient: LcdClient; + protected readonly lcdClient: LcdClient & AuthModule; /** Any address the chain considers valid (valid bech32 with proper prefix) */ protected anyValidAddress: string | undefined; private chainId; diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index b3fd530d..d94febb4 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -20,6 +20,7 @@ export { export { makeSignBytes } from "./encoding"; export { AuthAccountsResponse, + AuthModule, BlockResponse, BroadcastMode, EncodeTxResponse, @@ -30,6 +31,9 @@ export { normalizeLcdApiArray, PostTxsResponse, SearchTxsResponse, + setupAuthModule, + setupSupplyModule, + SupplyModule, TxsResponse, } from "./lcdapi"; export { RestClient } from "./restclient"; diff --git a/packages/sdk38/types/lcdapi/auth.d.ts b/packages/sdk38/types/lcdapi/auth.d.ts new file mode 100644 index 00000000..ecd2020b --- /dev/null +++ b/packages/sdk38/types/lcdapi/auth.d.ts @@ -0,0 +1,22 @@ +import { Coin } from "../coins"; +import { LcdClient, LcdModule } from "./lcdclient"; +export interface CosmosSdkAccount { + /** Bech32 account address */ + readonly address: string; + readonly coins: readonly Coin[]; + /** Bech32 encoded pubkey */ + readonly public_key: string; + readonly account_number: number; + readonly sequence: number; +} +export interface AuthAccountsResponse { + readonly height: string; + readonly result: { + readonly type: "cosmos-sdk/Account"; + readonly value: CosmosSdkAccount; + }; +} +export interface AuthModule extends LcdModule { + readonly authAccounts: (address: string) => Promise; +} +export declare function setupAuthModule(base: LcdClient): AuthModule; diff --git a/packages/sdk38/types/lcdapi/auth.spec.d.ts b/packages/sdk38/types/lcdapi/auth.spec.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/packages/sdk38/types/lcdapi/auth.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/sdk38/types/lcdapi/base.d.ts b/packages/sdk38/types/lcdapi/base.d.ts index 3f520738..d7927b0f 100644 --- a/packages/sdk38/types/lcdapi/base.d.ts +++ b/packages/sdk38/types/lcdapi/base.d.ts @@ -1,4 +1,3 @@ -import { Coin } from "../coins"; import { CosmosSdkTx } from "../types"; /** * The mode used to send transaction @@ -85,22 +84,6 @@ export interface BlockResponse { readonly block_id: BlockId; readonly block: Block; } -export interface CosmosSdkAccount { - /** Bech32 account address */ - readonly address: string; - readonly coins: readonly Coin[]; - /** Bech32 encoded pubkey */ - readonly public_key: string; - readonly account_number: number; - readonly sequence: number; -} -export interface AuthAccountsResponse { - readonly height: string; - readonly result: { - readonly type: "cosmos-sdk/Account"; - readonly value: CosmosSdkAccount; - }; -} export interface TxsResponse { readonly height: string; readonly txhash: string; diff --git a/packages/sdk38/types/lcdapi/index.d.ts b/packages/sdk38/types/lcdapi/index.d.ts index 5dd4140a..ab6fc2a3 100644 --- a/packages/sdk38/types/lcdapi/index.d.ts +++ b/packages/sdk38/types/lcdapi/index.d.ts @@ -1,6 +1,6 @@ -export { SupplyModule, TotalSupplyAllReponse, TotalSupplyReponse } from "./supply"; +export { AuthModule, AuthAccountsResponse, setupAuthModule } from "./auth"; +export { setupSupplyModule, SupplyModule, TotalSupplyAllReponse, TotalSupplyReponse } from "./supply"; export { - AuthAccountsResponse, BlockResponse, BroadcastMode, EncodeTxResponse, diff --git a/packages/sdk38/types/lcdapi/lcdclient.d.ts b/packages/sdk38/types/lcdapi/lcdclient.d.ts index 379051c7..924fc62a 100644 --- a/packages/sdk38/types/lcdapi/lcdclient.d.ts +++ b/packages/sdk38/types/lcdapi/lcdclient.d.ts @@ -1,6 +1,5 @@ import { CosmosSdkTx, StdTx } from "../types"; import { - AuthAccountsResponse, BlockResponse, BroadcastMode, EncodeTxResponse, @@ -147,7 +146,6 @@ export declare class LcdClient { constructor(apiUrl: string, broadcastMode?: BroadcastMode); get(path: string): Promise; post(path: string, params: any): Promise; - authAccounts(address: string): Promise; blocksLatest(): Promise; blocks(height: number): Promise; nodeInfo(): Promise;