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>
);
}
useChains
The useChains
hook allows you to work with multiple chains simultaneously. This is useful when you need to access data and functionality from several blockchains at once:
import { useChains } from '@interchain-kit/react';
function MultiChainComponent() {
// Access data and functions for multiple chains
const chains = useChains(['osmosis', 'juno', 'cosmoshub']);
return (
<div>
<h2>Multi-Chain Dashboard</h2>
{/* Osmosis Chain */}
<div>
<h3>Osmosis</h3>
<div>Status: {chains.osmosis.status}</div>
<div>Address: {chains.osmosis.address}</div>
<div>Chain ID: {chains.osmosis.chain.chainId}</div>
{chains.osmosis.status === 'Connected' ? (
<button onClick={chains.osmosis.disconnect}>Disconnect Osmosis</button>
) : (
<button onClick={chains.osmosis.connect}>Connect Osmosis</button>
)}
</div>
{/* Juno Chain */}
<div>
<h3>Juno</h3>
<div>Status: {chains.juno.status}</div>
<div>Address: {chains.juno.address}</div>
<div>Chain ID: {chains.juno.chain.chainId}</div>
{chains.juno.status === 'Connected' ? (
<button onClick={chains.juno.disconnect}>Disconnect Juno</button>
) : (
<button onClick={chains.juno.connect}>Connect Juno</button>
)}
</div>
{/* Cosmos Hub Chain */}
<div>
<h3>Cosmos Hub</h3>
<div>Status: {chains.cosmoshub.status}</div>
<div>Address: {chains.cosmoshub.address}</div>
<div>Chain ID: {chains.cosmoshub.chain.chainId}</div>
{chains.cosmoshub.status === 'Connected' ? (
<button onClick={chains.cosmoshub.disconnect}>Disconnect Cosmos Hub</button>
) : (
<button onClick={chains.cosmoshub.connect}>Connect Cosmos Hub</button>
)}
</div>
</div>
);
}
Advanced Multi-Chain Usage
You can also use useChains
for more complex scenarios like cross-chain operations:
import { useChains } from '@interchain-kit/react';
import { useState } from 'react';
function CrossChainComponent() {
const chains = useChains(['osmosis', 'juno']);
const [isProcessing, setIsProcessing] = useState(false);
const performCrossChainOperation = async () => {
if (chains.osmosis.status !== 'Connected' || chains.juno.status !== 'Connected') {
alert('Please connect to both Osmosis and Juno');
return;
}
setIsProcessing(true);
try {
// Example: Get signing clients for both chains
const osmosisClient = await chains.osmosis.getSigningClient();
const junoClient = await chains.juno.getSigningClient();
// Perform operations on both chains
console.log('Osmosis address:', chains.osmosis.address);
console.log('Juno address:', chains.juno.address);
// Your cross-chain logic here
console.log('Cross-chain operation completed');
} catch (error) {
console.error('Cross-chain operation failed:', error);
} finally {
setIsProcessing(false);
}
};
return (
<div>
<h2>Cross-Chain Operations</h2>
<div>
<h3>Chain Status</h3>
<div>Osmosis: {chains.osmosis.status}</div>
<div>Juno: {chains.juno.status}</div>
</div>
<button
onClick={performCrossChainOperation}
disabled={isProcessing ||
chains.osmosis.status !== 'Connected' ||
chains.juno.status !== 'Connected'
}
>
{isProcessing ? 'Processing...' : 'Perform Cross-Chain Operation'}
</button>
</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';
import "@interchain-ui/react/styles.css"; // Import styles for the modal
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>
useChains
<script setup lang="ts">
import { ref } from 'vue';
import { useChains } from '@interchain-kit/vue';
const chainNames = ref(['osmosis', 'juno', 'cosmoshub']);
const chains = useChains(chainNames);
</script>
<template>
<div>
<h2>Multi-Chain Dashboard</h2>
<!-- Osmosis Chain -->
<div>
<h3>Osmosis</h3>
<div>Status: {{ chains.osmosis.status }}</div>
<div>Address: {{ chains.osmosis.address }}</div>
<div>Chain ID: {{ chains.osmosis.chain.chainId }}</div>
<button
v-if="chains.osmosis.status === 'Connected'"
@click="chains.osmosis.disconnect.value()"
>
Disconnect Osmosis
</button>
<button
v-else
@click="chains.osmosis.connect.value()"
>
Connect Osmosis
</button>
</div>
<!-- Juno Chain -->
<div>
<h3>Juno</h3>
<div>Status: {{ chains.juno.status }}</div>
<div>Address: {{ chains.juno.address }}</div>
<div>Chain ID: {{ chains.juno.chain.chainId }}</div>
<button
v-if="chains.juno.status === 'Connected'"
@click="chains.juno.disconnect.value()"
>
Disconnect Juno
</button>
<button
v-else
@click="chains.juno.connect.value()"
>
Connect Juno
</button>
</div>
<!-- Cosmos Hub Chain -->
<div>
<h3>Cosmos Hub</h3>
<div>Status: {{ chains.cosmoshub.status }}</div>
<div>Address: {{ chains.cosmoshub.address }}</div>
<div>Chain ID: {{ chains.cosmoshub.chain.chainId }}</div>
<button
v-if="chains.cosmoshub.status === 'Connected'"
@click="chains.cosmoshub.disconnect.value()"
>
Disconnect Cosmos Hub
</button>
<button
v-else
@click="chains.cosmoshub.connect.value()"
>
Connect Cosmos Hub
</button>
</div>
</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>
);
}
Supporting Solana
Interchain Kit provides comprehensive support for Solana blockchain through SolanaWallet:
Available Solana Wallets
Interchain Kit supports several popular Solana wallets:
- Phantom Extension - Most popular Solana wallet
- Backpack Extension - Multi-chain wallet with Solana support
- Solflare Extension - Feature-rich Solana wallet
- Ledger - Hardware wallet support for Solana
- Mock Wallet - For development and testing
Basic Solana Integration
import { useChainWallet } from '@interchain-kit/react';
import { SolanaWallet } from '@interchain-kit/core';
function SolanaComponent() {
const {
address,
status,
wallet,
connect,
disconnect
} = useChainWallet('solana', 'phantom-extension');
return (
<div>
<div>Wallet: Phantom</div>
<div>Chain: Solana</div>
<div>Status: {status}</div>
<div>Address: {address}</div>
<button onClick={connect}>Connect</button>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
Solana Transaction Signing
import { useChainWallet } from '@interchain-kit/react';
import { SolanaWallet } from '@interchain-kit/core';
import {
Connection,
PublicKey,
Transaction,
SystemProgram,
LAMPORTS_PER_SOL
} from '@solana/web3.js';
function SolanaTransactionComponent() {
const { address, status, wallet } = useChainWallet('solana', 'phantom-extension');
const [isLoading, setIsLoading] = useState(false);
const sendSol = async () => {
if (status !== 'Connected' || !address) return;
setIsLoading(true);
try {
// Get Solana wallet instance
const solanaWallet = wallet.getWalletOfType(SolanaWallet);
if (!solanaWallet) throw new Error('Solana wallet not found');
// Create connection to Solana network
const connection = new Connection('https://api.mainnet-beta.solana.com');
// Create transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey(address),
toPubkey: new PublicKey('recipient-address'),
lamports: 0.1 * LAMPORTS_PER_SOL, // 0.1 SOL
})
);
// Get recent blockhash
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(address);
// Sign and send transaction
const signedTransaction = await solanaWallet.signTransaction(transaction);
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
console.log('Transaction signature:', signature);
} catch (error) {
console.error('Transaction failed:', error);
} finally {
setIsLoading(false);
}
};
return (
<div>
<button
onClick={sendSol}
disabled={isLoading || status !== 'Connected'}
>
{isLoading ? 'Sending...' : 'Send 0.1 SOL'}
</button>
</div>
);
}
Signing Solana Messages
import { useChainWallet } from '@interchain-kit/react';
import { SolanaWallet } from '@interchain-kit/core';
function SolanaMessageComponent() {
const { address, status, wallet } = useChainWallet('solana', 'phantom-extension');
const [message, setMessage] = useState('');
const [signature, setSignature] = useState<Uint8Array | null>(null);
const signMessage = async () => {
if (status !== 'Connected' || !message) return;
try {
const solanaWallet = wallet.getWalletOfType(SolanaWallet);
if (!solanaWallet) throw new Error('Solana wallet not found');
// Convert message to Uint8Array
const messageBytes = new TextEncoder().encode(message);
// Sign the message
const signedMessage = await solanaWallet.signMessage(messageBytes, 'utf8');
setSignature(signedMessage);
console.log('Message signed:', signedMessage);
} catch (error) {
console.error('Failed to sign message:', error);
}
};
return (
<div>
<h3>Sign Solana Message</h3>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter message to sign"
rows={3}
cols={50}
/>
<br />
<button onClick={signMessage} disabled={status !== 'Connected'}>
Sign Message
</button>
{signature && (
<div>
<h4>Signature:</h4>
<pre>{Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join('')}</pre>
</div>
)}
</div>
);
}
Batch Transaction Signing
import { useChainWallet } from '@interchain-kit/react';
import { SolanaWallet } from '@interchain-kit/core';
import {
Connection,
PublicKey,
Transaction,
SystemProgram,
LAMPORTS_PER_SOL
} from '@solana/web3.js';
function SolanaBatchTransactionComponent() {
const { address, status, wallet } = useChainWallet('solana', 'phantom-extension');
const signBatchTransactions = async () => {
if (status !== 'Connected' || !address) return;
try {
const solanaWallet = wallet.getWalletOfType(SolanaWallet);
if (!solanaWallet) throw new Error('Solana wallet not found');
const connection = new Connection('https://api.mainnet-beta.solana.com');
const { blockhash } = await connection.getLatestBlockhash();
// Create multiple transactions
const transactions = [
new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey(address),
toPubkey: new PublicKey('recipient1-address'),
lamports: 0.1 * LAMPORTS_PER_SOL,
})
),
new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey(address),
toPubkey: new PublicKey('recipient2-address'),
lamports: 0.05 * LAMPORTS_PER_SOL,
})
)
];
// Set recent blockhash for all transactions
transactions.forEach(tx => {
tx.recentBlockhash = blockhash;
tx.feePayer = new PublicKey(address);
});
// Sign all transactions at once
const signedTransactions = await solanaWallet.signAllTransactions(transactions);
console.log('Batch transactions signed:', signedTransactions);
} catch (error) {
console.error('Batch signing failed:', error);
}
};
return (
<div>
<button onClick={signBatchTransactions} disabled={status !== 'Connected'}>
Sign Batch Transactions
</button>
</div>
);
}
Solana Account Information
import { useChainWallet } from '@interchain-kit/react';
import { Connection, PublicKey } from '@solana/web3.js';
import { useState, useEffect } from 'react';
function SolanaAccountInfo() {
const { address, status } = useChainWallet('solana', 'phantom-extension');
const [balance, setBalance] = useState<number | null>(null);
const [isLoading, setIsLoading] = useState(false);
const fetchBalance = async () => {
if (status !== 'Connected' || !address) return;
setIsLoading(true);
try {
const connection = new Connection('https://api.mainnet-beta.solana.com');
const publicKey = new PublicKey(address);
const balance = await connection.getBalance(publicKey);
setBalance(balance / LAMPORTS_PER_SOL); // Convert lamports to SOL
} catch (error) {
console.error('Failed to fetch balance:', error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
if (status === 'Connected') {
fetchBalance();
}
}, [status, address]);
return (
<div>
<h3>Account Information</h3>
<div>Address: {address}</div>
<div>Status: {status}</div>
<div>
Balance: {isLoading ? 'Loading...' : balance !== null ? `${balance} SOL` : 'N/A'}
</div>
<button onClick={fetchBalance} disabled={isLoading || status !== 'Connected'}>
Refresh Balance
</button>
</div>
);
}
Vue Solana Integration
<script setup lang="ts">
import { ref } from 'vue';
import { useChainWallet } from '@interchain-kit/vue';
import { SolanaWallet } from '@interchain-kit/core';
import { Connection, PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
const chainName = ref('solana');
const walletName = ref('phantom-extension');
const { address, connect, disconnect, status, wallet } = useChainWallet(chainName, walletName);
const sendSol = async () => {
if (status.value !== 'Connected' || !address.value) return;
try {
const solanaWallet = wallet.value.getWalletOfType(SolanaWallet);
if (!solanaWallet) throw new Error('Solana wallet not found');
const connection = new Connection('https://api.mainnet-beta.solana.com');
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey(address.value),
toPubkey: new PublicKey('recipient-address'),
lamports: 0.1 * LAMPORTS_PER_SOL,
})
);
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(address.value);
const signedTransaction = await solanaWallet.signTransaction(transaction);
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
console.log('Transaction signature:', signature);
} catch (error) {
console.error('Transaction failed:', error);
}
};
</script>
<template>
<div>
<div>Wallet: Phantom</div>
<div>Chain: Solana</div>
<div>Status: {{ status }}</div>
<div>Address: {{ address }}</div>
<button @click="connect.value()" v-if="status !== 'Connected'">Connect</button>
<button @click="disconnect.value()" v-else>Disconnect</button>
<button @click="sendSol" v-if="status === 'Connected'">Send 0.1 SOL</button>
</div>
</template>
Solana Wallet Setup
To use Solana wallets in your application, you need to include them in your ChainProvider:
import { ChainProvider } from '@interchain-kit/react';
import { phantomWallet } from '@interchain-kit/phantom-extension';
import { backPackWallet } from '@interchain-kit/backpack-extension';
import { solflareWallet } from '@interchain-kit/solflare-extension';
// Define Solana chain configuration
const solanaChain = {
chainId: 'solana',
chainName: 'Solana',
rpc: 'https://api.mainnet-beta.solana.com',
rest: 'https://api.mainnet-beta.solana.com',
bip44: {
coinType: 501,
},
bech32Config: {
bech32PrefixAccAddr: 'sol',
bech32PrefixAccPub: 'solpub',
bech32PrefixValAddr: 'solvaloper',
bech32PrefixValPub: 'solvaloperpub',
bech32PrefixConsAddr: 'solvalcons',
bech32PrefixConsPub: 'solvalconspub',
},
currencies: [
{
coinDenom: 'SOL',
coinMinimalDenom: 'lamports',
coinDecimals: 9,
},
],
feeCurrencies: [
{
coinDenom: 'SOL',
coinMinimalDenom: 'lamports',
coinDecimals: 9,
},
],
stakeCurrency: {
coinDenom: 'SOL',
coinMinimalDenom: 'lamports',
coinDecimals: 9,
},
coinType: 501,
features: ['ibc-transfer'],
};
function App() {
return (
<ChainProvider
wallets={[phantomWallet, backPackWallet, solflareWallet]}
chains={[solanaChain]}
assetLists={[]}
>
{/* Your app components */}
</ChainProvider>
);
}
Solana-Specific Features
Interchain Kit's Solana support includes:
- Transaction Signing: Sign individual and batch transactions
- Message Signing: Sign arbitrary messages for authentication
- Account Management: Access to public keys and account information
- Provider Access: Direct access to Solana wallet providers
- Multi-Wallet Support: Support for multiple Solana wallets simultaneously
- Error Handling: Comprehensive error handling for Solana-specific operations
Best Practices for Solana
- Network Selection: Always specify the correct Solana network (mainnet-beta, devnet, testnet)
- Transaction Fees: Solana transactions require SOL for fees - ensure sufficient balance
- Recent Blockhash: Always fetch and set recent blockhash for transactions
- Error Handling: Handle Solana-specific errors like insufficient funds or network issues
- Account Validation: Validate Solana addresses before sending transactions
- Batch Operations: Use batch transaction signing for better UX when possible
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