Wallets
Starknet Start does not need connector instances for browser wallets.
StarknetConfig wraps GetStarknetProvider from @starknet-io/get-starknet-modal,
which discovers the wallets injected in the page and exposes them to
useConnect and to the
premade connect UI.
Three StarknetConfig props control which wallets your users see:
recommendedWallets: wallets to suggest, including ones the user has not installed yet.extraWallets: wallets that can't be discovered from the page, such as a wallet injected under a custom key.store: a custom discovery store, to change how wallets are discovered.
Wallet discovery
Injected wallets are discovered automatically. You don't need to configure anything for wallets that use one of these mechanisms:
| Mechanism | How the wallet announces itself |
|---|---|
| Wallet Standard | The wallet registers through the wallet-standard:register-wallet event and implements the Starknet wallet features. |
Legacy window objects | The wallet injects a StarknetWindowObject (id, name, version, icon, request, on, off) on a window.starknet* key. |
| EIP-6963 (MetaMask Snap) | MetaMask announces itself through EIP-6963 and is adapted to Starknet with the Starknet Snap. |
Legacy injected wallets are wrapped in StarknetInjectedWallet so every
wallet exposes the same Wallet Standard interface
(WalletWithStarknetFeatures). If a wallet is found both ways, the Wallet
Standard registration replaces the legacy one.
Recommended wallets
recommendedWallets takes wallet metadata (WalletInformation: id, name,
icon and downloads links), not wallet instances. Recommended wallets that
are not installed are listed as "unavailable" with their download links.
Installed wallets are matched to their metadata by their Starknet wallet API
id, wallet.features[StarknetWalletApi].id.
When the prop is omitted, every wallet known to get-starknet is recommended: Ready Wallet (formerly Argent X), Braavos, MetaMask, OKX Wallet and Keplr. Pass your own list to change the suggestions, or an empty array to show only installed wallets.
"use client";
import React from "react";
import { , } from "@starknet-io/get-starknet-core/wallets";
import { } from "@starknetfoundation/starknet-start-chains";
import { } from "@starknetfoundation/starknet-start-providers";
import { } from "@starknetfoundation/starknet-start-react";
function ({ }: { : React. }) {
return (
< ={[]} ={()} ={[, ]}>
{}
</>
);
}@starknet-io/get-starknet-core/wallets exports readyWallet, braavos,
metaMask, okxWallet, keplr and the full wallets list. To recommend
another wallet, pass a WalletInformation object whose id equals the
wallet's features[StarknetWalletApi].id. For a legacy injected wallet, that
is the id of its window object. If the ids don't match, the modal lists the
installed wallet and an unavailable recommendation as two separate entries.
Extra wallets
extraWallets takes Wallet Standard objects (WalletWithStarknetFeatures[])
and lists them alongside the discovered wallets. They are always shown as
available and are returned by useConnect().connectors.
Keep extra wallets stable between renders (at module scope, in state or in a
useMemo). Don't pass a wallet that discovery already finds, or it is listed
twice.
Custom injected wallets
If a wallet injects a StarknetWindowObject that discovery doesn't pick up,
wrap it with StarknetInjectedWallet and pass it to extraWallets. Read the
window object after your app mounts: window is not defined during
server-side rendering, and the wallet may inject itself after your bundle is
evaluated.
"use client";
import React, { , , } from "react";
import { } from "@starknet-io/get-starknet-core";
import { } from "@starknetfoundation/starknet-start-chains";
import { } from "@starknetfoundation/starknet-start-providers";
import { } from "@starknetfoundation/starknet-start-react";
type = <typeof >[0];
declare global {
interface Window {
?: ;
}
}
function () {
const [, ] = <>();
(() => {
if (.) {
(new (.));
}
}, []);
return ;
}
export function ({ }: { : React. }) {
const = ();
const = (() => ( ? [] : []), []);
return (
< ={[]} ={()} ={}>
{}
</>
);
}Replace window.myWallet with the key your wallet injects. If the wallet
injects itself after your app has mounted, run the check again when the wallet
signals that it is ready.
If you are building a wallet, register it through the Wallet Standard. Dapps then discover it without extra configuration, whenever it loads.
Cartridge Controller
Install both the @cartridge/connector and @cartridge/controller packages.
pnpm i @cartridge/connector @cartridge/controllerCreating a ControllerConnector registers Controller through the Wallet
Standard, so wallet discovery finds it like any other wallet. Create the
connector once, at module scope, and don't pass controller.asWalletStandard()
to extraWallets: Controller would be listed twice.
"use client";
import type React from "react";
import { ControllerConnector } from "@cartridge/connector";
import { mainnet, sepolia } from "@starknetfoundation/starknet-start-chains";
import { cartridgeProvider } from "@starknetfoundation/starknet-start-providers";
import { StarknetConfig } from "@starknetfoundation/starknet-start-react";
import { constants } from "starknet";
// Registers Controller with the Wallet Standard when created in the browser.
const controller = new ControllerConnector({
chains: [
{
rpcUrl: "https://api.cartridge.gg/x/starknet/sepolia",
},
{
rpcUrl: "https://api.cartridge.gg/x/starknet/mainnet",
},
],
defaultChainId: constants.StarknetChainId.SN_SEPOLIA,
});
export function AppProviders({ children }: { children: React.ReactNode }) {
return (
<StarknetConfig chains={[sepolia, mainnet]} provider={cartridgeProvider()} defaultChainId={sepolia.id}>
{children}
</StarknetConfig>
);
}The Controller enables seamless use of Session Keys. Pass session policies
to the connector to enable them:
import { ControllerConnector } from "@cartridge/connector";
import { SessionPolicies } from "@cartridge/controller";
import { constants } from "starknet";
const policies: SessionPolicies = {
contracts: {
"0x3f96056436be253753351fe689110ced7d53f5db3fd98f13df3f19058311b95": {
name: "Example Contract",
description: "Example contract interaction",
methods: [
{
name: "Create",
description: "Create a new instance",
entrypoint: "create",
},
],
},
},
};
const controller = new ControllerConnector({
chains: [
{
rpcUrl: "https://api.cartridge.gg/x/starknet/sepolia",
},
{
rpcUrl: "https://api.cartridge.gg/x/starknet/mainnet",
},
],
defaultChainId: constants.StarknetChainId.SN_SEPOLIA,
policies,
});To change where Controller appears in the premade UI, use the sortAlgorithm
prop of WalletConnectModal.
Custom discovery store
By default, all StarknetConfig instances share one discovery store. Pass your
own store to change how wallets are discovered. For example, to stop
offering MetaMask through the Starknet Snap, create a store without EIP-1193
adapters:
"use client";
import React from "react";
import { } from "@starknet-io/get-starknet-core";
import { } from "@starknetfoundation/starknet-start-chains";
import { } from "@starknetfoundation/starknet-start-providers";
import { } from "@starknetfoundation/starknet-start-react";
// Create the store once: it registers discovery listeners on `window`.
const = ({ : [] });
function ({ }: { : React. }) {
return (
< ={[]} ={()} ={}>
{}
</>
);
}You may also want to drop metaMask from recommendedWallets so it is no
longer suggested.
Connecting from your UI
Use WalletConnectModal from @starknet-io/get-starknet-ui for a ready-made
connect button and wallet list; see the Connect Wallet UI demo.
To build your own list, useConnect returns the discovered and extra wallets
as connectors:
"use client";
import React from "react";
import { } from "@starknet-io/get-starknet-core";
import { } from "@starknetfoundation/starknet-start-react";
function () {
const { , } = ();
return (
<>
{.(() => (
< ={.[].} ={() => ({ })}>
< ={.} ="" ={20} ={20} />
Connect {.}
</>
))}
</>
);
}connectors only contains installed and extra wallets. Recommended wallets
that are not installed are only listed by the premade UI.