├─ package.json
├─ README.md
├─ vite.config.js
├─ tailwind.config.cjs
├─ postcss.config.cjs
├─ .env.example
├─ src/
│ ├─ main.jsx
│ ├─ App.jsx
│ ├─ index.css
│ ├─ hooks/usePoints.js
│ ├─ components/
│ │ ├─ WalletProvider.jsx
│ │ ├─ Navbar.jsx
│ │ ├─ Dashboard.jsx
│ │ ├─ Staking.jsx
│ │ ├─ Swap.jsx
│ │ ├─ NFTMarket.jsx
│ │ └─ About.jsx
│ └─ utils/solana.js
└─ server/
├─ package.json
└─ index.js
---
package.json
{
"name": "solana-vote-predict-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@heroicons/react": "^2.0.18",
"@solana/wallet-adapter-base": "^0.9.14",
"@solana/wallet-adapter-react": "^0.16.10",
"@solana/wallet-adapter-react-ui": "^0.11.5",
"@solana/wallet-adapter-wallets": "^0.18.5",
"@solana/web3.js": "^1.79.0",
"axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.14.1",
"tailwindcss": "^3.5.2"
},
"devDependencies": {
"vite": "^5.2.0"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
README.md
# Solana Voting & Prediction Platform
Connect wallet, stake, swap tokens, trade NFTs, earn points, and participate in votes/predictions.
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({ plugins: [react()] })
tailwind.config.cjs
module.exports = {
content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
theme: { extend: {} },
plugins: [],
}
postcss.config.cjs
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
.env.example
VITE_SOLANA_CLUSTER=https://api.devnet.solana.com
VITE_JUPITER_API=https://quote-api.jup.ag
VITE_BACKEND_URL=http://localhost:4000
---
src/main.jsx
import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import './index.css'
createRoot(document.getElementById('root')).render(
)
src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
html, body, #root { height: 100%; }
src/utils/solana.js
import { Connection, clusterApiUrl } from '@solana/web3.js'
export function getConnection(){
const cluster = import.meta.env.VITE_SOLANA_CLUSTER || clusterApiUrl('devnet')
return new Connection(cluster, 'confirmed')
}
src/components/WalletProvider.jsx
import React, { useMemo } from 'react'
import { ConnectionProvider, WalletProvider as SAWalletProvider } from '@solana/wallet-adapter-react'
import { PhantomWalletAdapter, SolflareWalletAdapter, SlopeWalletAdapter } from '@solana/wallet-adapter-wallets'
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'
import { getConnection } from '../utils/solana'
require('@solana/wallet-adapter-react-ui/styles.css')
export default function WalletProvider({ children }){
const endpoint = import.meta.env.VITE_SOLANA_CLUSTER
const wallets = useMemo(() => [ new PhantomWalletAdapter(), new SolflareWalletAdapter(), new SlopeWalletAdapter() ], [])
return (
{children}
)
}
src/components/Navbar.jsx
import React from 'react'
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'
import { Link } from 'react-router-dom'
export default function Navbar(){
return (
)
}
src/hooks/usePoints.js
import { useState, useEffect } from 'react'
import axios from 'axios'
export default function usePoints(publicKey){
const [points, setPoints] = useState(0)
useEffect(()=>{
if(!publicKey){ setPoints(0); return }
axios.get(`${import.meta.env.VITE_BACKEND_URL}/points/${publicKey}`).then(r=>{
setPoints(r.data.points||0)
}).catch(()=>{
const p = parseInt(localStorage.getItem(`points_${publicKey}`))||0
setPoints(p)
})
},[publicKey])
const addPoints = async amt => {
try{
await axios.post(`${import.meta.env.VITE_BACKEND_URL}/points/add`, { publicKey, amount: amt })
setPoints(p=>p+amt)
}catch{
const newv=(parseInt(localStorage.getItem(`points_${publicKey}`))||0)+amt
localStorage.setItem(`points_${publicKey}`,newv)
setPoints(newv)
}
}
return { points, addPoints }
}
src/components/Dashboard.jsx
import React from 'react'
import { useWallet } from '@solana/wallet-adapter-react'
import usePoints from '../hooks/usePoints'
export default function Dashboard(){
const { publicKey } = useWallet()
const { points } = usePoints(publicKey?.toBase58())
return (
Dashboard
Wallet: {publicKey?.toBase58()||"Not connected"}
Staked: 0 SOL
Trading Volume: 0 SOL
Points: {points}
)
}
src/components/Staking.jsx
import React from 'react'
import { useWallet } from '@solana/wallet-adapter-react'
import usePoints from '../hooks/usePoints'
export default function Staking(){
const { publicKey } = useWallet()
const { addPoints } = usePoints(publicKey?.toBase58())
return (
Staking
)
}
src/components/Swap.jsx
import React, { useState } from 'react'
import axios from 'axios'
export default function Swap(){
const [fromMint, setFromMint] = useState('So11111111111111111111111111111111111111112')
const [toMint, setToMint] = useState('So11111111111111111111111111111111111111112')
const [amount, setAmount] = useState('')
const [quote, setQuote] = useState(null)
const getQuote = async () => {
try{
const api = import.meta.env.VITE_JUPITER_API
const res = await axios.get(`${api}/v4/quote`, {
params:{ inputMint: fromMint, outputMint: toMint, amount: Math.round(Number(amount)*1e9) }
})
setQuote(res.data)
}catch(e){ alert('Quote failed') }
}
return (
Swap
setAmount(e.target.value)} placeholder="Amount" />
{quote &&
{JSON.stringify(quote,null,2)}}
)
}
src/components/NFTMarket.jsx
import React from 'react'
export default function NFTMarket(){ return NFT Market
}
src/components/About.jsx
import React from 'react'
export default function About(){ return About Platform
}
src/App.jsx
import React from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import WalletProvider from './components/WalletProvider'
import Navbar from './components/Navbar'
import Dashboard from './components/Dashboard'
import Staking from './components/Staking'
import Swap from './components/Swap'
import NFTMarket from './components/NFTMarket'
import About from './components/About'
export default function App(){
return (
} />
} />
} />
} />
} />
)
}
---
server/index.js
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
const store = {}
app.get('/points/:pk',(req,res)=>res.json({points:store[req.params.pk]||0}))
app.post('/points/add',(req,res)=>{
const {publicKey,amount}=req.body
store[publicKey]=(store[publicKey]||0)+(amount||0)
res.json({points:store[publicKey]})
})
app.listen(4000)
server/package.json
{
"name": "solvote-server",
"version": "0.1.0",
"main": "index.js",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2"
},
"scripts": { "start": "node index.js" }
}