Manage Starknet accounts
You can manage Starknet accounts in MetaMask using the
get-starknet library or the
wallet_invokeSnap JSON-RPC method.
- Account creation in Starknet is handled by the wallet provider. As a dapp developer, you do not create accounts directly. Instead, you can guide users to create an account with MetaMask.
- Currently, the Starknet Snap doesn't support multiple Starknet accounts.
Prerequisites
Connect to Starknet from your dapp.
Display account information
After a user connects to their Starknet account in MetaMask, you can display the account details. The following example displays the account address:
- get-starknet
- wallet_invokeSnap
const connectStarknetAccount = async () => {
  const starknet = await connect();
  await starknet.enable();  // Prompts the user to connect their Starknet account using MetaMask.
  return starknet;
};
const showAccountInfo = async () => {
  const starknet = await connectStarknetAccount();
  
  if (account) {
    document.getElementById("accountAddress").innerText = `Account Address: ${starknet.selectedAddress}`;
  }
};
const showAccountInfo = async () => {
  if (typeof provider !== "undefined" && provider.isMetaMask) {
    try {
      // Invoke the Starknet Snap to get account information.
      const response = await provider // Or window.ethereum if you don't support EIP-6963.
        .request({
          method: "wallet_invokeSnap",
          params: {
            snapId: "npm:@starknet-snap/snap", 
            request: {
              method: "starknet_recoverAccounts"
            }
          }
        });
      if (response && response.length > 0) {
        const account = response[0]; // Get the first account.
        document.getElementById("accountAddress").innerText = `Account Address: ${account.address}`;
      } else {
        document.getElementById("accountAddress").innerText = "No Starknet account found";
      }
    } catch (error) {
      console.error("Error fetching Starknet account:", error);
      document.getElementById("accountAddress").innerText = "Error fetching account information";
    }
  } else {
    document.getElementById("accountAddress").innerText = "MetaMask not detected or Snaps not supported";
  }
};
// Call the function when needed.
showAccountInfo();
Retrieve the connected account
You can retrieve and display a user's connected Starknet account. The following example displays the connected account address if available, and displays buttons to connect or disconnect the account.
- get-starknet
- wallet_invokeSnap
import { useStarknet, useConnectors } from "@starknet-react/core";
import { useState, useEffect } from "react";
function AccountDisplay() {
  const { account } = useStarknet();
  const { available, connect, disconnect } = useConnectors();
  const [accountAddress, setAccountAddress] = useState<string | undefined>();
  useEffect(() => {
    setAccountAddress(account?.address);
  }, [account]);
  return (
    <div>
      {accountAddress ? (
        <p>Connected Account: {accountAddress}</p>
      ) : (
        <p>No account connected</p>
      )}
      {available.map((connector) => (
        <button key={connector.id()} onClick={() => connect(connector)}>
          Connect {connector.name()}
        </button>
      ))}
      {account && (
        <button onClick={() => disconnect()}>Disconnect</button>
      )}
    </div>
  );
}
import React, { useState, useEffect } from "react";
const STARKNET_SNAP_ID = "npm:@starknet-snap/snap";
function AccountDisplay() {
  const [accountAddress, setAccountAddress] = useState<string | undefined>();
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const connectToSnap = async () => {
    if (typeof provider !== "undefined" && provider.isMetaMask) {
      try {
        // Request permission to access the Snap.
        await provider // Or window.ethereum if you don't support EIP-6963.
          .request({
            method: "wallet_requestSnaps",
            params: { [STARKNET_SNAP_ID]: {} }
          });
        setIsConnected(true);
        fetchAccount();
      } catch (err) {
        console.error("Error connecting to Starknet Snap:", err);
        setError("Failed to connect to Starknet Snap");
      }
    } else {
      setError("MetaMask not detected or Snaps not supported");
    }
  };
  const disconnectFromSnap = async () => {
    setAccountAddress(undefined);
    setIsConnected(false);
  };
  const fetchAccount = async () => {
    if (typeof provider !== "undefined" && provider.isMetaMask) {
      try {
        const response = await provider // Or window.ethereum if you don't support EIP-6963.
          .request({
            method: "wallet_invokeSnap",
            params: {
              snapId: STARKNET_SNAP_ID,
              request: {
                method: "starknet_recoverAccounts"
              }
            }
          });
        if (response && response.length > 0) {
          setAccountAddress(response[0].address);
        } else {
          setError("No Starknet account found");
        }
      } catch (err) {
        console.error("Error fetching Starknet account:", err);
        setError("Failed to fetch account information");
      }
    }
  };
  useEffect(() => {
    if (isConnected) {
      fetchAccount();
    }
  }, [isConnected]);
  return (
    <div>
      {accountAddress ? (
        <p>Connected Account: {accountAddress}</p>
      ) : (
        <p>No account connected</p>
      )}
      {!isConnected ? (
        <button onClick={connectToSnap}>Connect to Starknet</button>
      ) : (
        <button onClick={disconnectFromSnap}>Disconnect</button>
      )}
      {error && <p style={{ color: "red" }}>{error}</p>}
    </div>
  );
}
export default AccountDisplay;
Manage account transactions
You can manage a user's Starknet account transactions. The following example invokes a specific function on a Starknet smart contract, handles wallet connection and transaction submission, and logs the result or any errors:
- get-starknet
- wallet_invokeSnap
const invokeStarknetContract = async () => {
  try {
    const starknet = getStarknet();
    await starknet.enable();  // Make sure the wallet is enabled.
    const contractAddress = "0xYourContractAddress";  // Replace with your contract address.
    const entrypoint = "function_name";  // The function you want to call.
    const calldata = [/* your function arguments */];  // Replace with calldata.
    const result = await starknet.account.execute({
      contractAddress: contractAddress,
      entrypoint: entrypoint,
      calldata: calldata
    });
    console.log("Transaction result: ", result);
  } catch (error) {
    console.error("Error invoking contract:", error);
  }
};
const invokeStarknetContract = async () => {
  if (typeof provider !== "undefined" && provider.isMetaMask) {
    try {
      const calls = [
        {
          entrypoint: "transfer", // The function name to call on the contract.
          calldata: [
            "0x1234567890abcdef1234567890abcdef12345678", // Recipient's address.
            "1000000000000000000" // Amount to transfer in wei (1 token, assuming 18 decimals).
          ]
        }
      ];
      const result = await provider // Or window.ethereum if you don't support EIP-6963.
        .request({
          method: "wallet_invokeSnap",
          params: {
            snapId: "npm:@consensys/starknet-snap",
            request: {
              method: "starkNet_executeTxn",
              params: {
                address: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", // The sender's address.
                calls: calls, // The array of calls with entrypoint and calldata.
                details: {
                  nonce: 1, // Optional nonce.
                  maxFee: "1000000000000000", // Maximum gas fee allowed.
                },
                chainId: "0x534e5f5345504f4c4941" // Starknet Sepolia testnet chain ID.
              }
            }
          }
        });
      console.log("Transaction result: ", result);
    } catch (error) {
      console.error("Error invoking contract:", error);
    }
  } else {
    console.error("MetaMask not detected or Snaps not supported");
  }
};
Handle account changes and disconnections
You can handle account changes and disconnections. Use the following component at the top level of your dapp to handle account changes globally:
- get-starknet
- wallet_invokeSnap
import { getStarknet } from "get-starknet";
import { useEffect, useState } from "react";
function AccountChangeHandler() {
  const [account, setAccount] = useState<string | null>(null);
  useEffect(() => {
    const starknet = getStarknet();
    const handleAccountsChanged = (accounts: string[]) => {
      console.log("Accounts changed:", accounts);
      setAccount(accounts[0] || null);
    };
    const handleDisconnect = () => {
      console.log("Disconnected from wallet");
      setAccount(null);
    };
    if (starknet) {
      starknet.on("accountsChanged", handleAccountsChanged);
      starknet.on("networkChanged", handleDisconnect);
      // Initial account setup.
      starknet.enable().then((accounts: string[]) => {
        setAccount(accounts[0] || null);
      });
      return () => {
        starknet.off("accountsChanged", handleAccountsChanged);
        starknet.off("networkChanged", handleDisconnect);
      };
    }
  }, []);
  return (
    <div>
      {account ? (
        <p>Connected Account: {account}</p>
      ) : (
        <p>No account connected</p>
      )}
    </div>
  );
}
export default AccountChangeHandler;
import React, { useEffect, useState } from "react";
const STARKNET_SNAP_ID = "npm:@starknet-snap/snap";
function AccountChangeHandler() {
  const [account, setAccount] = useState<string | null>(null);
  const fetchAccount = async () => {
    if (typeof provider !== "undefined" && provider.isMetaMask) {
      try {
        const response = await provider // Or window.ethereum if you don't support EIP-6963.
          .request({
            method: "wallet_invokeSnap",
            params: {
              snapId: STARKNET_SNAP_ID,
              request: {
                method: "starknet_recoverAccounts"
              }
            }
          });
        if (response && response.length > 0) {
          setAccount(response[0].address);
        } else {
          setAccount(null);
        }
      } catch (error) {
        console.error("Error fetching Starknet account:", error);
        setAccount(null);
      }
    } else {
      console.error("MetaMask not detected or Snaps not supported");
      setAccount(null);
    }
  };
  useEffect(() => {
    fetchAccount();
    // Retrieve account changes every 5 seconds.
    const intervalId = setInterval(fetchAccount, 5000);
    return () => clearInterval(intervalId);
  }, []);
  return (
    <div>
      {account ? (
        <p>Connected Account: {account}</p>
      ) : (
        <p>No account connected</p>
      )}
    </div>
  );
}
export default AccountChangeHandler;