Using Interchain Kit
This guide covers the detailed usage of Interchain Kit, showing you how to work with different hooks, connect to wallets, access blockchain data, and perform transactions.
Core Concepts
Before diving into the code examples, here are some key concepts to understand:
- ChainProvider: The main provider component that wraps your application and provides access to chains and wallets
- Chains: Blockchain networks with which your application can interact
- Wallets: Interfaces that allow users to access their accounts and sign transactions
- Hooks: React/Vue composables that provide functionality for interacting with chains and wallets
React Hooks
useChain
The useChain
hook allows you to work with a specific blockchain:
import { useChain } from '@interchain-kit/react';
function ChainComponent() {
// Access data and functions for the specified chain
const {
logoUrl, // Chain logo URL
address, // User's address on this chain
status, // Connection status ('Connected', 'Connecting', 'Disconnected', etc.)
username, // User's name (if available)
wallet, // Current wallet object
rpcEndpoint, // RPC endpoint for the chain
connect, // Function to connect to the chain
disconnect, // Function to disconnect from the chain
openView // Function to open wallet view
} = useChain('osmosis');
return (
<div>
<div>Connection Status: {status}</div>
{status === 'Connected' ? (
<>
<div>Address: {address}</div>
<button onClick={disconnect}>Disconnect</button>
</>
) : (
<button onClick={connect}>Connect</button>
)}
</div>
);
}
useChainWallet
The useChainWallet
hook is used to interact with a specific chain through a specific wallet:
import { useChainWallet } from '@interchain-kit/react';
function ChainWalletComponent() {
// Access data and functions for a specific chain and wallet combination
const {
address,
connect,
disconnect,
status,
signingClient, // Signing client for transactions
isSigningClientLoading,
assetList // List of assets on the chain
} = useChainWallet('juno', 'keplr-extension');
return (
<div>
<div>Wallet: Keplr</div>
<div>Chain: Juno</div>
<div>Status: {status}</div>
<div>Address: {address}</div>
<button onClick={connect}>Connect</button>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
useWalletManager
The useWalletManager
hook gives you access to the wallet manager instance, allowing you to interact with all available wallets and chains:
import { useWalletManager } from '@interchain-kit/react';
import { Chain } from '@chain-registry/types';
function WalletManagerComponent() {
const walletManager = useWalletManager();
return (
<div>
<h2>Available Chains</h2>
<ul>
{walletManager.chains.map((chain: Chain) => (
<li key={chain.chainId}>{chain.chainName}</li>
))}
</ul>
<h2>Available Wallets</h2>
<ul>
{walletManager.wallets.map((wallet) => (
<li key={wallet.info?.name}>{wallet.info?.prettyName}</li>
))}
</ul>
</div>
);
}
useWalletModal
The useWalletModal
hook controls the built-in wallet modal for connecting and switching wallets:
import { useWalletModal } from '@interchain-kit/react';
import { InterchainWalletModal } from '@interchain-kit/react';
function WalletModalComponent() {
const { isOpen, open, close } = useWalletModal();
return (
<>
<button onClick={open}>Select Wallet</button>
<InterchainWalletModal />
</>
);
}
Vue Composables
useChain
<script setup lang="ts">
import { ref } from 'vue';
import { useChain } from '@interchain-kit/vue';
const chainName = ref('cosmoshub');
const {
address,
wallet,
logoUrl,
connect,
disconnect,
status
} = useChain(chainName);
</script>
<template>
<div>
<div>Connection Status: {{ status }}</div>
<div v-if="status === 'Connected'">
<div>Address: {{ address }}</div>
<button @click="disconnect">Disconnect</button>
</div>
<button v-else @click="connect">Connect</button>
</div>
</template>
useChainWallet
<script setup lang="ts">
import { ref } from 'vue';
import { useChainWallet } from '@interchain-kit/vue';
const chainName = ref('juno');
const walletName = ref('keplr-extension');
const {
address,
connect,
disconnect,
status,
signingClient,
isSigningClientLoading
} = useChainWallet(chainName, walletName);
</script>
<template>
<div>
<div>Wallet: Keplr</div>
<div>Chain: Juno</div>
<div>Status: {{ status }}</div>
<div>Address: {{ address }}</div>
<button @click="connect.value()">Connect</button>
<button @click="disconnect.value()">Disconnect</button>
</div>
</template>
Using the Wallet Modal in Vue
<script setup lang="ts">
import { inject } from 'vue';
import { InterchainWalletModal, OPEN_MODAL_KEY } from '@interchain-kit/vue';
const openModal = inject(OPEN_MODAL_KEY);
</script>
<template>
<button @click="openModal">Select Wallet</button>
<InterchainWalletModal />
</template>
Working with Signers and Transactions
Interchain Kit provides access to signing clients for executing transactions on the blockchain:
import { useChainWallet } from '@interchain-kit/react'; // or '@interchain-kit/vue'
import { coins } from '@cosmjs/amino';
function TransactionComponent() {
const {
address,
signingClient,
isSigningClientLoading,
status
} = useChainWallet('osmosis', 'keplr-extension');
const sendTokens = async () => {
if (!signingClient || isSigningClientLoading || status !== 'Connected') {
return;
}
try {
// Example: Send tokens using CosmJS (with InterchainJS)
const result = await signingClient.sendTokens(
address, // from address (current connected wallet)
'recipient-address', // to address
coins('1000000', 'uosmo'), // amount
'memo' // optional memo
);
console.log('Transaction result:', result);
} catch (error) {
console.error('Transaction failed:', error);
}
};
return (
<div>
<button
onClick={sendTokens}
disabled={isSigningClientLoading || status !== 'Connected'}
>
Send Tokens
</button>
</div>
);
}
Querying Account Balances
You can query account balances using the RPC endpoint:
import { useChainWallet } from '@interchain-kit/react'; // or '@interchain-kit/vue'
import { getBalance } from 'interchainjs/cosmos/bank/v1beta1/query.rpc.func';
import { useState } from 'react';
function BalanceComponent() {
const { address, status, rpcEndpoint } = useChainWallet('osmosis', 'keplr-extension');
const [balance, setBalance] = useState<string>();
const [isLoading, setIsLoading] = useState(false);
const fetchBalance = async () => {
if (status !== 'Connected' || !rpcEndpoint) return;
setIsLoading(true);
try {
const result = await getBalance(rpcEndpoint as string, {
address,
denom: 'uosmo',
});
setBalance(result.balance.amount);
} catch (error) {
console.error('Failed to fetch balance:', error);
} finally {
setIsLoading(false);
}
};
return (
<div>
<button onClick={fetchBalance} disabled={isLoading || status !== 'Connected'}>
{isLoading ? 'Loading...' : 'Fetch Balance'}
</button>
{balance && <div>Balance: {balance} uosmo</div>}
</div>
);
}
Supporting EVM Chains
Interchain Kit also supports Ethereum-compatible chains through EthereumWallet:
import { useChainWallet } from '@interchain-kit/react'; // or '@interchain-kit/vue'
import { ethers } from 'ethers';
function EVMComponent() {
const { address, status, wallet } = useChainWallet('ethereum', 'metamask-extension');
const getEthBalance = async () => {
if (status !== 'Connected') return;
// Get Ethereum provider
const provider = await wallet.getProvider('1'); // Chain ID for Ethereum mainnet
const ethProvider = new ethers.providers.Web3Provider(provider);
// Get balance
const balance = await ethProvider.getBalance(address);
console.log('ETH Balance:', ethers.utils.formatEther(balance));
};
return (
<div>
<button onClick={getEthBalance} disabled={status !== 'Connected'}>
Get ETH Balance
</button>
</div>
);
}
Using WalletConnect
Interchain Kit supports WalletConnect for mobile wallet connections:
import { WCWallet } from '@interchain-kit/core';
import { ChainProvider } from '@interchain-kit/react'; // or '@interchain-kit/vue'
// Setup WalletConnect with custom metadata
const walletConnect = new WCWallet(undefined, {
metadata: {
name: "My Interchain App",
description: "Application description",
url: "https://myapp.example",
icons: ["https://myapp.example/logo.png"],
},
});
function AppWithWalletConnect() {
return (
<ChainProvider
wallets={[keplrWallet, leapWallet, walletConnect]}
chains={chains}
assetLists={assetLists}
>
{/* Your app components */}
</ChainProvider>
);
}
Best Practices
- Error Handling: Always implement proper error handling for wallet connections and transactions
- Loading States: Show loading states during wallet connections and transactions
- Responsive Design: Make sure your UI is responsive and works well on both desktop and mobile
- Security: Never store private keys or sensitive data in your application
- Testing: Test your application with multiple wallets and on different networks
Advanced Configuration
For advanced configuration options, you can provide additional options to the ChainProvider:
<ChainProvider
wallets={[keplrWallet, leapWallet]}
chains={chains}
assetLists={assetLists}
signerOptions={{
signingStargate: () => {
return {
gasPrice: GasPrice.fromString('0.0025uatom'),
};
},
signingCosmwasm: () => {
return {
gasPrice: GasPrice.fromString('0.0025uatom'),
};
},
}}
endpointOptions={{
endpoints: {
osmosis: {
rpc: ['https://custom-rpc.osmosis.zone'],
rest: ['https://custom-rest.osmosis.zone'],
},
},
}}
>
{/* Your app components */}
</ChainProvider>
Further Resources
- InterchainJS Documentation (opens in a new tab)
- Chain Registry Documentation (opens in a new tab)
- Example Applications (opens in a new tab)
Signing Arbitrary Messages with Cosmos Wallet
Interchain Kit allows you to sign arbitrary messages using a Cosmos Wallet:
import {
CosmosWallet,
ExtensionWallet,
isInstanceOf,
MultiChainWallet,
} from "@interchain-kit/core";
import { useChain } from "@interchain-kit/react";
import { useState } from "react";
const CosmosWalletExample: React.FC = () => {
// Connect to a specific chain
const { wallet, connect, address, disconnect, chain } =
useChain("osmosistestnet");
const [message, setMessage] = useState("");
const [signature, setSignature] = useState("");
const handleConnect = async () => {
connect();
};
const handleDisconnect = async () => {
disconnect();
};
const handleSignArbitrary = async () => {
// get specific wallet to use its own methods
const cosmosWallet = wallet.getWalletOfType(CosmosWallet);
if (cosmosWallet) {
const signed = await cosmosWallet.signArbitrary(
chain.chainId as string,
address,
message
);
setSignature(signed.signature);
}
};
return (
<div>
<h1>Cosmos Wallet</h1>
{address ? (
<div>
<p>Connected Address: {address}</p>
<button onClick={handleDisconnect}>Disconnect</button>
</div>
) : (
<button onClick={handleConnect}>Connect Wallet</button>
)}
<div>
<h2>Sign Arbitrary Message</h2>
<textarea
rows={4}
cols={50}
placeholder="Enter a message to sign"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<br />
<button onClick={handleSignArbitrary}>
Sign Message
</button>
{signature && (
<div>
<h3>Signature:</h3>
<pre>{signature}</pre>
</div>
)}
</div>
</div>
);
};
This example demonstrates how to:
- Connect to a specific chain using
useChain
- Get a Cosmos wallet instance using
wallet.getWalletOfType(CosmosWallet)
- Sign arbitrary messages with
cosmosWallet.signArbitrary()
- Display the resulting signature to the user
Signing Messages with Ethereum Wallet
Interchain Kit also allows you to sign messages using an Ethereum Wallet:
import { EthereumWallet } from "@interchain-kit/core";
import { useChain } from "@interchain-kit/react";
import React, { useState } from "react";
const EthereumWalletExample: React.FC = () => {
const [message, setMessage] = useState<string>("");
const [signature, setSignature] = useState<string | null>(null);
// Connect to Ethereum chain
const { connect, address, disconnect, wallet } = useChain("ethereum");
const connectWallet = async () => {
connect();
};
const disconnectWallet = async () => {
disconnect();
setSignature(null);
};
const signMessage = async () => {
// get specific wallet to use its own methods
const ethereumWallet = wallet.getWalletOfType(EthereumWallet);
if (ethereumWallet) {
try {
const signedMessage = await ethereumWallet.signMessage(message);
setSignature(signedMessage);
} catch (error) {
console.error("Error signing message:", error);
}
}
};
return (
<div>
<h2>Ethereum Sign Message Example</h2>
{!address ? (
<button onClick={connectWallet}>Connect Wallet</button>
) : (
<button onClick={disconnectWallet}>Disconnect Wallet</button>
)}
<div>
<div>
<strong>Connected:</strong> {address}
</div>
<textarea
rows={3}
style={{ width: "100%", marginTop: 16 }}
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<button style={{ marginTop: 16 }} onClick={signMessage}>
Sign Message
</button>
</div>
{signature && (
<div style={{ marginTop: 16 }}>
<strong>Signature:</strong>
<pre>{signature}</pre>
</div>
)}
</div>
);
};
This example demonstrates how to:
- Connect to the Ethereum chain using
useChain("ethereum")
- Get an Ethereum wallet instance using
wallet.getWalletOfType(EthereumWallet)
- Sign messages with
ethereumWallet.signMessage()
- Display the resulting signature to the user