SWIG provides account abstraction on Solana, enabling seamless embedded wallet experiences. This guide walks you through integrating SWIG with Para for embedded wallet creation.

Prerequisites

Before starting this integration:
  • Set up a Para account on their developer portal
  • Generate an API Key
  • Enable Solana as a supported network
  • Basic understanding of React, TypeScript, and Solana

Installation

Install the required dependencies for SWIG integration:
yarn add @getpara/react-sdk @tanstack/react-query @getpara/solana-web3.js-v1-integration @solana/web3.js @swig-wallet/classic @swig-wallet/coder
Install Vite polyfills for development:
yarn add vite-plugin-node-polyfills -D

Setup

Vite Configuration

Update your vite.config.ts for Solana compatibility:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import path from "path";

export default defineConfig({
  plugins: [react(), nodePolyfills()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Environment Variables

Create a .env.local file in your project root:
VITE_PARA_API_KEY=your_para_api_key

Para Provider Setup

Create providers.tsx in your src directory:
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";

const queryClient = new QueryClient();

interface ProvidersProps {
  children: React.ReactNode;
}

export function Providers({ children }: ProvidersProps) {
  return (
    <QueryClientProvider client={queryClient}>
      <ParaProvider
        paraClientConfig={{
          apiKey: import.meta.env.VITE_PARA_API_KEY || "",
        }}
      >
        {children}
      </ParaProvider>
    </QueryClientProvider>
  );
}

Authentication

Create a login button component with Para modal integration:
import React from "react";
import { ParaModal, useModal, OAuthMethod, useAccount, useLogout } from "@getpara/react-sdk";

export const LoginButton: React.FC = () => {
  const { openModal } = useModal();
  const { data: account } = useAccount();
  const { logoutAsync } = useLogout();

  const handleClick = () => {
    if (account?.isConnected) {
      logoutAsync();
    } else {
      openModal();
    }
  };

  return (
    <>
      <button
        onClick={handleClick}
        className={`w-full px-4 py-2 rounded-md ${
          account?.isConnected
            ? "bg-gray-200 text-gray-700 hover:bg-gray-300"
            : "bg-blue-600 text-white hover:bg-blue-700"
        }`}
      >
        {account?.isConnected ? "Sign out" : "Sign in with Para"}
      </button>

      <ParaModal
        appName="SWIG Para Example"
        logo="https://onswig.com/raccoon-logo.svg"
        oAuthMethods={[OAuthMethod.GOOGLE, OAuthMethod.TWITTER, OAuthMethod.DISCORD]}
      />
    </>
  );
};

SWIG Account Creation

Create a SWIG account using Para’s Solana Web3.js integration:
import React, { useState, useEffect } from "react";
import { Connection, PublicKey, Transaction, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { useAccount, useWallet, useClient } from "@getpara/react-sdk";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3.js-v1-integration";
import { Actions, Swig, findSwigPda, createEd25519AuthorityInfo } from "@swig-wallet/classic";

export const SwigAccountCreation: React.FC = () => {
  const { data: account } = useAccount();
  const { data: wallet } = useWallet();
  const [swigAddress, setSwigAddress] = useState<string | null>(null);
  const [solBalance, setSolBalance] = useState<number | null>(null);
  const [isCreatingSwig, setIsCreatingSwig] = useState(false);

  const para = useClient();
  const connection = new Connection("https://api.devnet.solana.com");

  const createSwigAccount = async () => {
    if (!wallet?.address || !para) return;
    setIsCreatingSwig(true);

    try {
      const id = new Uint8Array(32);
      crypto.getRandomValues(id);

      const paraPubkey = new PublicKey(wallet.address);
      const [swigPdaAddress] = findSwigPda(id);

      const signer = new ParaSolanaWeb3Signer(para, connection, wallet.id);

      const rootAuthorityInfo = createEd25519AuthorityInfo(paraPubkey);

      const rootActions = Actions.set().all().get();

      const createSwigInstruction = Swig.create({
        authorityInfo: rootAuthorityInfo,
        id,
        payer: paraPubkey,
        actions: rootActions,
      });

      const transaction = new Transaction();
      transaction.add(createSwigInstruction);
      transaction.feePayer = paraPubkey;

      const { blockhash } = await connection.getLatestBlockhash();
      transaction.recentBlockhash = blockhash;

      const signedTransaction = await signer.signTransaction(transaction);

      const signature = await connection.sendRawTransaction(signedTransaction.serialize());

      await connection.confirmTransaction({
        signature,
        blockhash,
        lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,
      });

      setSwigAddress(swigPdaAddress.toBase58());
      setIsCreatingSwig(false);

      console.log("Swig account created successfully!");
      console.log("Swig address:", swigPdaAddress.toBase58());
      console.log("Transaction signature:", signature);
    } catch (error) {
      console.error("Error in transaction signing:", error);
      setIsCreatingSwig(false);
    }
  };

  useEffect(() => {
    const fetchBalance = async () => {
      if (wallet?.address) {
        try {
          const balance = await connection.getBalance(new PublicKey(wallet.address));
          setSolBalance(balance / LAMPORTS_PER_SOL);
        } catch (e) {
          setSolBalance(null);
        }
      }
    };
    fetchBalance();
  }, [wallet?.address]);

  if (!account?.isConnected || !wallet) {
    return <div>Please connect your wallet first</div>;
  }

  return (
    <div className="space-y-4">
      <div className="text-center">
        <p className="text-green-700 font-medium">You are signed in!</p>
        <p className="text-sm text-gray-700">
          Wallet address: <span className="font-mono break-all">{wallet.address}</span>
        </p>
        {solBalance !== null && (
          <p className="text-sm text-gray-700">
            Balance: <span className="font-mono">{solBalance} SOL</span>
          </p>
        )}
      </div>

      {swigAddress && (
        <div className="text-center p-4 bg-green-50 rounded-md">
          <p className="text-green-800 font-medium">Swig Account Created!</p>
          <p className="text-sm text-green-700 break-all">
            Address: {swigAddress}
          </p>
        </div>
      )}

      {!swigAddress && (
        <button
          onClick={createSwigAccount}
          disabled={isCreatingSwig}
          className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:bg-blue-400"
        >
          {isCreatingSwig ? "Creating Swig..." : "Create Swig Account"}
        </button>
      )}
    </div>
  );
};

Complete Application

Here’s the complete App component that brings everything together:
import React from "react";
import { Providers } from "./providers";
import { LoginButton } from "./LoginButton";
import { SwigAccountCreation } from "./SwigAccountCreation";

export default function App() {
  return (
    <Providers>
      <div className="min-h-screen flex justify-center p-4">
        <div className="max-w-md w-full space-y-6 p-8">
          <div className="text-center">
            <h2 className="text-3xl font-extrabold text-gray-900">
              SWIG + Para Integration
            </h2>
            <p className="mt-2 text-sm text-gray-600">
              Using Para's Solana Web3.js integration for SWIG account creation
            </p>
          </div>
          
          <SwigAccountCreation />
          <LoginButton />
        </div>
      </div>
    </Providers>
  );
}

Key Implementation Details

SWIG Account Creation Process

The createSwigAccount function performs these critical steps:
  1. Generate Random ID: Creates a unique 32-byte identifier for the SWIG account
  2. Create Para Signer: Initializes ParaSolanaWeb3Signer with Para client and wallet
  3. Set Authority: Establishes the Para-generated wallet as root authority
  4. Configure Actions: Grants full permissions using Actions.set().all().get()
  5. Build Transaction: Creates and configures the Solana transaction
  6. Sign & Send: Uses Para’s signer to sign and broadcast the transaction

Important Notes

  • Devnet SOL Required: You need devnet SOL in your Para-generated wallet before creating a SWIG account
  • Root Authority: The Para-generated wallet becomes the root authority for the SWIG account
  • Error Handling: The implementation includes proper error handling and loading states
  • Balance Display: Shows wallet SOL balance and SWIG address after creation

Testing Your Integration

  1. Start your development server:
yarn dev
  1. Open your browser to the displayed URL
  2. Click “Sign in with Para” to authenticate
  3. Send devnet SOL to your wallet address
  4. Click “Create Swig Account” to create your SWIG account

Best Practices

  • Never commit API keys to version control
  • Use environment variables for sensitive configuration
  • Test thoroughly on Solana devnet before mainnet
  • Implement proper error handling throughout the flow
  • Store SWIG account information securely

Resources

Next Steps

Now that you have SWIG working with Para, you can:
  • Implement additional SWIG functionality (transfers, token management)
  • Customize the Para modal appearance and OAuth providers
  • Add more complex transaction flows
  • Implement additional security features like multi-signature support
  • Integrate with other Solana protocols and applications