import { useDynamicContext, getNetwork } from "@dynamic-labs/sdk-react-core";
import { isEthereumWallet } from "@dynamic-labs/ethereum";
import { parseUnits, erc20Abi } from 'viem';
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
const PaymentPage = () => {
const [searchParams] = useSearchParams();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const { primaryWallet, user } = useDynamicContext();
// Extract parameters from URL
const recipientAddress = searchParams.get("recipient");
const amount = searchParams.get("amount");
const token = searchParams.get("token") || "USDC";
const network = searchParams.get("network") || "1";
const handlePayment = async () => {
if (!recipientAddress || !amount) {
setError("Invalid payment link parameters");
return;
}
// Check if user is authenticated
if (!user) {
setError("Please log in to complete this payment");
return;
}
if (!primaryWallet || !isEthereumWallet(primaryWallet)) {
setError("Wallet not connected or not EVM compatible");
return;
}
// Check if wallet is on the correct network for USDC
const expectedChainId = parseInt(network); // From URL params
const currentChainId = await getNetwork(primaryWallet.connector);
if (currentChainId !== expectedChainId) {
// Try to switch to the correct network
if (primaryWallet.connector.supportsNetworkSwitching()) {
try {
setError(`Switching to ${getNetworkName(expectedChainId)}...`);
await primaryWallet.switchNetwork(expectedChainId);
// Verify the switch was successful
const newChainId = await getNetwork(primaryWallet.connector);
if (newChainId !== expectedChainId) {
setError(`Failed to switch to ${getNetworkName(expectedChainId)}. Please switch manually.`);
return;
}
} catch (switchError: any) {
setError(`Failed to switch network: ${switchError.message}. Please switch to ${getNetworkName(expectedChainId)} manually.`);
return;
}
} else {
setError(`Please switch to ${getNetworkName(expectedChainId)}. Your wallet doesn't support automatic network switching.`);
return;
}
}
setIsLoading(true);
setError(null);
try {
const walletClient = await primaryWallet.getWalletClient();
// Get USDC contract address for the current network
const usdcAddress = getUSDCAddress(currentChainId);
// Convert amount to USDC units (6 decimals)
const amountInUnits = parseUnits(amount, 6);
// Send USDC transfer
const hash = await walletClient.writeContract({
address: usdcAddress as `0x${string}`,
abi: erc20Abi,
functionName: 'transfer',
args: [recipientAddress as `0x${string}`, amountInUnits],
});
setSuccess(true);
console.log("USDC transfer successful:", hash);
} catch (err: any) {
setError(err.message || "Payment failed");
} finally {
setIsLoading(false);
}
};
// Helper function to get USDC contract address for different networks
const getUSDCAddress = (chainId: number): string => {
const usdcAddresses: Record<number, string> = {
1: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // Ethereum mainnet
137: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // Polygon
42161: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", // Arbitrum One
10: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", // Optimism
8453: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base
11155111: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", // Sepolia testnet
};
const address = usdcAddresses[chainId];
if (!address) {
throw new Error(`USDC not supported on network ${chainId}`);
}
return address;
};
// Helper function to get network name
const getNetworkName = (chainId: number): string => {
const networks: Record<number, string> = {
1: "Ethereum Mainnet",
137: "Polygon",
42161: "Arbitrum One",
10: "Optimism",
8453: "Base",
11155111: "Sepolia Testnet",
};
return networks[chainId] || `Network ${chainId}`;
};
if (!recipientAddress || !amount) {
return <div>Invalid payment link</div>;
}
// Show login prompt if user is not authenticated
if (!user) {
return (
<div style={{ padding: '20px', border: '1px solid #ffc107', borderRadius: '8px', backgroundColor: '#fff3cd' }}>
<h2>Authentication Required</h2>
<p>You need to log in to complete this payment.</p>
<p><strong>Amount:</strong> {amount} {token}</p>
<p><strong>Recipient:</strong> {recipientAddress.substring(0, 8)}...{recipientAddress.substring(recipientAddress.length - 6)}</p>
<div style={{ marginTop: '20px' }}>
<p>Please connect your wallet to continue with the payment.</p>
<p style={{ fontSize: '14px', color: '#666' }}>
Once you log in, you'll be able to complete the payment securely.
</p>
</div>
</div>
);
}
if (success) {
return (
<div>
<h2>Payment Successful!</h2>
<p>You have successfully sent {amount} {token} to {recipientAddress.substring(0, 8)}...</p>
</div>
);
}
return (
<div>
<h2>Complete Payment</h2>
<p>Amount: {amount} {token}</p>
<p>Recipient: {recipientAddress.substring(0, 8)}...{recipientAddress.substring(recipientAddress.length - 6)}</p>
{isLoading && <p>Processing payment...</p>}
{error && <p style={{ color: "red" }}>Error: {error}</p>}
<button onClick={handlePayment} disabled={isLoading}>
{isLoading ? "Processing..." : "Pay Now"}
</button>
</div>
);
};