React hook
This section explains how to integrate the Cosmostation Extension into a React application using the official hook-based package.
The React hook approach is recommended when:
- building a React / Next.js application
- managing wallet state declaratively
- supporting multiple wallet extensions through a unified interface
Wallet connection state, account data, and methods are all exposed via React hooks and context.
Installation
The Cosmostation wallet hook package lives in npm. To install the latest stable version, run the following command:
npm install @cosmostation/use-walletsOr if you're using yarn:
yarn add @cosmostation/use-walletsCosmosProvider
Components that rely on Cosmos wallet state must be wrapped
with CosmosProvider.
This provider:
- initializes wallet detection
- manages connection state
- exposes wallet context to child components
A good place to include it is your application root.
import { CosmosProvider } from '@cosmostation/use-wallets';
function App() {
return (
<CosmosProvider>
<MyApp />
</CosmosProvider>
);
}useCosmosWallets
useCosmosWallets is responsible for wallet-level state.
With this hook, you can:
- retrieve the list of detected wallets
- select which wallet to use
- access the currently selected wallet instance
The wallet list is automatically populated when browser extensions are detected.
If you would like to add a wallet, click here
selectWallet
Use this to prompt the user to select and connect a wallet.
import { useCosmosWallets } from '@cosmostation/use-wallets';
function Connect() {
const { cosmosWallets, selectWallet } = useCosmosWallets();
return (
<div>
{cosmosWallets.map((wallet) => (
<button
onClick={() => {
selectWallet(wallet.id);
}}
key={wallet.id}
>
<img src={wallet.logo} alt={wallet.name} width={40} height={40} /> {wallet.name}
</button>
))}
</div>
);
}getSupportedChainIds
Query the list of Cosmos chain IDs supported by the currently selected wallet.
This is useful for:
- validating whether a chain is available
- gating features by chain
- deciding whether to prompt
addChain
import { useCosmosWallets } from '@cosmostation/use-wallets';
function AddCustomChain() {
const { currentWallet } = useCosmosWallets();
return (
<div>
<button
onClick={() => {
try {
if (!currentWallet) {
throw new Error('No Selected Wallet');
}
const response = await currentWallet.methods.getSupportedChainIds();
} catch (e) {
console.log(e.message);
}
}}
>
Request Supported Chain Ids
</button>
</div>
);
}addChain
Add a custom chain or testnet to the selected wallet.
Use this when:
- integrating non-default Cosmos SDK chains
- supporting testnets or private networks
- onboarding newly launched chains
import { useCosmosWallets } from '@cosmostation/use-wallets';
function AddCustomChain() {
const { currentWallet } = useCosmosWallets();
return (
<div>
<button
onClick={() => {
try {
if (!currentWallet) {
throw new Error('No Selected Wallet');
}
await currentWallet.methods.addChain({
chain_id: 'custom-chain-1',
chain_name: 'custom-chain',
address_prefix: 'custom',
base_denom: 'ucustom',
display_denom: 'CUSTOM',
lcd_url: 'https://rpc.custom-chain.com',
decimals: 6, // optional
coin_type: "118'", // optional
});
} catch (e) {
console.log(e.message);
}
}}
>
Add Custom Chain
</button>
</div>
);
}useCosmosAccount
useCosmosAccount manages account-level state for a specific chain.
This hook:
- automatically requests account info when a wallet is selected
- keeps account data in sync with wallet state
- exposes chain-scoped signing methods
Account
Account information is fetched automatically.
If you need to re-fetch manually (for example, after a keystore change),
you can call mutate().
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function Account() {
const { data, error, mutate } = useCosmosAccount('cosmoshub-4');
useEffect(() => {
console.log('address', data?.account);
console.log('error', error);
}, [data, error]);
return <button onClick={() => mutate()}>Request Account</button>;
}Methods
The methods object exposes all wallet actions
available for the selected account and chain.
Typical examples include:
- signing transactions
- signing messages
- disconnecting the wallet
disconnect
Disconnect the current wallet session.
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function Account() {
const { data } = useCosmosAccount('cosmoshub-4');
return <button onClick={() => data?.method.disconnect()}>Disconnect</button>;
}signAmino
Sign transactions using Amino JSON.
Use this only when legacy compatibility is required.
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function SignAmino() {
const { data } = useCosmosAccount('cosmoshub-4');
const sendExampleDoc = {
// ...
};
return (
<button
onClick={async () => {
try {
if (!data) {
throw new Error('No data');
}
console.dir(await data?.methods.signAmino(sendExampleDoc), { depth: 100 });
} catch (e) {
console.log(e.message);
}
}}
>
Sign Amino
</button>
);
}signDirect
Sign protobuf-based transactions (SIGN_MODE_DIRECT).
This is the recommended signing method for modern Cosmos SDK chains.
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function SignDirect() {
const { data } = useCosmosAccount('cosmoshub-4');
const sendExampleDoc = {
// ...
};
return (
<button
onClick={async () => {
try {
if (!data) {
throw new Error('No data');
}
const result = await data.methods.signDirect(sendExampleDoc);
console.dir(result, { depth: 100 });
} catch (e) {
console.log(e.message);
}
}}
>
Sign Direct
</button>
);
}signMessage
Sign arbitrary bytes (off-chain message signing).
Common use cases:
- authentication challenges
- wallet ownership proofs
- off-chain authorization
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function SignAndSendTransaction() {
const { data } = useCosmosAccount('cosmoshub-4');
return (
<Button
onClick={async () => {
try {
if (!data) {
throw new Error('No data');
}
if (!data.methods.signMessage) {
throw new Error('No signMessage method');
}
const message = '(test) sign message';
console.dir(await data.methods.signMessage(message));
} catch (e) {
console.log(e.message);
}
}}
>
Sign Message
</Button>
);
}verifyMessage
Verify a signed message against the signer’s address.
import { useCosmosAccount } from '@cosmostation/use-wallets';
export default function SignAndSendTransaction() {
const { data } = useCosmosAccount('cosmoshub-4');
return (
<Button
onClick={async () => {
try {
if (!data) {
throw new Error('No data');
}
if (!data.methods.signMessage) {
throw new Error('No signMessage method');
}
if (!data.methods.verifyMessage) {
throw new Error('No verifyMessage method');
}
const message = '(test) sign message';
const response = await data.methods.signMessage(message);
const verify = await data.methods.verifyMessage(message, response.signature);
console.log(verify ? 'verified' : 'not verified');
} catch (e) {
console.log(e.message);
}
}}
>
Verify Message
</Button>
);
}Type
This section defines the TypeScript interfaces used by the React hook API.
These types describe:
- account shape
- public key formats
- available wallet methods
- signing document structures
They are useful for:
- advanced typing
- custom abstractions
- understanding SDK behavior
Account
interface Account {
data?: {
account: CosmosAccount;
methods: CosmosMethods;
};
error?: string;
mutate: () => void;
}CosmosAccount
interface CosmosAccount {
address: string;
public_key: {
type: CosmosPublicKeyType;
value: string;
};
name?: string;
is_ledger?: boolean;
}CosmosPublicKeyType
type CosmosPublicKeyType = 'secp256k1' | 'ethsecp256k1';CosmosMethods
interface CosmosMethods {
connect: (chainIds: string | string[]) => Promise<void>;
getAccount: (chainId: string) => Promise<CosmosRequestAccountResponse>;
getAccountsSettled: (chainIds: string[]) => Promise<CosmosRequestAccountsSettledResponse>;
signAmino: (
chain_id: string,
document: CosmosSignAminoDoc,
options?: CosmosSignOptions,
) => Promise<CosmosSignAminoResponse>;
signDirect: (
chain_id: string,
document: CosmosSignDirectDoc,
options?: CosmosSignOptions,
) => Promise<CosmosSignDirectResponse>;
sendTransaction: (
chain_id: string,
tx_bytes: Uint8Array | string,
mode?: number,
) => Promise<string>;
signMessage?: (
chainId: string,
message: string,
signer: string,
) => Promise<CosmosSignMessageResponse>;
verifyMessage?: (
chain_id: string,
message: string,
signer: string,
signature: string,
public_key: string,
) => Promise<boolean>;
disconnect?: () => Promise<void>;
addChain?: (chain: CosmosAddChain) => Promise<void>;
getSupportedChainIds: () => Promise<string[]>;
}CosmosSignAminoDoc
interface CosmosSignAminoDoc {
sequence: string;
account_number: string;
fee: {
amount?: {
denom: string;
amount: string;
}[];
gas: string;
};
memo: string;
msgs: {
type: string;
value: any;
}[];
}CosmosSignAminoResponse
interface CosmosSignAminoResponse {
signature: string;
signed_doc: any;
}CosmosSignDirectDoc
interface CosmosSignDirectDoc {
account_number: string;
body_bytes: string | Uint8Array;
auth_info_bytes: string | Uint8Array;
}CosmosSignDirectResponse
interface CosmosSignDirectResponse {
signature: string;
signed_doc: CosmosSignedDoc;
}SignAndSendTransactionProps
interface CosmosSignAndSendTransactionProps {
messages: Message[];
memo?: string;
fee?: Fee;
sequence?: number;
lcd_url?: string;
fee_denom?: string;
gas_rate?: number;
payer?: string;
granter?: string;
}
interface CosmosMessage {
type_url: string;
value?: unknown;
}CosmosFee
interface CosmosFee {
amount: Amount[];
gas_limit: number;
payer?: string;
granter?: string;
}
interface CosmosAmount {
denom: string;
amount: number;
}