| name | graz |
| description | React hooks for Cosmos blockchain interactions — connect wallets, query balances, send tokens, sign messages. Use when building Cosmos dApps with graz hooks, setting up GrazProvider, connecting wallets, or performing transactions. |
Using the graz Library
React hooks for Cosmos blockchain interactions.
Quick start
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { GrazProvider, useConnect, useAccount, useSendTokens, useStargateSigningClient } from "graz";
import { cosmoshub } from "graz/chains";
const queryClient = new QueryClient();
export function App() {
return (
<QueryClientProvider client={queryClient}>
<GrazProvider grazOptions={{ chains: [cosmoshub] }}>
<Wallet />
</GrazProvider>
</QueryClientProvider>
);
}
function Wallet() {
const { connect } = useConnect();
const { data: accounts, isConnected } = useAccount({ chainId: ["cosmoshub-4"] as const });
const { data: signingClients } = useStargateSigningClient({ chainId: ["cosmoshub-4"] as const, enabled: isConnected });
const { sendTokens } = useSendTokens();
const addr = accounts?.["cosmoshub-4"]?.bech32Address;
return (
<button onClick={async () => {
if (!addr) return connect();
await sendTokens({ signingClient: signingClients?.["cosmoshub-4"], senderAddress: addr, recipientAddress: "cosmos1...", amount: [{ denom: "uatom", amount: "1000" }], fee: { amount: [{ denom: "uatom", amount: "500" }], gas: "200000" } });
}}>{addr || "Connect"}</button>
);
}
Provider Setup
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { GrazProvider } from "graz";
import { cosmoshub } from "graz/chains";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<GrazProvider grazOptions={{ chains: [cosmoshub] }}>
<YourApp />
</GrazProvider>
</QueryClientProvider>
);
}
GrazProvider must be inside QueryClientProvider. The chains prop is required — pass ChainInfo[] (from graz/chains, defineChainInfo(), or manually).
Configure Options
interface ConfigureGrazArgs {
chains: ChainInfo[];
defaultWallet?: WalletType;
chainsConfig?: Record<string, ChainConfig>;
autoReconnect?: boolean;
walletConnect?: {
options: { projectId: string };
modalOptions?: ModalConfig;
};
walletDefaultOptions?: Keplr["defaultOptions"];
multiChainFetchConcurrency?: number;
onNotFound?: () => void;
onReconnectFailed?: () => void;
iframeOptions?: IframeOptions;
pingInteval?: number;
logger?: { enabled?: boolean; level?: LogLevel; categories?: (keyof typeof LogCategory)[] };
paraConfig?: ParaGrazConfig;
}
Chain Info
import { defineChainInfo, defineChains } from "graz";
const myChain = defineChainInfo({
chainId: "mychain-1",
currencies: [{ coinDenom: "TOKEN", coinMinimalDenom: "utoken", coinDecimals: 6 }],
rpc: "https://rpc.example.com",
rest: "https://rest.example.com",
bech32Config: {
bech32PrefixAccAddr: "mychain",
bech32PrefixAccPub: "mychainpub",
bech32PrefixValAddr: "mychainvaloper",
bech32PrefixValPub: "mychainvaloperpub",
bech32PrefixConsAddr: "mychainvalcons",
bech32PrefixConsPub: "mychainvalconspub",
},
chainName: "My Chain",
feeCurrencies: [{ coinDenom: "TOKEN", coinMinimalDenom: "utoken", coinDecimals: 6 }],
stakeCurrency: { coinDenom: "TOKEN", coinMinimalDenom: "utoken", coinDecimals: 6 },
bip44: { coinType: 118 },
});
defineChains({ cosmoshub, osmosis });
CLI Generate
pnpm graz cli --generate
pnpm graz cli --generate --mainnet cosmoshub,osmosis --testnet osmosistestnet
pnpm graz cli --generate --endpoint <url>
pnpm graz cli --generate --best
pnpm graz cli --generate --authz
Output goes to packages/graz/chains/index.{js,mjs,ts} (gitignored).
import { cosmoshub, osmosis, mainnetChains, testnetChains } from "graz/chains";
Wallet Connection
Connect
import { useConnect, useAccount, useDisconnect, useActiveWalletType, useCheckWallet } from "graz";
import { WalletType } from "graz";
const { connect, connectAsync, isLoading, isSuccess, isSupported, error } = useConnect();
connect();
connect({ walletType: WalletType.KEPLR });
connect({ chainId: ["cosmoshub-4", "osmosis-1"] });
connect({ walletType: WalletType.LEAP, chainId: ["cosmoshub-4"] });
connect({ autoReconnect: false });
import { connect, disconnect, getAvailableWallets, checkWallet, clearSession } from "graz";
await connect({ walletType: WalletType.KEPLR });
Reactive Account State
const { data: accounts, isConnected, isConnecting, isDisconnected, status, reconnect } = useAccount();
const address = Object.values(accounts || {})[0]?.bech32Address;
const { data: accounts } = useAccount({ chainId: ["cosmoshub-4", "osmosis-1"] as const });
const atomAddress = accounts?.["cosmoshub-4"]?.bech32Address;
Check Wallet Availability
const { data: isKeplrAvailable } = useCheckWallet(WalletType.KEPLR);
const { data: isCosmostationAvailable } = useCheckWallet(WalletType.COSMOSTATION);
const available = getAvailableWallets();
const supported = checkWallet();
const cosmostationSupported = checkWallet(WalletType.COSMOSTATION);
const { walletType, isKeplr, isCosmostation, isWalletConnect } = useActiveWalletType();
Disconnect
const { disconnect, disconnectAsync, isLoading } = useDisconnect();
disconnect();
disconnect({ chainId: ["cosmoshub-4"] });
import { clearSession } from "graz";
clearSession();
Wallet Events
Use useWalletEvents to react to committed wallet state changes. The hook owns
its subscription and automatically cleans it up when the component unmounts.
import { useWalletEvents } from "graz";
function WalletEventObserver() {
useWalletEvents({
onAccountChange: ({ accounts, previousAccounts, changedChainIds, walletType }) => {
console.log({ accounts, previousAccounts, changedChainIds, walletType });
},
onActiveChainsChange: ({ activeChainIds, previousActiveChainIds, walletType }) => {
console.log({ activeChainIds, previousActiveChainIds, walletType });
},
onDisconnect: ({ chainIds, reason, walletType }) => {
console.log({ chainIds, reason, walletType });
},
});
return null;
}
onActiveChainsChange reports the complete set of connected
activeChainIds. It does not represent an EVM-style switch to one active
chain. Initial connection does not emit account or active-chain events.
For non-React consumers, subscribe imperatively and retain the cleanup
function:
import { subscribeWalletEvents } from "graz";
const unsubscribe = subscribeWalletEvents({
onDisconnect: ({ reason }) => console.log(reason),
});
unsubscribe();
Balance changes are not wallet events. Use useBalance or useBalances and an
explicit refetch strategy when balance monitoring is required.
Offline Signers
const { data: signers } = useOfflineSigners();
const { data: signers } = useOfflineSigners({ chainId: ["cosmoshub-4"] as const });
const { offlineSigner, offlineSignerAmino, offlineSignerAuto } = signers?.["cosmoshub-4"] || {};
import { getOfflineSigners } from "graz";
const signers = await getOfflineSigners({ chainId: "cosmoshub-4", walletType: WalletType.KEPLR });
Balance Queries
const { data: balances } = useBalances({
chainId: "cosmoshub-4",
bech32Address: "cosmos1...",
enabled: Boolean(address),
});
const { data: atomBalance } = useBalance({
chainId: "cosmoshub-4",
bech32Address: "cosmos1...",
denom: "uatom",
enabled: Boolean(address),
});
const { data: staked } = useBalanceStaked({
chainId: "cosmoshub-4",
bech32Address: "cosmos1...",
enabled: Boolean(address),
});
Clients
Read Clients
const { data: stargateClients } = useStargateClient({
chainId: ["cosmoshub-4"] as const,
enabled: Boolean(connected),
});
const { data: cosmwasmClients } = useCosmWasmClient({
chainId: ["neutron-1"] as const,
enabled: Boolean(connected),
});
Signing Clients (requires wallet connected)
const { data: signingClients, isLoading } = useStargateSigningClient({
chainId: ["cosmoshub-4"] as const,
enabled: isConnected,
offlineSigner: "offlineSignerAuto",
});
const { data: cosmwasmSigningClients } = useCosmWasmSigningClient({
chainId: ["neutron-1"] as const,
enabled: isConnected,
});
await signingClients?.["cosmoshub-4"]?.sendTokens(
senderAddress,
recipientAddress,
[{ denom: "uatom", amount: "1000" }],
{ amount: [{ denom: "uatom", amount: "500" }], gas: "200000" }
);
Transaction Hooks
const { sendTokens, sendTokensAsync, isPending, isSuccess, isError, data, reset } = useSendTokens();
sendTokens({
signingClient: signingClients?.["cosmoshub-4"],
senderAddress: account?.bech32Address,
recipientAddress: "cosmos1...",
amount: [{ denom: "uatom", amount: "1000" }],
fee: { amount: [{ denom: "uatom", amount: "500" }], gas: "200000" },
memo: "optional memo",
});
const { sendIbcTokens } = useSendIbcTokens();
sendIbcTokens({
signingClient,
senderAddress,
recipientAddress: "osmo1...",
transferAmount: { denom: "uatom", amount: "1000" },
sourcePort: "transfer",
sourceChannel: "channel-0",
timeoutTimestamp: (Date.now() + 600_000) * 1_000_000,
fee: { amount: [{ denom: "uatom", amount: "500" }], gas: "200000" },
});
const { executeContract } = useExecuteContract();
executeContract({
signingClient,
senderAddress: account?.bech32Address,
contractAddress: "cosmos1contract...",
msg: { transfer: { recipient: "cosmos1...", amount: "100" } },
fee: { amount: [{ denom: "uatom", amount: "500" }], gas: "300000" },
funds: [{ denom: "uatom", amount: "100" }],
});
const { instantiateContract } = useInstantiateContract();
instantiateContract({
codeId: 1,
signingClient,
senderAddress: account?.bech32Address,
msg: { name: "My Contract", symbol: "MYC" },
label: "my-contract",
fee: { amount: [{ denom: "uatom", amount: "5000" }], gas: "500000" },
});
const { data: queryResult } = useQuerySmart({
address: "cosmos1contract...",
queryMsg: { get_info: {} },
});
Chain Management
const { suggest } = useSuggestChain();
await suggest({ chainInfo: cosmoshub, walletType: WalletType.KEPLR });
const { suggestAndConnect } = useSuggestChainAndConnect();
await suggestAndConnect({ chainInfo: osmosistestnet });
const { addChain } = useAddChain();
await addChain({ chainInfo: myNewChain });
const { data: chainInfo } = useChainInfo({ chainId: "cosmoshub-4" });
const { data: chainInfos } = useChainInfos({ chainId: ["cosmoshub-4", "osmosis-1"] });
const { data: activeChains } = useActiveChains();
const { data: activeChainIds } = useActiveChainIds();
const { data: recentChainIds, clear: clearRecentIds } = useRecentChainIds();
const { data: recentChains, clear: clearRecentChains } = useRecentChains();
import { addChain, suggestChain, suggestChainAndConnect, getChainInfo, getChainInfos } from "graz";
Multi-Chain API Pattern
All hooks that accept chainId support three overloads:
useAccount();
useAccount({ chainId: ["cosmoshub-4"] as const });
useAccount({ chainId: ["cosmoshub-4", "osmosis-1"] as const });
This applies to: useAccount, useOfflineSigners, useStargateClient, useCosmWasmClient, useStargateSigningClient, useCosmWasmSigningClient.
The UseMultiChainQueryResult<TChainIds, TData> return type gives you:
TypeUseMultiChainQueryResult<TChainIds, TData> = UseQueryResult<
TChainIds extends readonly string[] ? ChainIdToRecord<TChainIds, TData> : Record<string, TData>
>;
Logger
import { LOG_CATEGORIES, LOG_FUNCTIONS, LOG_HOOKS, LogLevel, LogCategory } from "graz";
<GrazProvider grazOptions={{
chains: [...],
logger: {
enabled: true,
level: LogLevel.DEBUG,
categories: ["WALLET", "TRANSACTION"],
},
}}/>;
Key Types
import { WalletType, Key, Wallet, OfflineSigners, ConnectResult, UseMultiChainQueryResult, ChainConfig } from "graz";
WalletType.KEPLR, WalletType.COSMOSTATION,
WalletType.VECTIS, WalletType.WALLETCONNECT, WalletType.OKX,
WalletType.PARA, WalletType.INITIA, WalletType.CACTUSCOSMOS,
WalletType.COMPASS, WalletType.STATION, WalletType.XDEFI,
WalletType.COSMIFRAME, WalletType.METAMASK_SNAP_COSMOS,
WalletType.WC_KEPLR_MOBILE,
WalletType.WC_COSMOSTATION_MOBILE, WalletType.WC_CLOT_MOBILE
interface Key {
name: string;
algo: string;
pubKey: Uint8Array;
address: Uint8Array;
bech32Address: string;
isNanoLedger: boolean;
}
interface OfflineSigners {
offlineSigner: OfflineSigner;
offlineSignerAmino: OfflineSignerAmino;
offlineSignerAuto: OfflineSigner;
}
interface QueryConfig { enabled?: boolean; }
interface MutationEventArgs<T = unknown, S = T> {
onError?: (error: unknown, data: T) => unknown;
onLoading?: (data: T) => unknown;
onSuccess?: (data: S) => unknown;
}
Quick Reference
| Task | Hook/Action |
|---|
| Connect wallet | useConnect() → connect() |
| Disconnect | useDisconnect() → disconnect() |
| Account state | useAccount({ chainId }) |
| Wallet events | useWalletEvents(handlers), subscribeWalletEvents(handlers) |
| Check wallet availability | useCheckWallet(type), getAvailableWallets() |
| Active wallet info | useActiveWalletType() |
| Offline signers | useOfflineSigners({ chainId }) |
| Read client | useStargateClient({ chainId }), useCosmWasmClient({ chainId }) |
| Signing client | useStargateSigningClient({ chainId }), useCosmWasmSigningClient({ chainId }) |
| Balances | useBalances({ chainId, bech32Address }) |
| Single balance | useBalance({ chainId, bech32Address, denom }) |
| Staked balance | useBalanceStaked({ chainId, bech32Address }) |
| Send tokens | useSendTokens() |
| IBC transfer | useSendIbcTokens() |
| Execute contract | useExecuteContract() |
| Instantiate contract | useInstantiateContract() |
| Query contract | useQuerySmart({ address, queryMsg }) |
| Query raw | useQueryRaw({ address, key }) |
| Suggest chain | useSuggestChain(), useSuggestChainAndConnect() |
| Add chain | useAddChain() |
| Chain info | useChainInfo({ chainId }), useChainInfos({ chainId }) |
| Active chains | useActiveChains(), useActiveChainIds() |
| Validators | useQueryClientValidators({ queryClient }) |