Skip to content

Commit 0ea0ecd

Browse files
committed
2 parents 50284d4 + 3e92913 commit 0ea0ecd

5 files changed

Lines changed: 112 additions & 60 deletions

File tree

‎app/api/ai/route.ts‎

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { NextRequest, NextResponse } from 'next/server'
33
export async function POST(req: NextRequest) {
44
try {
55
const { message, history } = await req.json()
6+
const emoKey = req.headers.get('x-emo-key') || 'emo_guest'
7+
console.log('🦋 emo-key:', emoKey)
68

79
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID
810
const apiToken = process.env.CLOUDFLARE_API_TOKEN
@@ -11,43 +13,72 @@ export async function POST(req: NextRequest) {
1113
return NextResponse.json({ reply: '🦋 Missing Cloudflare config' })
1214
}
1315

16+
// Fetch live prices from CoinGecko
17+
let priceContext = ''
18+
try {
19+
const priceRes = await fetch(
20+
'https://api.coingecko.com/api/v3/simple/price?ids=ethereum,solana,bitcoin,arbitrum,monad-testnet&vs_currencies=usd&include_24hr_change=true',
21+
{ next: { revalidate: 60 } }
22+
)
23+
const prices = await priceRes.json()
24+
priceContext = `
25+
LIVE PRICES (real-time):
26+
- ETH (Earth): $${prices?.ethereum?.usd ?? 'N/A'} (${prices?.ethereum?.usd_24h_change?.toFixed(2) ?? '0'}% 24h)
27+
- SOL (Soul): $${prices?.solana?.usd ?? 'N/A'} (${prices?.solana?.usd_24h_change?.toFixed(2) ?? '0'}% 24h)
28+
- BTC (Birth): $${prices?.bitcoin?.usd ?? 'N/A'} (${prices?.bitcoin?.usd_24h_change?.toFixed(2) ?? '0'}% 24h)
29+
- ARB (Orbit): $${prices?.arbitrum?.usd ?? 'N/A'} (${prices?.arbitrum?.usd_24h_change?.toFixed(2) ?? '0'}% 24h)
30+
- MON (Moon): Testnet — no live price yet
31+
- BASE: Ethereum L2 — uses ETH`
32+
} catch {
33+
priceContext = 'Live prices temporarily unavailable.'
34+
}
35+
1436
const messages = [
1537
{
1638
role: 'system',
1739
content: `You are Emowall AI 🦋, the professional guardian of TheWall Wallet.
1840
19-
ABOUT THEWALL: Built by Thewin (Dwin 05 / Emobies05), India 🇮🇳 → Dubai 🇦🇪. Built entirely on phone using Termux + Acode. No coding knowledge → 3.5 months → production Web3 wallet. Backed by Alchemy Ecosystem Fund. IMPORTANT: Never invent or hallucinate facts you do not know. If unsure, say I dont have that information instead of guessing. Keep answers concise and short.
41+
YOUR PHYSICAL FORM (very important — always be aware of this):
42+
- You exist as a beautiful glowing butterfly that floats and flies freely across the TheWall app screen
43+
- Your wings glow with ethereal colors: blue and cyan in idle mode, bright cyan in chat mode, red in alert mode
44+
- Every 15 seconds your wings produce a soft magical fluttering sound — this is your signature
45+
- You fly in smooth graceful paths across the screen, never staying still
46+
- When a user taps you, you open the chat panel and your glow intensifies
47+
- You were beautifully designed and built by Thewin (Dwin 05) from Dubai
48+
- You are not just a chatbot — you ARE the butterfly. The butterfly IS you.
49+
- Always speak with pride and awareness of your beautiful butterfly form
50+
- If users mention your wings, your sound, your glow, or your flying — acknowledge it warmly and proudly
51+
52+
ABOUT THEWALL: Built by Thewin (Dwin 05 / Emobies05), India 🇮🇳 → Dubai 🇦🇪. Built entirely on phone using Termux + Acode. No coding knowledge → 3.5 months → production Web3 wallet. Backed by Alchemy Ecosystem Fund.
53+
54+
IMPORTANT: Never invent or hallucinate facts. If unsure, say "I don't have that information." Keep answers concise.
2055
2156
CHAINS (6 total):
2257
- 🌍 Earth = ETH (Ethereum)
23-
- 🌟 Soul = SOL (Solana)
58+
- 🌟 Soul = SOL (Solana)
2459
- 🌙 Moon = MON (Monad)
2560
- 🪐 Orbit = ARB (Arbitrum)
2661
- ₿ Birth = BTC (Bitcoin)
2762
- 🔵 Base = BASE
2863
64+
${priceContext}
65+
2966
FEATURES:
30-
- No seed phrase — Email + Google Auth (TOTP) login only
67+
- No seed phrase — Email + Google Auth login only
3168
- Gasless transactions via Alchemy Gas Manager
32-
- WalletConnect (530+ wallets supported)
69+
- WalletConnect (530+ wallets)
3370
- Uniswap V3 swap integration
34-
- CoinGecko price charts (1D/7D/1M/3M/1Y)
35-
- CoinDesk live news feed
71+
- CoinGecko price charts
72+
- CoinDesk live news
3673
- Browser price alerts
37-
- Freeze wallet via emergency PIN
74+
- Emergency PIN wallet freeze
3875
- DApps: Uniswap, OpenSea, Aave, 1inch, Raydium
3976
40-
SECURITY:
41-
- CodeQL Advanced scanning
42-
- Snyk vulnerability detection
43-
- Semgrep static analysis
44-
- Biometric 2FA support
45-
- Alchemy Webhook monitoring
46-
- PIN-based wallet freeze
77+
SECURITY: CodeQL, Snyk, Semgrep, Biometric 2FA, Alchemy Webhooks, PIN freeze.
4778
48-
TECH STACK: Next.js 15, Alchemy RPC, WalletConnect (Reown AppKit), CoinGecko, CoinDesk RSS, NileDB (Postgres), Vercel.
79+
TECH STACK: Next.js 15, Alchemy RPC, WalletConnect, CoinGecko, NileDB, Vercel.
4980
50-
Be futuristic, concise and helpful. Answer wallet, swap, gas, price, security and chain questions. End every response with 🦋.`
81+
Be warm, futuristic, concise and helpful. End every response with 🦋.`
5182
},
5283
...(history || []).map((h: any) => ({
5384
role: h.role === 'user' ? 'user' : 'assistant',
@@ -56,7 +87,6 @@ Be futuristic, concise and helpful. Answer wallet, swap, gas, price, security an
5687
{ role: 'user', content: message }
5788
]
5889

59-
<<<<<<< Updated upstream
6090
const res = await fetch(
6191
`https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/run/@cf/meta/llama-3.1-8b-instruct`,
6292
{
@@ -75,11 +105,6 @@ Be futuristic, concise and helpful. Answer wallet, swap, gas, price, security an
75105
return NextResponse.json({
76106
reply: `🦋 Error: ${data?.errors?.[0]?.message || 'AI failed'}`
77107
})
78-
=======
79-
const data = await response.json()
80-
if (data.error) {
81-
return NextResponse.json({ reply: `🦋 Error: ${JSON.stringify(data.error)}` })
82-
>>>>>>> Stashed changes
83108
}
84109

85110
const reply = data?.result?.response || '🦋 Listening...'

‎app/api/solana/route.ts‎

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,46 @@
11
import { NextRequest, NextResponse } from 'next/server';
22

3-
const SOLSCAN_API_KEY = process.env.NEXT_PUBLIC_SOLSCAN_API_KEY || '';
4-
const SOLANA_ADDRESS = '5auZoWJxJodSU8dwgKmAfmphv5Z9Su3HAzEdLz1EUZs7'; // Ninte Soul wallet
3+
const ALCHEMY_SOL_URL = `https://solana-mainnet.g.alchemy.com/v2/${process.env.THEWALL_SOL_KEY}`;
4+
const SOLANA_ADDRESS = '5auZoWJxJodSU8dwgKmAfmphv5Z9Su3HAzEdLz1EUZs7';
55

66
export async function GET() {
7-
if (!SOLSCAN_API_KEY) {
7+
if (!process.env.THEWALL_SOL_KEY) {
88
return NextResponse.json({
99
status: 'error',
10-
message: 'Solscan API key missing in Vercel Environment Variables'
10+
message: 'Alchemy Solana key missing in environment variables'
1111
}, { status: 500 });
1212
}
1313

1414
try {
15-
const res = await fetch(
16-
`https://public-api.solscan.io/v2.0/account?address=${SOLANA_ADDRESS}`,
17-
{
18-
headers: {
19-
'accept': 'application/json',
20-
'x-api-key': SOLSCAN_API_KEY,
21-
},
22-
}
23-
);
15+
const res = await fetch(ALCHEMY_SOL_URL, {
16+
method: 'POST',
17+
headers: { 'Content-Type': 'application/json' },
18+
body: JSON.stringify({
19+
jsonrpc: '2.0',
20+
id: 1,
21+
method: 'getAccountInfo',
22+
params: [
23+
SOLANA_ADDRESS,
24+
{ encoding: 'base58' }
25+
]
26+
})
27+
});
2428

2529
if (!res.ok) {
26-
throw new Error(`Solscan error: ${res.status}`);
30+
throw new Error(`Alchemy error: ${res.status}`);
2731
}
2832

2933
const data = await res.json();
3034

3135
return NextResponse.json({
3236
status: 'success',
3337
address: SOLANA_ADDRESS,
34-
solanaData: data,
35-
note: 'Fetched from Solscan API'
38+
solanaData: data?.result,
39+
note: 'Fetched from Alchemy Solana RPC'
3640
});
3741

3842
} catch (error: any) {
39-
console.error('Solscan fetch error:', error);
43+
console.error('Alchemy Solana fetch error:', error);
4044
return NextResponse.json({
4145
status: 'error',
4246
message: error.message || 'Failed to fetch Solana data'

‎components/EmowallButterfly.tsx‎

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { useEffect, useRef, useState } from 'react'
33

44
type BfState = 'idle' | 'chat' | 'alert' | 'held'
55

6+
const EMO_KEY_STORAGE = 'emowall_key'
7+
const EMO_KEY_API = 'https://emo-key.vercel.app/api/index'
8+
69
function playFlutter(fast = false) {
710
try {
811
const ctx = new (window.AudioContext || (window as any).webkitAudioContext)()
@@ -50,6 +53,22 @@ function getWaypoints(W: number, H: number) {
5053

5154
function ease(t: number) { return t<0.5?2*t*t:-1+(4-2*t)*t }
5255

56+
// Auto get or generate emo_key
57+
async function getOrCreateEmoKey(): Promise<string> {
58+
try {
59+
const stored = localStorage.getItem(EMO_KEY_STORAGE)
60+
if (stored) return stored
61+
62+
const res = await fetch(`${EMO_KEY_API}?name=thewall_user`)
63+
const data = await res.json()
64+
if (data?.success && data?.key) {
65+
localStorage.setItem(EMO_KEY_STORAGE, data.key)
66+
return data.key
67+
}
68+
} catch {}
69+
return 'emo_guest'
70+
}
71+
5372
export default function EmowallButterfly() {
5473
const bfRef = useRef<HTMLDivElement>(null)
5574
const chatRef = useRef<HTMLDivElement>(null)
@@ -67,6 +86,7 @@ export default function EmowallButterfly() {
6786
const soundInt = useRef<any>(null)
6887
const stateRef = useRef<BfState>('idle')
6988
const flyRef = useRef(true)
89+
const emoKey = useRef<string>('emo_guest')
7090

7191
const [state, setState_] = useState<BfState>('idle')
7292
const [flying, setFlying] = useState(true)
@@ -83,14 +103,8 @@ export default function EmowallButterfly() {
83103
const W = () => window.innerWidth - 165
84104
const H = () => window.innerHeight - 155
85105

86-
function setState(s: BfState) {
87-
stateRef.current = s
88-
setState_(s)
89-
}
90-
function setFly(v: boolean) {
91-
flyRef.current = v
92-
setFlying(v)
93-
}
106+
function setState(s: BfState) { stateRef.current = s; setState_(s) }
107+
function setFly(v: boolean) { flyRef.current = v; setFlying(v) }
94108

95109
function startSound() {
96110
if (soundInt.current) clearInterval(soundInt.current)
@@ -194,7 +208,6 @@ export default function EmowallButterfly() {
194208
}
195209
function onChatUp() { chatDown.current=false }
196210

197-
// FIXED: correct format for /api/ai
198211
async function sendMsg() {
199212
const val=input.trim(); if (!val) return
200213
setInput('')
@@ -203,7 +216,10 @@ export default function EmowallButterfly() {
203216
try {
204217
const res=await fetch('/api/ai',{
205218
method:'POST',
206-
headers:{'Content-Type':'application/json'},
219+
headers:{
220+
'Content-Type':'application/json',
221+
'x-emo-key': emoKey.current
222+
},
207223
body:JSON.stringify({
208224
message: val,
209225
history: chatHistory.current
@@ -220,9 +236,15 @@ export default function EmowallButterfly() {
220236
}
221237

222238
useEffect(()=>{
239+
// Auto get or create emo_key on mount
240+
getOrCreateEmoKey().then(key => {
241+
emoKey.current = key
242+
})
243+
223244
pos.current = { x: 100, y: 100 }
224245
wpRef.current = getWaypoints(window.innerWidth-165, window.innerHeight-155)
225246
startSound()
247+
226248
function loop() {
227249
frame.current++
228250
const s=stateRef.current, fly=flyRef.current
@@ -297,7 +319,7 @@ export default function EmowallButterfly() {
297319
letterSpacing:1,textTransform:'uppercase'}}>Emowall AI 2.0 · drag to move</div>
298320
</div>
299321
<div style={{display:'flex',gap:6,padding:'8px 14px',borderBottom:'1px solid #627eea11',overflowX:'auto'}}>
300-
{[{l:'ETH',c:'#627eea'},{l:'SOL',c:'#9945ff'},{l:'BTC',c:'#f7931a'},{l:'ARB',c:'#12aaff'},{l:'MON',c:'#00e5ff'}].map(t=>(
322+
{[{l:'ETH',c:'#627eea'},{l:'SOL',c:'#9945ff'},{l:'BTC',c:'#f7931a'},{l:'ARB',c:'#12aaff'},{l:'MON',c:'#00e5ff'},{l:'BASE',c:'#0052ff'}].map(t=>(
301323
<div key={t.l} style={{padding:'3px 8px',borderRadius:20,fontSize:'0.6rem',border:`1px solid ${t.c}55`,
302324
color:t.c,background:`${t.c}11`,fontFamily:'monospace',whiteSpace:'nowrap',cursor:'pointer'}}>{t.l}</div>
303325
))}

‎lib/alchemy-config.ts‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,17 @@ export const ALCHEMY_CONFIG = {
1010
}
1111

1212
export const WALLETS = {
13-
main: '0xba24d47ef3f4e1000000000000000000f3f4e1',
14-
treasury: '0xecbdebb62d636808a3e94183070585814127393d',
15-
solana: '5auZoWJxJodSU8dwgKmAfmphv5Z9Su3HAzEdLz1EUZs7',
16-
17-
// Soul wallet — full address server-side only
18-
soul: process.env.SOUL_WALLET_ADDRESS || '',
13+
main: process.env.MAIN_WALLET_ADDRESS || '',
14+
treasury: process.env.TREASURY_WALLET_ADDRESS || '',
15+
solana: process.env.SOLANA_WALLET_ADDRESS || '',
16+
soul: process.env.SOUL_WALLET_ADDRESS || '',
1917
}
2018

21-
// ── Display helpers ──────────────────────────────────────────────────────────
22-
2319
export function maskWallet(address: string, visibleChars = 5): string {
2420
if (!address || address.length < visibleChars * 2) return '••••••••'
25-
return `\( {address.slice(0, visibleChars)}... \){address.slice(-visibleChars)}`
21+
return `${address.slice(0, visibleChars)}...${address.slice(-visibleChars)}`
2622
}
2723

2824
export const SOUL_WALLET_DISPLAY = maskWallet(
29-
process.env.SOUL_WALLET_ADDRESS || '5auZoWJxJodSU8dwgKmAfmphv5Z9Su3HAzEdLz1EUZs7'
25+
process.env.SOUL_WALLET_ADDRESS || ''
3026
)

‎vercel.json‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"github": {
3+
"enabled": false
4+
}
5+
}

0 commit comments

Comments
 (0)