diff --git a/src/app/page.tsx b/src/app/page.tsx index 400ac2c..755f1f9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,50 +5,31 @@ import WalletHeader from '../components/WalletHeader' import AIServiceCard from '../components/AIServiceCard' import { generateWithFlux, FluxGenerationResult, FLUX_MODELS } from '../services/fluxService' import { processMTMPayment } from '../services/paymentService' - -interface WalletState { - connected: boolean - publicKey: string | null -} - -declare global { - interface Window { - solflare: any; // Or use a more specific type if available - } -} +import { connectWallet, WalletState } from '../services/walletService' +import { WalletType } from '../services/types' const Page: React.FC = (): React.ReactElement => { const [walletState, setWalletState] = useState({ connected: false, publicKey: null, + type: null }) - const connectWallet = async (): Promise => { + const handleConnect = async (walletType: WalletType): Promise => { try { - if (typeof window === 'undefined' || !window.solflare) { - throw new Error('Solflare wallet not found! Please install it first.') - } - - await window.solflare.connect() - - if (!window.solflare.publicKey) { - throw new Error('Failed to connect to wallet') - } - - const publicKey: string = window.solflare.publicKey.toString() - setWalletState({ - connected: true, - publicKey, - }) + const newWalletState = await connectWallet(walletType) + setWalletState(newWalletState) } catch (error) { console.error('Wallet connection error:', error) setWalletState({ connected: false, publicKey: null, + type: null }) } } + const handleFluxGeneration = (modelId: string, cost: number) => { return async (prompt: string): Promise => { if (!walletState.connected || !walletState.publicKey || !window.solflare) { @@ -59,7 +40,7 @@ const Page: React.FC = (): React.ReactElement => { const paymentResult = await processMTMPayment( walletState.publicKey, cost, - window.solflare + walletState.type ) if (!paymentResult.success) { @@ -84,10 +65,9 @@ const Page: React.FC = (): React.ReactElement => {

+ walletState={walletState} + onConnect={handleConnect} + /> {/* Flux Models Grid */} diff --git a/src/components/WalletHeader.tsx b/src/components/WalletHeader.tsx index 553fb7d..81954c1 100644 --- a/src/components/WalletHeader.tsx +++ b/src/components/WalletHeader.tsx @@ -1,30 +1,35 @@ 'use client' import React from 'react' +import { WalletState, SUPPORTED_WALLETS } from '../services/walletService' interface WalletHeaderProps { - isConnected: boolean - publicKey: string | null - onConnect: () => Promise + walletState: WalletState + onConnect: (walletType: string) => Promise } -const WalletHeader: React.FC = ({ isConnected, publicKey, onConnect }) => { +const WalletHeader: React.FC = ({ walletState, onConnect }) => { return ( -
- {!isConnected ? ( - +
+ {!walletState.connected ? ( +
+ {SUPPORTED_WALLETS.map((wallet) => ( + + ))} +
) : (
- Connected Wallet - - {publicKey?.slice(0, 22)}... + Connected Wallet + + {walletState.publicKey?.slice(0, 22)}...
)} diff --git a/src/services/paymentService.ts b/src/services/paymentService.ts index 7a3e6e0..a6a1459 100644 --- a/src/services/paymentService.ts +++ b/src/services/paymentService.ts @@ -6,22 +6,20 @@ import { createAssociatedTokenAccountInstruction, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token' +import { WalletType } from './types' -// Constants +// Constants remain the same const MTM_TOKEN_MINT: string = '97RggLo3zV5kFGYW4yoQTxr4Xkz4Vg2WPHzNYXXWpump' const PAYMENT_RECEIVER_ADDRESS: string = 'FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY' - -// RPC Configuration const SOLANA_RPC_URL: string = 'https://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4' const SOLANA_WEBSOCKET_URL: string = 'wss://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4' -// Initialize connection with WebSocket support const connection = new Connection( SOLANA_RPC_URL, { commitment: 'confirmed', wsEndpoint: SOLANA_WEBSOCKET_URL, - confirmTransactionInitialTimeout: 60000, // 60 seconds + confirmTransactionInitialTimeout: 60000, } ) @@ -47,9 +45,14 @@ async function findAssociatedTokenAddress( export async function processMTMPayment( walletPublicKey: string, tokenAmount: number, - solflareWallet: any + walletType: WalletType ): Promise { try { + const wallet = window[walletType === 'phantom' ? 'phantom.solana' : 'solflare'] + if (!wallet) { + throw new Error(`${walletType} wallet not found`) + } + const senderPublicKey = new PublicKey(walletPublicKey) const mintPublicKey = new PublicKey(MTM_TOKEN_MINT) const receiverPublicKey = new PublicKey(PAYMENT_RECEIVER_ADDRESS) @@ -89,10 +92,10 @@ export async function processMTMPayment( console.log('Creating receiver token account') transaction.add( createAssociatedTokenAccountInstruction( - senderPublicKey, // payer - receiverATA, // ata - receiverPublicKey, // owner - mintPublicKey // mint + senderPublicKey, + receiverATA, + receiverPublicKey, + mintPublicKey ) ) } @@ -101,10 +104,10 @@ export async function processMTMPayment( console.log('Creating sender token account') transaction.add( createAssociatedTokenAccountInstruction( - senderPublicKey, // payer - senderATA, // ata - senderPublicKey, // owner - mintPublicKey // mint + senderPublicKey, + senderATA, + senderPublicKey, + mintPublicKey ) ) } @@ -112,10 +115,10 @@ export async function processMTMPayment( // Add transfer instruction transaction.add( createTransferInstruction( - senderATA, // from - receiverATA, // to - senderPublicKey, // owner - BigInt(tokenAmount * (10 ** 6)) // amount + senderATA, + receiverATA, + senderPublicKey, + BigInt(tokenAmount * (10 ** 6)) ) ) @@ -124,7 +127,7 @@ export async function processMTMPayment( transaction.feePayer = senderPublicKey console.log('Sending transaction...') - const { signature } = await solflareWallet.signAndSendTransaction(transaction) + const { signature } = await wallet.signAndSendTransaction(transaction) console.log('Transaction sent:', signature) const confirmation = await connection.confirmTransaction({ @@ -147,3 +150,4 @@ export async function processMTMPayment( } } } + diff --git a/src/services/types.ts b/src/services/types.ts new file mode 100644 index 0000000..7b862fe --- /dev/null +++ b/src/services/types.ts @@ -0,0 +1,19 @@ +export type WalletType = 'solflare' | 'phantom' + +declare global { + interface Window { + solflare?: { + connect(): Promise + disconnect(): Promise + publicKey?: { toString(): string } + signAndSendTransaction(transaction: any): Promise<{ signature: string }> + } + phantom?: { + solana?: { + connect(): Promise<{ publicKey: { toString(): string } }> + disconnect(): Promise + signAndSendTransaction(transaction: any): Promise<{ signature: string }> + } + } + } +} diff --git a/src/services/walletService.ts b/src/services/walletService.ts new file mode 100644 index 0000000..e15f298 --- /dev/null +++ b/src/services/walletService.ts @@ -0,0 +1,64 @@ +import { WalletType } from './types' + +export interface WalletState { + connected: boolean + publicKey: string | null + type: WalletType | null +} + +export interface WalletConfig { + type: WalletType + name: string + connect: () => Promise<{ publicKey: string } | null> +} + +const connectSolflare = async (): Promise<{ publicKey: string } | null> => { + if (!window.solflare) return null + await window.solflare.connect() + return window.solflare.publicKey ? { publicKey: window.solflare.publicKey.toString() } : null +} + +const connectPhantom = async (): Promise<{ publicKey: string } | null> => { + if (!window.phantom?.solana) return null + try { + const response = await window.phantom.solana.connect() + return response.publicKey ? { publicKey: response.publicKey.toString() } : null + } catch { + return null + } +} + +export const SUPPORTED_WALLETS: WalletConfig[] = [ + { + type: 'solflare', + name: 'Solflare', + connect: connectSolflare + }, + { + type: 'phantom', + name: 'Phantom', + connect: connectPhantom + } +] + +export async function connectWallet(type: WalletType): Promise { + const wallet = SUPPORTED_WALLETS.find(w => w.type === type) + if (!wallet) throw new Error('Unsupported wallet') + + try { + const result = await wallet.connect() + if (!result) throw new Error(`${wallet.name} not found`) + + return { + connected: true, + publicKey: result.publicKey, + type: wallet.type + } + } catch (error) { + return { + connected: false, + publicKey: null, + type: null + } + } +}