Add check for phantom wallet before throwing error #1

Merged
nabarun merged 2 commits from ag-phantom-support into main 2025-01-27 09:46:41 +00:00
6 changed files with 38 additions and 28 deletions

6
.env.example Normal file
View File

@ -0,0 +1,6 @@
FAL_AI_KEY=
NEXT_PUBLIC_MTM_TOKEN_MINT=97RggLo3zV5kFGYW4yoQTxr4Xkz4Vg2WPHzNYXXWpump
NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY
NEXT_PUBLIC_SOLANA_RPC_URL=https://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4
NEXT_PUBLIC_SOLANA_WEBSOCKET_URL=wss://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
.next
.env

View File

@ -15,7 +15,7 @@ const Page: React.FC = (): React.ReactElement => {
type: null type: null
}) })
const handleConnect = async (walletType: WalletType): Promise<void> => { const handleConnect = async (walletType: WalletType): Promise<void> => {
try { try {
const newWalletState = await connectWallet(walletType) const newWalletState = await connectWallet(walletType)
setWalletState(newWalletState) setWalletState(newWalletState)
@ -29,11 +29,13 @@ const Page: React.FC = (): React.ReactElement => {
} }
} }
const handleFluxGeneration = (modelId: string, cost: number) => { const handleFluxGeneration = (modelId: string, cost: number) => {
return async (prompt: string): Promise<FluxGenerationResult> => { return async (prompt: string): Promise<FluxGenerationResult> => {
if (!walletState.connected || !walletState.publicKey || !window.solflare) { const type = walletState.type;
return { error: 'Wallet not connected' } if (!walletState.connected || !walletState.publicKey ||
(type === 'phantom' && !window.phantom) ||
(type === 'solflare' && !window.solflare)) {
return { error: 'Wallet not connected' }
} }
// Process payment first // Process payment first
@ -63,7 +65,7 @@ const Page: React.FC = (): React.ReactElement => {
<p className="text-gray-400 text-lg mb-8"> <p className="text-gray-400 text-lg mb-8">
Use MTM to generate memes Use MTM to generate memes
</p> </p>
<WalletHeader <WalletHeader
walletState={walletState} walletState={walletState}
onConnect={handleConnect} onConnect={handleConnect}
@ -82,7 +84,7 @@ const Page: React.FC = (): React.ReactElement => {
onGenerate={handleFluxGeneration(model.modelId, model.cost)} onGenerate={handleFluxGeneration(model.modelId, model.cost)}
/> />
))} ))}
{/* Coming Soon Card */} {/* Coming Soon Card */}
<div className="relative bg-gray-800/50 backdrop-blur-lg rounded-2xl shadow-xl border border-gray-700/50 overflow-hidden group"> <div className="relative bg-gray-800/50 backdrop-blur-lg rounded-2xl shadow-xl border border-gray-700/50 overflow-hidden group">
<div className="absolute inset-0 bg-gradient-to-br from-yellow-500/10 to-orange-500/10 opacity-50"></div> <div className="absolute inset-0 bg-gradient-to-br from-yellow-500/10 to-orange-500/10 opacity-50"></div>
@ -98,12 +100,11 @@ const Page: React.FC = (): React.ReactElement => {
<span className="text-orange-300 text-sm">TBD</span> <span className="text-orange-300 text-sm">TBD</span>
</div> </div>
</div> </div>
<div className="mt-6"> <div className="mt-6">
<button <button
disabled disabled
className="w-full bg-gradient-to-r from-yellow-500/50 to-orange-500/50 className="w-full bg-gradient-to-r from-yellow-500/50 to-orange-500/50
text-white/50 font-semibold py-4 px-6 rounded-xl text-white/50 font-semibold py-4 px-6 rounded-xl
cursor-not-allowed opacity-50" cursor-not-allowed opacity-50"
> >
Coming Soon Coming Soon

View File

@ -43,7 +43,7 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
try { try {
const result = await onGenerate(inputText) const result = await onGenerate(inputText)
if (result.error) { if (result.error) {
setGenerationState({ setGenerationState({
...generationState, ...generationState,
@ -91,8 +91,8 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
onChange={(e) => setInputText(e.target.value)} onChange={(e) => setInputText(e.target.value)}
placeholder="Enter your prompt here..." placeholder="Enter your prompt here..."
disabled={!isWalletConnected} disabled={!isWalletConnected}
className="w-full bg-gray-900/50 text-gray-100 border border-gray-700 rounded-xl p-4 className="w-full bg-gray-900/50 text-gray-100 border border-gray-700 rounded-xl p-4
placeholder-gray-500 focus:border-green-500 focus:ring-2 focus:ring-green-500/20 placeholder-gray-500 focus:border-green-500 focus:ring-2 focus:ring-green-500/20
focus:outline-none min-h-[120px] transition-all duration-200 focus:outline-none min-h-[120px] transition-all duration-200
disabled:opacity-50 disabled:cursor-not-allowed" disabled:opacity-50 disabled:cursor-not-allowed"
rows={4} rows={4}
@ -100,9 +100,9 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
<button <button
onClick={handleGenerate} onClick={handleGenerate}
disabled={!isWalletConnected || generationState.loading || !inputText} disabled={!isWalletConnected || generationState.loading || !inputText}
className="w-full bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 className="w-full bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600
hover:to-emerald-600 text-white font-semibold py-4 px-6 rounded-xl hover:to-emerald-600 text-white font-semibold py-4 px-6 rounded-xl
transition-all duration-200 shadow-lg hover:shadow-green-500/25 transition-all duration-200 shadow-lg hover:shadow-green-500/25
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:shadow-none" disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:shadow-none"
> >
{generationState.loading ? 'Processing...' : `Pay ${tokenCost} MTM & Generate`} {generationState.loading ? 'Processing...' : `Pay ${tokenCost} MTM & Generate`}

View File

@ -16,13 +16,13 @@ export const FLUX_MODELS: FluxModelConfig[] = [
modelId: "fal-ai/flux/schnell", modelId: "fal-ai/flux/schnell",
name: "Schnell", name: "Schnell",
description: "Fast meme generator", description: "Fast meme generator",
cost: 300 cost: 300
}, },
{ {
modelId: "fal-ai/recraft-v3", modelId: "fal-ai/recraft-v3",
name: "Recraft", name: "Recraft",
description: "Advanced meme generator", description: "Advanced meme generator",
cost: 400 cost: 400
}, },
{ {
modelId: "fal-ai/stable-diffusion-v35-large", modelId: "fal-ai/stable-diffusion-v35-large",

View File

@ -1,17 +1,16 @@
import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js' import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js'
import { import {
TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID,
createTransferInstruction, createTransferInstruction,
getAssociatedTokenAddress,
createAssociatedTokenAccountInstruction, createAssociatedTokenAccountInstruction,
ASSOCIATED_TOKEN_PROGRAM_ID ASSOCIATED_TOKEN_PROGRAM_ID
} from '@solana/spl-token' } from '@solana/spl-token'
import { WalletType } from './types' import { WalletType } from './types'
const MTM_TOKEN_MINT: string = '97RggLo3zV5kFGYW4yoQTxr4Xkz4Vg2WPHzNYXXWpump' const MTM_TOKEN_MINT = process.env.NEXT_PUBLIC_MTM_TOKEN_MINT;
const PAYMENT_RECEIVER_ADDRESS: string = 'FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY' const PAYMENT_RECEIVER_ADDRESS = process.env.NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS;
const SOLANA_RPC_URL: string = 'https://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4' const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
const SOLANA_WEBSOCKET_URL: string = 'wss://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4' const SOLANA_WEBSOCKET_URL = process.env.NEXT_PUBLIC_SOLANA_WEBSOCKET_URL;
const connection = new Connection( const connection = new Connection(
SOLANA_RPC_URL, SOLANA_RPC_URL,
@ -52,7 +51,7 @@ export async function processMTMPayment(
): Promise<PaymentResult> { ): Promise<PaymentResult> {
try { try {
let wallet: WalletAdapter | null = null; let wallet: WalletAdapter | null = null;
if (walletType === 'phantom') { if (walletType === 'phantom') {
wallet = window.phantom?.solana || null; wallet = window.phantom?.solana || null;
} else if (walletType === 'solflare') { } else if (walletType === 'solflare') {
@ -150,8 +149,8 @@ export async function processMTMPayment(
return { success: true } return { success: true }
} catch (error) { } catch (error) {
console.error('Payment error:', error) console.error('Payment error:', error)
return { return {
success: false, success: false,
error: error instanceof Error ? error.message : 'Payment failed' error: error instanceof Error ? error.message : 'Payment failed'
} }
} }