forked from mito-systems/sol-mem-gen
Add check for phantom wallet before throwing error #1
6
.env.example
Normal file
6
.env.example
Normal 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
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
|
||||||
|
.env
|
@ -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
|
||||||
|
@ -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`}
|
||||||
|
@ -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",
|
||||||
|
@ -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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user