Skip to main content

Scaffold

npx create-inco-app@latest my-app --wallet privy --framework anchor --chain svm --yes

Environment Setup

Create a .env.local file in the frontend/ directory:
NEXT_PUBLIC_PRIVY_APP_ID=your-privy-app-id
Get your App ID from the Privy Dashboard. Make sure to enable SVM (Solana) support for your App ID in the Privy dashboard settings.

Provider Setup

Privy for SVM is configured in Solana-only mode with embedded wallet support and external wallet connectors (Phantom, Solflare, etc.):
components/Providers.tsx
"use client";

import { PrivyProvider } from "@privy-io/react-auth";
import { toSolanaWalletConnectors } from "@privy-io/react-auth/solana";
import { createSolanaRpc, createSolanaRpcSubscriptions } from "@solana/kit";
import { ThemeProvider } from "next-themes";

const appId = process.env.NEXT_PUBLIC_PRIVY_APP_ID || "";
const solanaConnectors = toSolanaWalletConnectors();

export const Providers = ({ children }: { children: React.ReactNode }) => {
  if (!appId) {
    console.warn(
      "Missing NEXT_PUBLIC_PRIVY_APP_ID. Get one at https://dashboard.privy.io/"
    );
  }

  return (
    <ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
      <PrivyProvider
        appId={appId}
        config={{
          appearance: {
            theme: "dark",
            showWalletLoginFirst: true,
            walletChainType: "solana-only",
          },
          loginMethods: ["wallet"],
          embeddedWallets: {
            solana: {
              createOnLogin: "users-without-wallets",
            },
          },
          externalWallets: {
            solana: { connectors: solanaConnectors },
          },
          solana: {
            rpcs: {
              "solana:devnet": {
                rpc: createSolanaRpc("https://api.devnet.solana.com"),
                rpcSubscriptions: createSolanaRpcSubscriptions(
                  "wss://api.devnet.solana.com"
                ),
              },
            },
          },
        }}
      >
        {children}
      </PrivyProvider>
    </ThemeProvider>
  );
};

Inco SDK Integration

The hook uses usePrivy and useWallets from Privy to get the Solana wallet, and @inco/solana-sdk for client-side encryption:
hooks/useConfPool.ts
import { usePrivy, useWallets } from "@privy-io/react-auth";
import { PublicKey, SystemProgram, Connection } from "@solana/web3.js";
import * as anchor from "@coral-xyz/anchor";
import { encryptValue } from "@inco/solana-sdk/encryption";
import { hexToBuffer } from "@inco/solana-sdk/utils";

const INCO_LIGHTNING_PROGRAM_ID = new PublicKey(
  "5sjEbPiqgZrYwR31ahR6Uk9wf5awoX61YGg7jExQSwaj"
);

export function useConfPool() {
  const { user } = usePrivy();
  const { wallets } = useWallets();

  // Get Solana wallet — filter out EVM addresses (0x prefix)
  const solanaWallet = wallets.find(
    (w) => w.address && !w.address.startsWith("0x")
  );

  const deposit = async (amount: string) => {
    // 1. Encrypt the deposit amount client-side
    const amountBn = BigInt(Math.floor(parseFloat(amount) * 1e9));
    const encryptedHex = await encryptValue(amountBn);

    // 2. Build the Anchor transaction
    const tx = await program.methods
      .deposit(hexToBuffer(encryptedHex), 0)
      .accounts({
        pool: poolPda,
        participant: participantPda,
        depositor: publicKey,
        systemProgram: SystemProgram.programId,
        incoLightningProgram: INCO_LIGHTNING_PROGRAM_ID,
      })
      .transaction();

    // 3. Sign via Phantom provider and send
    const provider = window?.phantom?.solana;
    const signed = await provider.signTransaction(tx);
    const sig = await connection.sendRawTransaction(signed.serialize());
    await connection.confirmTransaction(sig, "confirmed");
  };
}

Dependencies

PackagePurpose
@privy-io/react-authPrivy authentication and wallet management
@privy-io/react-auth/solanaSolana wallet connectors for Privy
@solana/kitSolana RPC setup
@solana/web3.jsSolana RPC and transactions
@coral-xyz/anchorAnchor program interaction
@inco/solana-sdkClient-side encryption