Starknet wallet integration patterns for AI coding assistants. Covers wallet connection, account management, transaction building, and network configuration with ZapKit.
This skill teaches AI assistants how to integrate Starknet wallets using ZapKit SDK (@dngbuilds/zapkit-core and @dngbuilds/zapkit-react).
Every ZapKit app must be wrapped with ZapProvider:
import { ZapProvider } from "@dngbuilds/zapkit-react";
function App() {
return (
<ZapProvider
config={{
appName: "My dApp",
chains: ["mainnet"],
strategies: ["controller"],
}}
>
{children}
</ZapProvider>
);
}
The primary hook for wallet state:
import { useWallet } from "@dngbuilds/zapkit-react";
const { address, status, connect, disconnect, account } = useWallet();
// status: "idle" | "connecting" | "connected" | "error"
ZapKit supports multiple onboarding strategies:
import { useConnect } from "@dngbuilds/zapkit-react";
const { connect, connectors } = useConnect();
await connect({ strategy: "controller" });
const { address } = useWallet();
// address is the full hex address: "0x049d36570d4e46f48e99674bd3fcc84644ddddc7"
import { useStarknetId } from "@dngbuilds/zapkit-react";
const { name } = useStarknetId(address);
// name: "vitalik.stark" or null
Always call disconnect before switching strategies:
const { disconnect } = useWallet();
await disconnect();
import { useZapKit } from "@dngbuilds/zapkit-react";
const { zapkit } = useZapKit();
const result = await zapkit.execute({
contractAddress: TOKEN_ADDRESS,
entrypoint: "transfer",
calldata: [recipientAddress, amount, 0],
});
Always batch approve + action in a single multicall:
const result = await zapkit.execute([
{
contractAddress: TOKEN_ADDRESS,
entrypoint: "approve",
calldata: [spenderAddress, amount, 0],
},
{
contractAddress: DEX_ADDRESS,
entrypoint: "swap",
calldata: [TOKEN_ADDRESS, amount, 0, minAmountOut, 0],
},
]);
Handle UserRejectedRequestError separately from network errors:
try {
await zapkit.execute(calls);
} catch (err) {
if (err.name === "UserRejectedRequestError") {
// User cancelled — show nothing or a mild toast
} else {
// Network/contract error — show error UI
console.error("Transaction failed:", err);
}
}
Use the ChainId enum, never hardcode chain IDs:
import { ChainId } from "@dngbuilds/zapkit-core";
// ChainId.MAINNET — "SN_MAIN"
// ChainId.SEPOLIA — "SN_SEPOLIA"
// ChainId.DEVNET — "SN_DEVNET"
<ZapProvider config={{ rpcUrl: "https://starknet-mainnet.public.blastapi.io" }}>
| Rule | Priority | Description |
|---|---|---|
| wallet-connect | CRITICAL | Always wrap app with ZapProvider; use hooks not direct SDK calls |
| transaction-building | HIGH | Use multicall for approve+action; always handle errors |
| error-handling | HIGH | Handle UserRejectedRequestError separately from network errors |
| network-config | MEDIUM | Use ChainId enum, never hardcode chain IDs |
| account-lifecycle | MEDIUM | Always call disconnect() before switching strategies |