diff --git a/.env.example b/.env.example index dde6480..bfbe710 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,7 @@ # Client-side environment variables (must be prefixed with NEXT_PUBLIC_) # Solana Payment Configuration +# TODO: Use different RPC URL or use browser wallet NEXT_PUBLIC_SOLANA_RPC_URL=https://skilled-prettiest-seed.solana-mainnet.quiknode.pro/eeecfebd04e345f69f1900cc3483cbbfea02a158 NEXT_PUBLIC_GORBAGANA_RPC_URL=https://rpc.gorbagana.wtf NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS=71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFELvg diff --git a/src/app/api/registry/route.ts b/src/app/api/registry/route.ts index fae5397..e577ad4 100644 --- a/src/app/api/registry/route.ts +++ b/src/app/api/registry/route.ts @@ -10,9 +10,9 @@ import { DENOM as ALNT_DENOM } from '@cerc-io/registry-sdk'; import { verifyUnusedSolanaPayment } from '@/utils/solana-verify'; import { transferLNTTokens } from '@/services/laconic-transfer'; import { getRegistry, getRegistryConfig } from '@/config'; -import { getRequiredNativeGorInfo, getRequiredTokenInfo } from '@/services/jupiter-price'; -import { PaymentMethod } from '@/constants/payments'; -import { getRecipientAddress } from '@/services/solana'; +import { getRequiredTokenInfo } from '@/services/jupiter-price'; +import { WRAPPED_SOL_MINT_ADDRESS } from '@/constants/payments'; +import { PaymentMethod } from '@/types'; assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required'); assert(process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL, 'GORBAGANA_RPC_URL is required'); @@ -141,7 +141,7 @@ export const registryTransactionWithRetry = async ( // Helper function to get the appropriate connection based on payment method const getConnection = (paymentMethod: PaymentMethod): Connection => { - if (paymentMethod === 'nat-gor' && GORBAGANA_RPC_URL) { + if (paymentMethod === PaymentMethod.NAT_GOR && GORBAGANA_RPC_URL) { return new Connection(GORBAGANA_RPC_URL); } return new Connection(SOLANA_RPC_URL); @@ -185,7 +185,7 @@ export async function POST(request: NextRequest) { } // Validate payment method - if (paymentMethod !== 'nat-gor' && paymentMethod !== 'spl-token') { + if (paymentMethod !== PaymentMethod.NAT_GOR && paymentMethod !== PaymentMethod.SPL_TOKEN) { return NextResponse.json({ status: 'error', message: 'Invalid payment method. Must be "nat-gor" or "spl-token".' @@ -205,21 +205,18 @@ export async function POST(request: NextRequest) { // Calculate expected token amount based on current price - let expectedRecipientAddress: string; let requiredAmountInBaseUnits: number; const targetUsdAmount = parseFloat(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD!); + const mintAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS!; try { - if (paymentMethod === 'nat-gor') { - const requiredNativeGorInfo = await getRequiredNativeGorInfo(targetUsdAmount); + if (paymentMethod === PaymentMethod.NAT_GOR) { + const requiredNativeGorInfo = await getRequiredTokenInfo(targetUsdAmount, WRAPPED_SOL_MINT_ADDRESS); requiredAmountInBaseUnits = requiredNativeGorInfo.requiredAmountInBaseUnits; - expectedRecipientAddress = getRecipientAddress('nat-gor'); - } else if (paymentMethod === 'spl-token') { - const mintAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS!; + } else if (paymentMethod === PaymentMethod.SPL_TOKEN) { const requiredTokenInfo = await getRequiredTokenInfo(targetUsdAmount, mintAddress); requiredAmountInBaseUnits = requiredTokenInfo.requiredAmountInBaseUnits; - expectedRecipientAddress = getRecipientAddress('spl-token'); } else { return NextResponse.json({ status: 'error', @@ -241,7 +238,6 @@ export async function POST(request: NextRequest) { txHash, new BN(expectedTokenAmount), paymentMethod, - expectedRecipientAddress ); if (!solanaPaymentResult.valid) { diff --git a/src/app/page.tsx b/src/app/page.tsx index 26ea6da..9d4c7a4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState, useRef } from 'react'; import dynamic from 'next/dynamic'; import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'; @@ -10,8 +10,9 @@ import { BackpackWalletName } from '@solana/wallet-adapter-backpack'; import URLForm from '@/components/URLForm'; import StatusDisplay from '@/components/StatusDisplay'; import { createApplicationDeploymentRequest } from '@/services/registry'; -import { PaymentMethod, PAYMENT_METHOD_LABELS } from '@/constants/payments'; +import { PAYMENT_METHOD_LABELS } from '@/constants/payments'; import { usePaymentMethod } from '@/contexts/PaymentMethodContext'; +import { PaymentMethod } from '@/types'; // Dynamically import components to avoid SSR issues with browser APIs const PaymentModal = dynamic(() => import('@/components/PaymentModal'), { ssr: false }); @@ -51,13 +52,24 @@ export default function Home() { warnOnIncorrectChain(); }, [wallet]); + // Track previous payment method to detect switches + const previousPaymentMethodRef = useRef(null); + useEffect(() => { if (selectedPaymentMethod === null) { return; } - disconnect(); - }, [selectedPaymentMethod, disconnect]); + // Only disconnect if switching between different payment methods while connected + if (previousPaymentMethodRef.current !== null && + previousPaymentMethodRef.current !== selectedPaymentMethod && + connected) { + console.log("DISCONNECT TRIGGERED - Payment method switched while connected") + disconnect(); + } + + previousPaymentMethodRef.current = selectedPaymentMethod; + }, [selectedPaymentMethod, connected, disconnect]); const handleUrlSubmit = (submittedUrl: string) => { setUrl(submittedUrl); @@ -71,7 +83,7 @@ export default function Home() { const walletName = wallet.adapter.name.toLowerCase(); const isBackpack = walletName.includes('backpack'); - if (selectedPaymentMethod === 'nat-gor') { + if (selectedPaymentMethod === PaymentMethod.NAT_GOR) { return isBackpack; // Only Backpack for native GOR } else { return !isBackpack; // Only non-Backpack wallets for SPL tokens @@ -140,13 +152,13 @@ export default function Home() {