Wallet Connection Flow
Connecting to a SUI wallet is the first step in any dApp. This chapter covers the SUI wallet standard, auto-discovery of browser wallets, and the provider hierarchy needed for React dApps.
The SUI Wallet Standard
SUI uses the [Wallet Standard](https://docs.sui.io/guides/developer/sui-wallet-standard) -- a specification that allows dApps to discover and interact with wallets without knowing the specific wallet implementation. Any wallet that implements the standard (EVE Vault, Sui Wallet, etc.) will automatically appear in your dApp.
Provider Setup
The wallet context must wrap your entire application. The AncientStorage dApp uses a lazy-loaded provider to avoid SSR crashes:
'use client';
import { Component, useEffect, useState } from 'react';
type SuiNetwork = 'mainnet' | 'testnet';
const DEFAULT_NETWORK: SuiNetwork =
(process.env.NEXT_PUBLIC_SUI_NETWORK as SuiNetwork) ?? 'testnet';
const FULLNODE_URLS: Record<SuiNetwork, string> = {
mainnet: 'https://fullnode.mainnet.sui.io:443',
testnet: 'https://fullnode.testnet.sui.io:443',
};
export function SuiWalletProvider({
children,
}: {
children: React.ReactNode;
}): React.ReactElement {
const [suiModules, setSuiModules] = useState(null);
useEffect(() => {
let cancelled = false;
Promise.all([
import('@mysten/dapp-kit-core'),
import('@mysten/dapp-kit-react'),
import('@mysten/sui/grpc'),
])
.then(([coreModule, reactModule, grpcModule]) => {
if (cancelled) return;
const kit = coreModule.createDAppKit({
networks: [DEFAULT_NETWORK],
createClient: (network: string) =>
new grpcModule.SuiGrpcClient({
network: network || DEFAULT_NETWORK,
baseUrl: FULLNODE_URLS[network] ?? FULLNODE_URLS[DEFAULT_NETWORK],
}),
defaultNetwork: DEFAULT_NETWORK,
autoConnect: true,
});
setSuiModules({
DAppKitProvider: reactModule.DAppKitProvider,
dAppKit: kit,
});
})
.catch(() => {
// Module load failure is non-fatal
});
return () => { cancelled = true; };
}, []);
if (!suiModules) {
return <>{children}</>;
}
const { DAppKitProvider, dAppKit } = suiModules;
return (
<DAppKitProvider dAppKit={dAppKit}>
{children}
</DAppKitProvider>
);
}Why Lazy Loading?
The @mysten/dapp-kit-react package accesses window at the module level, which causes crashes during server-side rendering (SSR) in Next.js. By dynamically importing the modules inside useEffect, we ensure they only load in the browser.
The createDAppKit Configuration
const kit = coreModule.createDAppKit({
networks: [DEFAULT_NETWORK],
createClient: (network) =>
new SuiGrpcClient({
network,
baseUrl: FULLNODE_URLS[network],
}),
defaultNetwork: DEFAULT_NETWORK,
autoConnect: true,
});- networks: Which networks your dApp supports.
- createClient: Factory function that creates a SUI client for each network.
- defaultNetwork: Which network to use initially.
- autoConnect: Attempt to reconnect to the last-used wallet on page load.
Detecting Wallets
The useWallets hook returns all discovered wallets:
import { useWallets } from '@mysten/dapp-kit-react';
function WalletButton() {
const wallets = useWallets();
const hasWallet = wallets.length > 0;
if (!hasWallet) {
return (
<button onClick={() => window.open('https://evefrontier.com/vault', '_blank')}>
Install EVE Vault
</button>
);
}
return <button>Connect Wallet</button>;
}Wallet discovery happens automatically through the wallet standard. When a user has EVE Vault (or any SUI-compatible wallet) installed as a browser extension, it registers itself and appears in the wallets array.
Connecting
Use useDAppKit().connectWallet() to initiate the connection:
import { useDAppKit, useWallets } from '@mysten/dapp-kit-react';
function ConnectButton() {
const wallets = useWallets();
const dAppKit = useDAppKit();
const handleConnect = async () => {
if (wallets.length === 0) return;
await dAppKit.connectWallet({ wallet: wallets[0] });
};
return <button onClick={handleConnect}>Connect</button>;
}The connectWallet call triggers the wallet's connection popup. The user approves the connection, and the dApp receives the connected account information.
Reading Connection State
The useWalletConnection hook provides the current connection state:
import { useWalletConnection } from '@mysten/dapp-kit-react';
function AccountInfo() {
const connection = useWalletConnection();
if (!connection.isConnected || !connection.account) {
return <p>Not connected</p>;
}
const address = connection.account.address;
const abbreviated = ${address.slice(0, 6)}...${address.slice(-4)};
return <p>Connected: {abbreviated}</p>;
}The connection.account object provides:
address-- the user's SUI address (e.g.,0x1234...abcd)- Other wallet-specific metadata
Disconnecting
const dAppKit = useDAppKit();
const handleDisconnect = async () => {
await dAppKit.disconnectWallet();
};The Complete Component
Here is the AncientStorage dApp's wallet connection button with all states:
export function WalletConnectButton({ callbackUrl = '/' }) {
const wallets = useWallets();
const dAppKit = useDAppKit();
const connection = useWalletConnection();
const hasWallet = wallets.length > 0;
// Not connected — show connect or install button
if (!connection.isConnected) {
return (
<button onClick={async () => {
if (!hasWallet) {
window.open('https://evefrontier.com/vault', '_blank');
return;
}
await dAppKit.connectWallet({ wallet: wallets[0] });
}}>
{hasWallet ? 'Connect Wallet' : 'Install EVE Vault'}
</button>
);
}
// Connected but not signed in — show sign-in button
return (
<div>
<button onClick={handleSignIn}>
Sign Message to Log In
</button>
<span>{connection.account?.address}</span>
</div>
);
}Notice the two-step flow: first connect (establish communication with the wallet), then sign in (prove identity via message signing, covered in the next chapter).
Key Takeaways
- SUI uses the Wallet Standard for automatic wallet discovery -- any compatible wallet works.
- Lazy-load
@mysten/dapp-kit-reactto avoid SSR crashes in Next.js. createDAppKitconfigures the network, client factory, and auto-connect behavior.- Use
useWallets()to detect installed wallets anduseDAppKit().connectWallet()to connect. useWalletConnection()provides the current connection state and account address.- Wallet connection is separate from authentication -- connecting only establishes communication, not identity.
Sign in to track your progress.