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
})
const handleConnect = async (walletType: WalletType): Promise<void> => {
const handleConnect = async (walletType: WalletType): Promise<void> => {
try {
const newWalletState = await connectWallet(walletType)
setWalletState(newWalletState)
@ -29,11 +29,13 @@ const Page: React.FC = (): React.ReactElement => {
}
}
const handleFluxGeneration = (modelId: string, cost: number) => {
return async (prompt: string): Promise<FluxGenerationResult> => {
if (!walletState.connected || !walletState.publicKey || !window.solflare) {
return { error: 'Wallet not connected' }
const type = walletState.type;
if (!walletState.connected || !walletState.publicKey ||
(type === 'phantom' && !window.phantom) ||
(type === 'solflare' && !window.solflare)) {
return { error: 'Wallet not connected' }
}
// Process payment first
@ -63,7 +65,7 @@ const Page: React.FC = (): React.ReactElement => {
<p className="text-gray-400 text-lg mb-8">
Use MTM to generate memes
</p>
<WalletHeader
walletState={walletState}
onConnect={handleConnect}
@ -82,7 +84,7 @@ const Page: React.FC = (): React.ReactElement => {
onGenerate={handleFluxGeneration(model.modelId, model.cost)}
/>
))}
{/* 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="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>
</div>
</div>
<div className="mt-6">
<button
disabled
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
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
cursor-not-allowed opacity-50"
>
Coming Soon

View File

@ -43,7 +43,7 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
try {
const result = await onGenerate(inputText)
if (result.error) {
setGenerationState({
...generationState,
@ -91,8 +91,8 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
onChange={(e) => setInputText(e.target.value)}
placeholder="Enter your prompt here..."
disabled={!isWalletConnected}
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
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
focus:outline-none min-h-[120px] transition-all duration-200
disabled:opacity-50 disabled:cursor-not-allowed"
rows={4}
@ -100,9 +100,9 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
<button
onClick={handleGenerate}
disabled={!isWalletConnected || generationState.loading || !inputText}
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
transition-all duration-200 shadow-lg hover:shadow-green-500/25
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
transition-all duration-200 shadow-lg hover:shadow-green-500/25
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:shadow-none"
>
{generationState.loading ? 'Processing...' : `Pay ${tokenCost} MTM & Generate`}

View File

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

View File

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