Code Examples

Real-world code examples to help you integrate ExePay into your application.

1. Simple SOL Payment

Send SOL from one wallet to another with transaction confirmation.

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

export function SendSOL() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();

  const sendPayment = async (recipientAddress: string, amount: number) => {
    if (!publicKey) throw new Error('Wallet not connected');

    const transaction = new Transaction().add(
      SystemProgram.transfer({
        fromPubkey: publicKey,
        toPubkey: new PublicKey(recipientAddress),
        lamports: amount * LAMPORTS_PER_SOL,
      })
    );

    const signature = await sendTransaction(transaction, connection);
    await connection.confirmTransaction(signature, 'confirmed');
    
    return signature;
  };

  return (
    <button onClick={() => sendPayment('RECIPIENT_ADDRESS', 0.1)}>
      Send 0.1 SOL
    </button>
  );
}

2. SPL Token Transfer (USDC)

Send USDC or other SPL tokens with automatic ATA creation.

import { useWallet, useConnection } from '@solana/wallet-adapter-react';
import { PublicKey, Transaction } from '@solana/web3.js';
import {
  getAssociatedTokenAddress,
  createAssociatedTokenAccountInstruction,
  createTransferInstruction,
} from '@solana/spl-token';

const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // Mainnet USDC

export function SendUSDC() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();

  const sendUSDC = async (recipientAddress: string, amount: number) => {
    if (!publicKey) throw new Error('Wallet not connected');

    const recipient = new PublicKey(recipientAddress);
    
    // Get token accounts
    const senderATA = await getAssociatedTokenAddress(USDC_MINT, publicKey);
    const recipientATA = await getAssociatedTokenAddress(USDC_MINT, recipient);

    const transaction = new Transaction();

    // Check if recipient ATA exists, if not create it
    const recipientAccount = await connection.getAccountInfo(recipientATA);
    if (!recipientAccount) {
      transaction.add(
        createAssociatedTokenAccountInstruction(
          publicKey,
          recipientATA,
          recipient,
          USDC_MINT
        )
      );
    }

    // Add transfer instruction (USDC has 6 decimals)
    transaction.add(
      createTransferInstruction(
        senderATA,
        recipientATA,
        publicKey,
        amount * 1_000_000 // Convert to smallest unit
      )
    );

    const signature = await sendTransaction(transaction, connection);
    await connection.confirmTransaction(signature, 'confirmed');
    
    return signature;
  };

  return (
    <button onClick={() => sendUSDC('RECIPIENT_ADDRESS', 10)}>
      Send 10 USDC
    </button>
  );
}

3. Batch Payments

Send payments to multiple recipients in a single transaction.

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

interface Recipient {
  address: string;
  amount: number;
}

export function BatchPayment() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();

  const sendBatch = async (recipients: Recipient[]) => {
    if (!publicKey) throw new Error('Wallet not connected');

    const transaction = new Transaction();

    // Add transfer instruction for each recipient
    for (const recipient of recipients) {
      transaction.add(
        SystemProgram.transfer({
          fromPubkey: publicKey,
          toPubkey: new PublicKey(recipient.address),
          lamports: recipient.amount * LAMPORTS_PER_SOL,
        })
      );
    }

    const signature = await sendTransaction(transaction, connection);
    await connection.confirmTransaction(signature, 'confirmed');
    
    return signature;
  };

  const recipients: Recipient[] = [
    { address: 'ADDRESS_1', amount: 0.1 },
    { address: 'ADDRESS_2', amount: 0.2 },
    { address: 'ADDRESS_3', amount: 0.3 },
  ];

  return (
    <button onClick={() => sendBatch(recipients)}>
      Send Batch Payment
    </button>
  );
}

4. Recurring Payments Setup

Create a subscription that automatically executes payments on a schedule.

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

interface Subscription {
  id: string;
  recipient: string;
  amount: number;
  frequency: 'daily' | 'weekly' | 'monthly';
  nextPayment: Date;
  active: boolean;
}

export function RecurringPayment() {
  const { publicKey, sendTransaction } = useWallet();
  const { connection } = useConnection();
  const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);

  const createSubscription = (
    recipient: string,
    amount: number,
    frequency: 'daily' | 'weekly' | 'monthly'
  ) => {
    const subscription: Subscription = {
      id: Date.now().toString(),
      recipient,
      amount,
      frequency,
      nextPayment: getNextPaymentDate(frequency),
      active: true,
    };

    setSubscriptions([...subscriptions, subscription]);
    localStorage.setItem('subscriptions', JSON.stringify([...subscriptions, subscription]));
  };

  const executePayment = async (subscription: Subscription) => {
    if (!publicKey) return;

    const transaction = new Transaction().add(
      SystemProgram.transfer({
        fromPubkey: publicKey,
        toPubkey: new PublicKey(subscription.recipient),
        lamports: subscription.amount * LAMPORTS_PER_SOL,
      })
    );

    const signature = await sendTransaction(transaction, connection);
    await connection.confirmTransaction(signature, 'confirmed');

    // Update next payment date
    const updated = subscriptions.map(sub =>
      sub.id === subscription.id
        ? { ...sub, nextPayment: getNextPaymentDate(sub.frequency) }
        : sub
    );
    setSubscriptions(updated);
    localStorage.setItem('subscriptions', JSON.stringify(updated));

    return signature;
  };

  const getNextPaymentDate = (frequency: string) => {
    const now = new Date();
    switch (frequency) {
      case 'daily':
        return new Date(now.getTime() + 24 * 60 * 60 * 1000);
      case 'weekly':
        return new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
      case 'monthly':
        return new Date(now.setMonth(now.getMonth() + 1));
      default:
        return now;
    }
  };

  // Check for due payments
  useEffect(() => {
    const interval = setInterval(() => {
      subscriptions.forEach(sub => {
        if (sub.active && new Date() >= sub.nextPayment) {
          executePayment(sub);
        }
      });
    }, 60000); // Check every minute

    return () => clearInterval(interval);
  }, [subscriptions]);

  return (
    <div>
      <button
        onClick={() => createSubscription('RECIPIENT_ADDRESS', 0.1, 'monthly')}
      >
        Subscribe (0.1 SOL/month)
      </button>

      <div>
        {subscriptions.map(sub => (
          <div key={sub.id}>
            <p>To: {sub.recipient}</p>
            <p>Amount: {sub.amount} SOL</p>
            <p>Frequency: {sub.frequency}</p>
            <p>Next: {sub.nextPayment.toLocaleDateString()}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

5. Fetch Transaction History

Display a user's transaction history with details.

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

interface Transaction {
  signature: string;
  timestamp: number;
  amount: number;
  type: 'sent' | 'received';
  counterparty: string;
}

export function TransactionHistory() {
  const { publicKey } = useWallet();
  const { connection } = useConnection();
  const [transactions, setTransactions] = useState<Transaction[]>([]);
  const [loading, setLoading] = useState(false);

  const fetchHistory = async () => {
    if (!publicKey) return;
    
    setLoading(true);
    try {
      const signatures = await connection.getSignaturesForAddress(publicKey, { limit: 10 });
      const txs: Transaction[] = [];

      for (const sig of signatures) {
        const tx = await connection.getParsedTransaction(sig.signature);
        if (!tx) continue;

        const instruction = tx.transaction.message.instructions[0];
        if ('parsed' in instruction && instruction.parsed.type === 'transfer') {
          const info = instruction.parsed.info;
          const isSent = info.source === publicKey.toBase58();

          txs.push({
            signature: sig.signature,
            timestamp: tx.blockTime || 0,
            amount: info.lamports / LAMPORTS_PER_SOL,
            type: isSent ? 'sent' : 'received',
            counterparty: isSent ? info.destination : info.source,
          });
        }
      }

      setTransactions(txs);
    } catch (error) {
      console.error('Failed to fetch history:', error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchHistory();
  }, [publicKey]);

  return (
    <div>
      <h2>Transaction History</h2>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <div>
          {transactions.map(tx => (
            <div key={tx.signature}>
              <p>
                {tx.type === 'sent' ? '↗️ Sent' : '↙️ Received'} {tx.amount} SOL
              </p>
              <p>
                {tx.type === 'sent' ? 'To' : 'From'}: {tx.counterparty.slice(0, 8)}...
              </p>
              <p>{new Date(tx.timestamp * 1000).toLocaleString()}</p>
              <a
                href={`https://solscan.io/tx/${tx.signature}`}
                target="_blank"
                rel="noopener noreferrer"
              >
                View on Solscan
              </a>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

More Examples

Check out our GitHub repository for more examples, including:

  • Payment links and QR codes
  • Multi-token support
  • Error handling and retries
  • Mobile wallet integration