From 32b583a6371dd679ee9ada4269ddaef6c57cdf24 Mon Sep 17 00:00:00 2001 From: Shreerang Kale Date: Thu, 24 Jul 2025 18:41:33 +0530 Subject: [PATCH] Refactor paymentModal code --- .env.example | 8 ++++-- src/app/api/registry/route.ts | 4 +-- src/app/page.tsx | 14 ++++----- src/components/PaymentModal.tsx | 26 ++++++----------- src/constants/payments.ts | 7 ++--- src/types/index.ts | 1 - src/utils/solana-verify.ts | 50 ++++++++++++++++----------------- 7 files changed, 50 insertions(+), 60 deletions(-) diff --git a/.env.example b/.env.example index af6cdaa..fb8fd7a 100644 --- a/.env.example +++ b/.env.example @@ -3,13 +3,15 @@ # 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 NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR -NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD=5 # Payment amount in USD +NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD=5 + +# Gorbagana Chain Configuration +NEXT_PUBLIC_GORBAGANA_RPC_URL=https://rpc.gorbagana.wtf NEXT_PUBLIC_ENABLE_NATIVE_GOR_TRANSFER=true -# Multisig address +# Multisig Address NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY # UI Configuration diff --git a/src/app/api/registry/route.ts b/src/app/api/registry/route.ts index e577ad4..96a3a26 100644 --- a/src/app/api/registry/route.ts +++ b/src/app/api/registry/route.ts @@ -11,11 +11,11 @@ import { verifyUnusedSolanaPayment } from '@/utils/solana-verify'; import { transferLNTTokens } from '@/services/laconic-transfer'; import { getRegistry, getRegistryConfig } from '@/config'; import { getRequiredTokenInfo } from '@/services/jupiter-price'; -import { WRAPPED_SOL_MINT_ADDRESS } from '@/constants/payments'; +import { IS_NAT_GOR_TRANSFER_ENABLED, 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'); +assert(!IS_NAT_GOR_TRANSFER_ENABLED || process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL, 'GORBAGANA_RPC_URL is required when NAT GOR transfer is enabled'); const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL; const GORBAGANA_RPC_URL = process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL; diff --git a/src/app/page.tsx b/src/app/page.tsx index d0bd60b..fc84e1f 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -10,7 +10,7 @@ import { BackpackWalletName } from '@solana/wallet-adapter-backpack'; import URLForm from '@/components/URLForm'; import StatusDisplay from '@/components/StatusDisplay'; import { createApplicationDeploymentRequest } from '@/services/registry'; -import { PAYMENT_METHOD_LABELS } from '@/constants/payments'; +import { IS_NAT_GOR_TRANSFER_ENABLED, PAYMENT_METHOD_LABELS } from '@/constants/payments'; import { usePaymentMethod } from '@/contexts/PaymentMethodContext'; import { PaymentMethod } from '@/types'; @@ -36,16 +36,14 @@ export default function Home() { const [error, setError] = useState(null); const [incorrectChainWarining, setIncorrectChainWarining] = useState(null); - const isNatGorEnabled = process.env.NEXT_PUBLIC_ENABLE_NATIVE_GOR_TRANSFER === "true"; - useEffect(() => { - if (!isNatGorEnabled) { + if (!IS_NAT_GOR_TRANSFER_ENABLED) { setSelectedPaymentMethod(PaymentMethod.SPL_TOKEN); } - }, [isNatGorEnabled, setSelectedPaymentMethod]); + }, [setSelectedPaymentMethod]); useEffect(() => { - if (!wallet || wallet.adapter.name !== BackpackWalletName) { + if (!wallet || wallet.adapter.name !== BackpackWalletName || selectedPaymentMethod !== PaymentMethod.NAT_GOR) { return; } @@ -58,7 +56,7 @@ export default function Home() { } warnOnIncorrectChain(); - }, [wallet]); + }, [wallet, selectedPaymentMethod]); // Track previous payment method to detect switches const previousPaymentMethodRef = useRef(null); @@ -151,7 +149,7 @@ export default function Home() { {/* Step 1: Payment Method Selection */} - { isNatGorEnabled && + { IS_NAT_GOR_TRANSFER_ENABLED &&

Choose Payment Method diff --git a/src/components/PaymentModal.tsx b/src/components/PaymentModal.tsx index 81754ba..d836503 100644 --- a/src/components/PaymentModal.tsx +++ b/src/components/PaymentModal.tsx @@ -1,18 +1,18 @@ 'use client'; -import { useCallback, useMemo, useState, useEffect } from 'react'; +import { useCallback, useState, useEffect } from 'react'; import assert from 'assert'; import { Connection, LAMPORTS_PER_SOL } from '@solana/web3.js'; import { useConnection, useWallet } from '@solana/wallet-adapter-react'; -import { sendSolanaPayment, getRecipientAddress } from '@/services/solana'; +import { sendSolanaPayment } from '@/services/solana'; import { getRequiredTokenInfo, RequiredTokenInfo } from '@/services/jupiter-price'; import { PaymentMethod, PaymentModalProps, PaymentRequest } from '@/types'; -import { PAYMENT_METHOD_LABELS, WRAPPED_SOL_MINT_ADDRESS } from '@/constants/payments'; +import { IS_NAT_GOR_TRANSFER_ENABLED, PAYMENT_METHOD_LABELS, WRAPPED_SOL_MINT_ADDRESS } from '@/constants/payments'; import { usePaymentMethod } from '@/contexts/PaymentMethodContext'; -assert(process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL, 'GORBAGANA_RPC_URL is required'); +assert(!IS_NAT_GOR_TRANSFER_ENABLED || process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL, 'GORBAGANA_RPC_URL is required when NAT GOR transfer is enabled'); const GORBAGANA_RPC_URL = process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL; @@ -24,7 +24,7 @@ export default function PaymentModal({ }: PaymentModalProps) { const { selectedPaymentMethod: paymentMethod } = usePaymentMethod(); - const { connection } = useConnection(); + const { connection: solanaConnection } = useConnection(); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); @@ -34,17 +34,10 @@ export default function PaymentModal({ const { wallet, publicKey } = useWallet(); - const solanaConnection = connection; - - const gorbaganaConnection = useMemo(() => - GORBAGANA_RPC_URL ? new Connection(GORBAGANA_RPC_URL) : solanaConnection, - [solanaConnection] - ); - // Get configuration from environment variables const targetUsdAmount = parseFloat(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD!); const mintAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS!; - const tokenSymbol = process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL || 'TOKEN'; + const tokenSymbol = process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL; // Fetch payment amount based on USD price for both payment methods useEffect(() => { @@ -113,11 +106,10 @@ export default function PaymentModal({ const paymentRequest: PaymentRequest = { paymentMethod: paymentMethod, amount: tokenAmount, - recipientAddress: getRecipientAddress(paymentMethod) }; // Use different RPC connection based on payment method - const connectionToUse = paymentMethod === PaymentMethod.NAT_GOR ? gorbaganaConnection : solanaConnection; + const connectionToUse = paymentMethod === PaymentMethod.NAT_GOR ? new Connection(GORBAGANA_RPC_URL!) : solanaConnection; const result = await sendSolanaPayment( wallet.adapter, @@ -136,7 +128,7 @@ export default function PaymentModal({ } finally { setLoading(false); } - }, [paymentMethod, tokenAmount, loadingPrice, wallet, solanaConnection, gorbaganaConnection, publicKey, onPaymentComplete]); + }, [paymentMethod, tokenAmount, loadingPrice, wallet, solanaConnection, publicKey, onPaymentComplete]); const getPaymentAmountDisplay = () => { if (loadingPrice) return 'Loading...'; @@ -187,7 +179,7 @@ export default function PaymentModal({

Recipient Address:

- {getRecipientAddress(paymentMethod)} + {process.env.NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS}
diff --git a/src/constants/payments.ts b/src/constants/payments.ts index b3d4330..a701ee4 100644 --- a/src/constants/payments.ts +++ b/src/constants/payments.ts @@ -3,10 +3,9 @@ import { PaymentMethod } from "@/types"; // Payment method labels for UI export const PAYMENT_METHOD_LABELS: Record = { [PaymentMethod.NAT_GOR]: 'GOR (native)', - [PaymentMethod.SPL_TOKEN]: process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL || 'SPL Token' + [PaymentMethod.SPL_TOKEN]: process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL! }; -// Default payment method (none selected initially) -export const DEFAULT_PAYMENT_METHOD: PaymentMethod | null = null; - export const WRAPPED_SOL_MINT_ADDRESS = 'So11111111111111111111111111111111111111112'; + +export const IS_NAT_GOR_TRANSFER_ENABLED = process.env.NEXT_PUBLIC_ENABLE_NATIVE_GOR_TRANSFER === "true"; diff --git a/src/types/index.ts b/src/types/index.ts index b5ae3b5..86203f5 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -46,7 +46,6 @@ export interface PaymentModalProps { export interface PaymentRequest { paymentMethod: PaymentMethod; amount: number; // in base units (lamports for native GOR, token base units for SPL) - recipientAddress: string; } export interface LaconicTransferResult { diff --git a/src/utils/solana-verify.ts b/src/utils/solana-verify.ts index f53eaf5..0e627dd 100644 --- a/src/utils/solana-verify.ts +++ b/src/utils/solana-verify.ts @@ -35,31 +35,31 @@ const extractTxInfo = async ( return { authority: source, amount: lamports.toString(), destination }; case PaymentMethod.SPL_TOKEN: - // Look for token transfer instruction using TOKEN_PROGRAM_ID - transferInstruction = result.transaction.message.instructions.find( - (instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID) - ); + // Look for token transfer instruction using TOKEN_PROGRAM_ID + transferInstruction = result.transaction.message.instructions.find( + (instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID) + ); - if (!transferInstruction || !('parsed' in transferInstruction)) { - throw new Error('SPL token transfer instruction not found'); - } + if (!transferInstruction || !('parsed' in transferInstruction)) { + throw new Error('SPL token transfer instruction not found'); + } - const parsed = transferInstruction.parsed; + const parsed = transferInstruction.parsed; - // Handle both transferChecked and transfer types - if (parsed.type === 'transferChecked') { - const { info: { tokenAmount, authority, destination } } = parsed; - return { - authority, - amount: tokenAmount.amount, - destination - }; - } else if (parsed.type === 'transfer') { - const { info: { amount, authority, destination } } = parsed; - return { authority, amount, destination }; - } + // Handle both transferChecked and transfer types + if (parsed.type === 'transferChecked') { + const { info: { tokenAmount, authority, destination } } = parsed; + return { + authority, + amount: tokenAmount.amount, + destination + }; + } else if (parsed.type === 'transfer') { + const { info: { amount, authority, destination } } = parsed; + return { authority, amount, destination }; + } - throw new Error('Unsupported token transfer type'); + throw new Error('Unsupported token transfer type'); default: throw new Error('Invalid payment method'); @@ -119,10 +119,10 @@ export const verifyUnusedSolanaPayment = async ( } // Extract transaction info based on payment method - const transferInfo = await extractTxInfo(connection, transactionSignature, paymentMethod); - const amount = transferInfo.amount; - const authority = transferInfo.authority; - const destination = transferInfo.destination; + const transferInfo = await extractTxInfo(connection, transactionSignature, paymentMethod); + const amount = transferInfo.amount; + const authority = transferInfo.authority; + const destination = transferInfo.destination; // Verify amount using BN comparison const transactionAmount = new BN(amount);