React + wagmi
This article demonstrates how to connect UKey Wallet via wagmi in a React project. The overall solution is based on EIP-1193 Provider: the application reads UKey Wallet's dedicated injection object window.$ukey.ethereum first, and if it cannot be found, it falls back to the multi-wallet Provider list or the general window.ethereum.
Setup
npm i wagmi viem
wagmi v2 uses viem as the underlying capability. This page uses the Injected connector to connect to the wallet injected by the browser, so it supports UKey Wallet and is also compatible with other EIP-1193 wallets.
Create a connector that prefers UKey Wallet
Multiple wallet extensions may be installed in the browser at the same time. If you use window.ethereum directly, the application sometimes cannot determine which wallet it is connected to. The following connector will first check the UKey Wallet-specific entry and then fall back in order to ensure more predictable connection behavior.
// File: ukeyConnector.ts
import { createConfig, http } from "wagmi";
import { mainnet, polygon, arbitrum, base, optimism } from "wagmi/chains";
import { injected } from "wagmi/connectors";
function selectPreferredUKeyProvider(): any {
// 1) Try UKey Wallet's dedicated injected provider first
const ukey = (window as any)?.$ukey?.ethereum;
if (ukey) return ukey;
// 2) Fallback: search the multi-provider deviceList for UKey Wallet
const deviceList = (window as any)?.ethereum?.providers;
const okFromList = deviceList?.find(
(p: any) =>
p?.isUKey ||
p?.ukey ||
(typeof p?.isUKey === "function" && p.isUKey()),
);
if (okFromList) return okFromList;
// 3) Last fallback: use the single injected provider
return (window as any)?.ethereum;
}
export const config = createConfig({
chains: [mainnet, polygon, arbitrum, base, optimism],
connectors: [
injected({
target() {
return {
id: "ukey",
name: "UKey Wallet",
provider: selectPreferredUKeyProvider,
};
},
shimDisconnect: true,
}),
],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
[arbitrum.id]: http(),
[base.id]: http(),
[optimism.id]: http(),
},
});
Access points
- Reading
window.$ukey.ethereumfirst can reduce the probability of selecting the wrong Provider in a multi-wallet environment. - When the user does not install UKey Wallet, the connector will still fall back to other injection wallets to facilitate compatibility processing.
eth_requestAccountsShould be triggered after the user clicks the button, do not automatically request the account when the page loads.- When the user refuses authorization,
4001will usually be returned. Please provide an understandable retry prompt on the interface.
Apply settings
// File: main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { config } from "./ukeyConnector";
import WalletConnectionPanel from "./WalletConnectionPanel";
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<WalletConnectionPanel />
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
);
Connect and read accounts
// File: WalletConnectionPanel.tsx
import { useAccount, useConnect, useDisconnect } from "wagmi";
export default function WalletConnectionPanel() {
const { address, isConnected } = useAccount();
const { connect, connectors, isPending } = useConnect();
const { disconnect } = useDisconnect();
if (isConnected) {
return (
<div>
<p>Connected: {address}</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
);
}
return (
<div>
{connectors.map((c) => (
<button
key={c.uid}
disabled={isPending}
onClick={() => connect({ connector: c })}
>
Connect with {c.name}
</button>
))}
</div>
);
}
Sign and send transactions
import { createWalletClient, custom } from "viem";
const provider =
(window as any)?.$ukey?.ethereum ||
(window as any)?.ethereum?.providers?.find(
(p: any) => p?.isUKey || p?.ukey,
) ||
(window as any)?.ethereum;
const client = createWalletClient({ transport: custom(provider) });
const [account] = await provider.request({ method: "eth_requestAccounts" });
// Note: personal signature
await provider.request({
method: "personal_sign",
requestParams: ["0x68656c6c6f", account],
});
// EIP-1559 type Transaction
const txHash = await provider.request({
method: "eth_sendTransaction",
requestParams: [{ from: account, to: "0x...", value: "0x..." }],
});
Events and network switching
- Monitor
accountsChangedandchainChanged, and refresh the application status synchronously when the account or chain changes. - When switching or adding networks, use
wallet_switchEthereumChainandwallet_addEthereumChain. - Before sending a transaction, re-read the current account and chain ID to prevent users from continuing to use the old status after switching on the wallet side.
Mobile deep linking
Mobile Web or WebView can open the wallet through UKey Wallet Deeplink:
- Custom protocol:
ukey-wallet:/wc?uri={encodeURIComponent(wcUri)} - Universal link:
https://app.ukey.io/
troubleshooting
4001: The user refuses authorization or signature. Please keep the current page status and allow the user to click the connection again.- Provider not detected: Checks whether the extension is installed, disabled by the browser, and the page is running in a supported environment.
- Multi-wallet conflict: read
window.$ukey.ethereumfirst to avoid Errornly connecting to other wallets.
EIP-6963 Add-On (Multiple Wallet Discovery)
If the project has been connected to EIP-6963, it can monitor the wallet announcement event and use it as the preferred provider when UKey Wallet is discovered:
let ukeyProvider: any = null;
const providers: any[] = [];
function captureAnnouncedProvider(event: any) {
const { info, provider } = event.detail || {};
providers.push({ info, provider });
if (info?.name === "UKey Wallet" || info?.rdns?.includes?.("ukey")) {
ukeyProvider = provider;
}
}
window.addEventListener("eip6963:announceProvider", captureAnnouncedProvider);
window.dispatchEvent(new Event("eip6963:requestProvider"));
// Prefer `ukeyProvider` during app init; if it is absent, fall back to selectPreferredUKeyProvider()