import { NextRequest, NextResponse } from 'next/server' import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' import { connectToDatabase } from '@/lib/mongodb' import { ObjectId } from 'mongodb' import { coinSchema } from '@/lib/validations' import { checkRateLimit } from '@/lib/rate-limit' export async function GET() { try { const { db } = await connectToDatabase() const coins = await db .collection('coins') .find({}) .sort({ createdAt: -1 }) .toArray() return NextResponse.json(coins) } catch (error) { console.error('Error fetching coins:', error) return NextResponse.json({ error: 'Failed to fetch coins' }, { status: 500 }) } } export async function POST(request: NextRequest) { try { const session = await getServerSession(authOptions) if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const { db } = await connectToDatabase() const body = await request.json() const validationResult = coinSchema.safeParse(body) if (!validationResult.success) { const errorMessage = validationResult.error.errors.map(e => e.message).join(', ') return NextResponse.json({ error: errorMessage }, { status: 400 }) } const { name, ticker, description, website, twitter, telegram, initialBuy, useUserImage, verified, boosted } = validationResult.data const cleanName = name const cleanTicker = ticker const cleanDescription = description if (!cleanName || !cleanTicker) { return NextResponse.json({ error: 'Name and ticker are required' }, { status: 400 }) } const user = await db.collection('users').findOne({ _id: new ObjectId(session.user.id) }) if (!user) { return NextResponse.json({ error: 'User not found' }, { status: 404 }) } //! verify via DB for security cuz client can be manipulated let isVerified = false if (verified && user.verified) { isVerified = true } //? costs const creationCost = 0.02; const boostCost = boosted ? 1.0 : 0; const initialBuyAmount = typeof initialBuy === 'number' && initialBuy > 0 ? initialBuy : 0; const totalCost = creationCost + boostCost + initialBuyAmount; if ((user.balance || 0) < totalCost) { return NextResponse.json({ error: `Insufficient balance (${totalCost.toFixed(3)} SOL required)` }, { status: 400 }) } const existingCoin = await db.collection('coins').findOne({ ticker: cleanTicker }) if (existingCoin) { return NextResponse.json({ error: 'Ticker already exists' }, { status: 400 }) } if (checkRateLimit(session.user.id, 'coin_creation', 1, 60000 * 5)) { return NextResponse.json({ error: 'Rate limit exceeded. You can only create 1 coin every 5 minutes.' }, { status: 429 }) } let virtualSolReserves = 30; const INITIAL_SUPPLY = 1000000000; let virtualTokenReserves = 1073000000; let initialLiquidity = 0; let initialPrice = virtualSolReserves / virtualTokenReserves; let initialVolume = 0; let boughtTokens = 0; // ! process IB (Snipe) if (initialBuyAmount > 0) { // chat wahat does calc stand for // i hate my life const k = virtualSolReserves * virtualTokenReserves; const newVirtualSolReserves = virtualSolReserves + initialBuyAmount; const newVirtualTokenReserves = k / newVirtualSolReserves; boughtTokens = virtualTokenReserves - newVirtualTokenReserves; // ? update states virtualSolReserves = newVirtualSolReserves; virtualTokenReserves = newVirtualTokenReserves; initialPrice = virtualSolReserves / virtualTokenReserves; initialLiquidity = initialBuyAmount; // ! real liquidity initialVolume = initialBuyAmount; } const now = new Date() const priceHistory = [{ timestamp: now, price: initialPrice, volume: initialVolume, }] const coinImage = (useUserImage && session.user.image) ? session.user.image : `https://api.dicebear.com/7.x/identicon/svg?seed=${cleanTicker}`; const coin = { name: cleanName, ticker: cleanTicker, description: cleanDescription, image: coinImage, website: website || '', twitter: twitter || '', telegram: telegram || '', creatorId: session.user.id, creatorName: user.name || 'Anonymous', // Use DB name, not session name createdAt: now, verified: isVerified, boosted: boosted ? new Date(Date.now() + 24 * 60 * 60 * 1000) : null, marketCap: initialPrice * INITIAL_SUPPLY, price: initialPrice, priceHistory, volume24h: initialVolume, holders: boughtTokens > 0 ? 1 : 0, supply: INITIAL_SUPPLY, liquidity: initialLiquidity, virtualSolReserves, virtualTokenReserves, } const result = await db.collection('coins').insertOne(coin) // deduct total cost await db.collection('users').updateOne( { _id: new ObjectId(session.user.id) }, { $inc: { balance: -totalCost } } ) // give tokens if bought if (boughtTokens > 0) { await db.collection('users').updateOne( { _id: new ObjectId(session.user.id) }, { $push: { portfolio: { coinId: result.insertedId.toString(), amount: boughtTokens, avgBuyPrice: initialBuyAmount / boughtTokens, }, } as any, } ) //? record trade await db.collection('trades').insertOne({ userId: session.user.id, coinId: result.insertedId.toString(), type: 'buy', amount: boughtTokens, price: initialPrice, total: initialBuyAmount, timestamp: now, }) } return NextResponse.json({ ...coin, _id: result.insertedId }) } catch (error) { console.error('Error creating coin:', error) return NextResponse.json({ error: 'Failed to create coin' }, { status: 500 }) } }