Interchain Kit
Usage

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

  1. Network Selection: Always specify the correct Solana network (mainnet-beta, devnet, testnet)
  2. Transaction Fees: Solana transactions require SOL for fees - ensure sufficient balance
  3. Recent Blockhash: Always fetch and set recent blockhash for transactions
  4. Error Handling: Handle Solana-specific errors like insufficient funds or network issues
  5. Account Validation: Validate Solana addresses before sending transactions
  6. 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

  1. Error Handling: Always implement proper error handling for wallet connections and transactions
  2. Loading States: Show loading states during wallet connections and transactions
  3. Responsive Design: Make sure your UI is responsive and works well on both desktop and mobile
  4. Security: Never store private keys or sensitive data in your application
  5. 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

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:

  1. Connect to a specific chain using useChain
  2. Get a Cosmos wallet instance using wallet.getWalletOfType(CosmosWallet)
  3. Sign arbitrary messages with cosmosWallet.signArbitrary()
  4. 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:

  1. Connect to the Ethereum chain using useChain("ethereum")
  2. Get an Ethereum wallet instance using wallet.getWalletOfType(EthereumWallet)
  3. Sign messages with ethereumWallet.signMessage()
  4. Display the resulting signature to the user