Quick Start

Send your first private payment in under 5 minutes. This guide assumes you've already installed ExePay.

Step 1: Set Up Wallet Provider

Wrap your app with the Solana wallet provider:

// app/layout.tsx or _app.tsx
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets';
import {
  ConnectionProvider,
  WalletProvider,
} from '@solana/wallet-adapter-react';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
import { useMemo } from 'react';

// Import wallet adapter CSS
import '@solana/wallet-adapter-react-ui/styles.css';

export default function App({ children }) {
  const network = WalletAdapterNetwork.Devnet;
  const endpoint = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
  const wallets = useMemo(() => [new PhantomWalletAdapter()], []);

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          {children}
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
}

Step 2: Connect Wallet

Add a wallet connect button to your page:

'use client';

import { useWallet } from '@solana/wallet-adapter-react';
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui';

export default function WalletPage() {
  const { publicKey, connected } = useWallet();

  return (
    <div>
      <WalletMultiButton />
      
      {connected && (
        <p>Connected: {publicKey?.toBase58()}</p>
      )}
    </div>
  );
}

Step 3: Send Your First Payment

Send a public SOL payment:

'use client';

import { useWallet, useConnection } from '@solana/wallet-adapter-react';
import { PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL } from '@solana/web3.js';
import { useState } from 'react';

export default function SendPayment() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();
  const [recipient, setRecipient] = useState('');
  const [amount, setAmount] = useState('');
  const [status, setStatus] = useState('');

  const handleSend = async () => {
    if (!publicKey) return;
    
    try {
      setStatus('Sending...');
      
      const transaction = new Transaction().add(
        SystemProgram.transfer({
          fromPubkey: publicKey,
          toPubkey: new PublicKey(recipient),
          lamports: parseFloat(amount) * LAMPORTS_PER_SOL,
        })
      );

      const signature = await sendTransaction(transaction, connection);
      await connection.confirmTransaction(signature, 'confirmed');
      
      setStatus(`Success! Signature: ${signature}`);
    } catch (error) {
      setStatus(`Error: ${error.message}`);
    }
  };

  return (
    <div>
      <input
        type="text"
        placeholder="Recipient address"
        value={recipient}
        onChange={(e) => setRecipient(e.target.value)}
      />
      <input
        type="number"
        placeholder="Amount (SOL)"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
      />
      <button onClick={handleSend}>Send SOL</button>
      {status && <p>{status}</p>}
    </div>
  );
}

Step 4: Enable Privacy

Switch to a shielded transfer to hide the amount:

import { createShieldedTransfer } from '@exe-pay/core';

// Instead of SystemProgram.transfer, use:
const { transaction, proof } = await createShieldedTransfer({
  sender: publicKey,
  recipient: new PublicKey(recipient),
  amount: parseFloat(amount) * LAMPORTS_PER_SOL,
  connection,
});

const signature = await sendTransaction(transaction, connection);

Production Ready

Shielded and Private transfers are now in PRODUCTION! They use real Groth16 ZK-SNARKs to provide cryptographic privacy. Your transactions are truly private.

Get Devnet SOL

You'll need devnet SOL for testing. Get free devnet SOL from:

Next Steps

You've sent your first payment! Now explore: