Skip to main content

Connecting to Phantom Wallets

The React SDK follows a clear connection pattern using hooks for wallet connection and chain-specific operations.

Connection Flow

  1. Provider Setup: Wrap your app with PhantomProvider
  2. Connection: Use useConnect() to establish wallet connection
  3. Chain Operations: Use chain-specific hooks (useSolana(), useEthereum()) for transactions and signing
import { useConnect, useSolana, useEthereum } from "@phantom/react-sdk";

function WalletExample() {
  const { connect } = useConnect();
  const { solana } = useSolana();
  const { ethereum } = useEthereum();

  // 1. Connect first
  const handleConnect = async () => {
    await connect();
  };

  // 2. Then use chain-specific operations
  const sendSolanaTransaction = async () => {
    const result = await solana.signAndSendTransaction(transaction);
  };

  const sendEthereumTransaction = async () => {
    const result = await ethereum.sendTransaction(transaction);
  };
}

Core Connection Hooks

useConnect

Connect to wallet:
import { useConnect } from "@phantom/react-sdk";

function ConnectButton() {
  const { connect, isConnecting, error } = useConnect();

  const handleConnect = async () => {
    try {
      const { walletId, addresses } = await connect();
      console.log("Connected addresses:", addresses);
    } catch (err) {
      console.error("Failed to connect:", err);
    }
  };

  return (
    <button onClick={handleConnect} disabled={isConnecting}>
      {isConnecting ? "Connecting..." : "Connect Wallet"}
    </button>
  );
}

useAccounts

Get connected wallet addresses:
import { useAccounts } from "@phantom/react-sdk";

function WalletAddresses() {
  const addresses = useAccounts();

  if (!addresses) {
    return <div>Not connected</div>;
  }

  return (
    <div>
      {addresses.map((addr, index) => (
        <div key={index}>
          <strong>{addr.addressType}:</strong> {addr.address}
        </div>
      ))}
    </div>
  );
}

useDisconnect

Disconnect from wallet:
import { useDisconnect } from "@phantom/react-sdk";

function DisconnectButton() {
  const { disconnect, isDisconnecting } = useDisconnect();

  return (
    <button onClick={disconnect} disabled={isDisconnecting}>
      {isDisconnecting ? "Disconnecting..." : "Disconnect"}
    </button>
  );
}

useIsExtensionInstalled

Check if the Phantom browser extension is installed (for injected provider):
import { useIsExtensionInstalled } from "@phantom/react-sdk";

function ExtensionStatus() {
  const { isLoading, isInstalled } = useIsExtensionInstalled();

  if (isLoading) {
    return <div>Checking for Phantom extension...</div>;
  }

  return (
    <div>
      {isInstalled ? (
        <p>✅ Phantom extension is installed!</p>
      ) : (
        <p>
          ❌ Phantom extension not found.{" "}
          <a href="https://phantom.app/download" target="_blank">
            Install here
          </a>
        </p>
      )}
    </div>
  );
}

Provider Type Switching

Even if you start with the embedded provider, you can switch to the injected provider (browser extension) at runtime using the underlying SDK:
import { useConnect, usePhantom, useIsExtensionInstalled } from "@phantom/react-sdk";

function ProviderSwitcher() {
  const { connect } = useConnect();
  const { sdk } = usePhantom();
  const { isInstalled, isLoading } = useIsExtensionInstalled();

  const switchToExtension = async () => {
    if (!isInstalled) {
      alert("Phantom extension is not installed");
      return;
    }

    // Switch to injected provider and connect
    await sdk.switchProvider("injected");
    const { addresses } = await connect();
    console.log("Connected to extension:", addresses);
  };

  if (isLoading) {
    return <div>Checking for Phantom extension...</div>;
  }

  return (
    <button onClick={switchToExtension} disabled={!isInstalled}>
      {isInstalled ? "Switch to Extension" : "Extension Not Installed"}
    </button>
  );
}
Future API Changes: This interface will change in future versions. The connect() method will receive a parameter with the provider type, eliminating the need for switchProvider().
Important notes about redirectUrl (for embedded provider):
  • Must be an existing page/route in your application
  • Must be whitelisted in your Phantom Portal app configuration
  • This is where users will be redirected after completing OAuth with Google
I