CardanoProvider Context
The CardanoProvider provides a React Context for managing Cardano state across your entire application.
Overview
Instead of passing Lucid instances through props, use CardanoProvider to make Cardano state available anywhere in your component tree.
import { CardanoProvider, useCardano } from 'cardano-devkit';
function App() {
return (
<CardanoProvider network="Preprod" debug={true}>
<Header />
<Main />
<Footer />
</CardanoProvider>
);
}
Setup
CardanoProvider Props
interface CardanoProviderProps {
children: React.ReactNode;
// Network configuration
network?: NetworkType; // Default: 'Preprod'
provider?: ProviderConfig; // Custom provider config
// Features
autoConnect?: boolean; // Auto-connect on mount
persistWallet?: boolean; // Remember wallet connection
debug?: boolean; // Enable debug logging
// Callbacks
onConnect?: (address: string) => void;
onDisconnect?: () => void;
onError?: (error: Error) => void;
onNetworkChange?: (network: NetworkType) => void;
}
Basic Setup
import { CardanoProvider } from 'cardano-devkit';
function App() {
return (
<CardanoProvider
network="Preprod"
autoConnect={true}
persistWallet={true}
onConnect={(address) => console.log('Connected:', address)}
onError={(error) => console.error('Error:', error)}
>
<YourApp />
</CardanoProvider>
);
}
Context Hooks
useCardano()
Get the full Cardano context with all state and actions.
import { useCardano } from 'cardano-devkit';
function MyComponent() {
const {
// State
lucid,
network,
address,
balance,
isInitialized,
isConnected,
isLoading,
error,
availableWallets,
// Actions
connect,
disconnect,
switchNetwork,
refreshBalance,
signMessage,
signTransaction,
} = useCardano();
// Use context values...
}
useCardanoWallet()
Focused hook for wallet operations.
import { useCardanoWallet } from 'cardano-devkit';
function WalletButton() {
const {
address,
balance,
isConnected,
availableWallets,
connect,
disconnect,
} = useCardanoWallet();
if (isConnected) {
return (
<div>
<span>{truncateAddress(address)}</span>
<span>{formatLovelace(balance)} ADA</span>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
return (
<div>
<h3>Connect Wallet</h3>
{availableWallets.map(wallet => (
<button
key={wallet.name}
onClick={() => connect('browser', wallet.name)}
>
<img src={wallet.icon} alt={wallet.name} />
{wallet.name}
</button>
))}
</div>
);
}
useCardanoNetwork()
Focused hook for network operations.
import { useCardanoNetwork } from 'cardano-devkit';
function NetworkSelector() {
const {
network,
isLocalDevnet,
isTestnet,
isMainnet,
switchNetwork,
useLocalDevnet,
usePreprod,
usePreview,
useMainnet,
} = useCardanoNetwork();
return (
<div>
<p>Current: {network}</p>
<button onClick={() => usePreprod()}>Preprod</button>
<button onClick={() => usePreview()}>Preview</button>
<button onClick={() => useLocalDevnet()}>Local</button>
<button
onClick={() => useMainnet({ confirmMainnet: true })}
style={{ color: 'red' }}
>
Mainnet
</button>
</div>
);
}
useCardanoTx()
Focused hook for transaction operations.
import { useCardanoTx } from 'cardano-devkit';
function SendButton() {
const {
send,
sendMultiple,
sendWithMessage,
mint,
status,
lastTxHash,
error,
} = useCardanoTx();
const handleSend = async () => {
const txHash = await send("addr_test1...", 5000000n);
console.log("Sent:", txHash);
};
return (
<div>
<button onClick={handleSend} disabled={status === 'submitting'}>
Send 5 ADA
</button>
{status === 'submitted' && <p>TX: {lastTxHash}</p>}
{error && <p>Error: {error.message}</p>}
</div>
);
}
Type Definitions
CardanoContext
interface CardanoContext {
state: CardanoContextState;
actions: CardanoContextActions;
}
interface CardanoContextState {
lucid: LucidEvolution | null;
network: NetworkType;
address: string | null;
balance: bigint;
utxos: UTxO[];
isInitialized: boolean;
isConnected: boolean;
isLoading: boolean;
error: Error | null;
availableWallets: AvailableWallet[];
}
interface CardanoContextActions {
// Connection
connect: (method: WalletMethod, credential: string) => Promise<void>;
disconnect: () => void;
// Network
switchNetwork: (network: NetworkType) => Promise<void>;
useLocalDevnet: (port?: number) => Promise<void>;
usePreprod: () => Promise<void>;
usePreview: () => Promise<void>;
useMainnet: (options: MainnetSwitchOptions) => Promise<void>;
// Wallet operations
refreshBalance: () => Promise<void>;
signMessage: (message: string) => Promise<string>;
signTransaction: (tx: Transaction) => Promise<SignedTransaction>;
// Transaction helpers
send: (to: string, amount: bigint) => Promise<string>;
sendMultiple: (payments: SimplePayment[]) => Promise<string>;
sendWithMessage: (to: string, amount: bigint, message: string) => Promise<string>;
}
interface AvailableWallet {
name: string;
icon: string;
apiVersion: string;
isEnabled: boolean;
}
type TransactionStatus =
| 'idle'
| 'building'
| 'signing'
| 'submitting'
| 'submitted'
| 'confirmed'
| 'error';
Complete Example
import React from 'react';
import {
CardanoProvider,
useCardano,
useCardanoWallet,
useCardanoNetwork,
useCardanoTx,
formatLovelace,
truncateAddress,
} from 'cardano-devkit';
// Wallet connection component
function WalletConnect() {
const { address, balance, isConnected, availableWallets, connect, disconnect } = useCardanoWallet();
if (isConnected) {
return (
<div className="wallet-info">
<span>{truncateAddress(address!, 8, 6)}</span>
<span>{formatLovelace(balance)}</span>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
return (
<div className="wallet-connect">
{availableWallets.map(wallet => (
<button key={wallet.name} onClick={() => connect('browser', wallet.name)}>
Connect {wallet.name}
</button>
))}
</div>
);
}
// Network switcher component
function NetworkSwitcher() {
const { network, usePreprod, usePreview, useLocalDevnet } = useCardanoNetwork();
return (
<select value={network} onChange={e => {
switch (e.target.value) {
case 'Preprod': usePreprod(); break;
case 'Preview': usePreview(); break;
case 'LocalDevnet': useLocalDevnet(); break;
}
}}>
<option value="Preprod">Preprod</option>
<option value="Preview">Preview</option>
<option value="LocalDevnet">Local Devnet</option>
</select>
);
}
// Transaction form component
function SendForm() {
const [recipient, setRecipient] = React.useState('');
const [amount, setAmount] = React.useState('');
const { send, status, lastTxHash, error } = useCardanoTx();
const { isConnected } = useCardanoWallet();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const lovelace = BigInt(parseFloat(amount) * 1_000_000);
await send(recipient, lovelace);
};
if (!isConnected) {
return <p>Connect wallet to send ADA</p>;
}
return (
<form onSubmit={handleSubmit}>
<input
placeholder="Recipient address"
value={recipient}
onChange={e => setRecipient(e.target.value)}
/>
<input
type="number"
placeholder="Amount (ADA)"
value={amount}
onChange={e => setAmount(e.target.value)}
/>
<button type="submit" disabled={status === 'submitting'}>
{status === 'submitting' ? 'Sending...' : 'Send ADA'}
</button>
{lastTxHash && <p>TX: {lastTxHash}</p>}
{error && <p className="error">{error.message}</p>}
</form>
);
}
// Main app
function App() {
return (
<CardanoProvider
network="Preprod"
autoConnect={true}
persistWallet={true}
debug={true}
>
<header>
<h1>My Cardano dApp</h1>
<NetworkSwitcher />
<WalletConnect />
</header>
<main>
<SendForm />
</main>
</CardanoProvider>
);
}
export default App;
Best Practices
- Wrap at the top level: Place
CardanoProvidernear the root of your app - Use specific hooks: Prefer
useCardanoWalletoveruseCardanowhen you only need wallet state - Handle loading states: Always check
isInitializedandisLoadingbefore rendering - Error boundaries: Wrap components in error boundaries to catch Cardano errors
- Persist wallet: Use
persistWallet={true}for better UX across page reloads
// Error boundary example
import { ErrorBoundary } from 'react-error-boundary';
function App() {
return (
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<CardanoProvider network="Preprod">
<YourApp />
</CardanoProvider>
</ErrorBoundary>
);
}