111dhruvil111/EntrysakibotPublic · Bot Template
AIThis TBL bot implements a private crypto community access flow called RED EYE. It stores user Telegram profiles, enforces entry requirements such as minimum crypto net worth and deal volume, and offers inline buttons for applying, checking application status, and contacting support. Admin commands are protected by an owner/admin registry, log actions to an audit trail, and route callback-driven menus. A global webhook worker retries failed notifications, and the wildcard handler collects multi-step form input such as asset names.
Socialcryptoprivate-communityaccess-applicationadmin-panelaudit-lognotifications
7 commands0 envUpdated 20d agoCreated Aug 17, 2026
commands/_handle_callback_query.js
javascript · 883 lines
1/**#command2name: /handle_callback_query3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12/**#command13name: /handle_callback_query14answer:15keyboard:16parse_mode: markdown17aliases:18allow_only_group: false19need_reply: 020case_insensitive: true21is_web: 022#command**/23 24// ======================================================25// RED EYE CONSOLIDATED SHARED HELPERS26// ======================================================27function reNum(v, d){ let n=Number(v); return Number.isFinite(n)?n:(d||0); }28function reHtml(v){ return String(v==null?"":v).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); }29function reNow(){ return Date.now(); }30async function reAudit(action,target,details,by){31 let logs=await db.bot.get("audit_logs",[]); if(!Array.isArray(logs))logs=[];32 logs.push({id:"AUD-"+Date.now()+"-"+Math.floor(Math.random()*100000),action:String(action||"event"),target_user_id:Number(target||0)||undefined,details:details||{},by:Number(by||0),at:Date.now()});33 await db.bot.set("audit_logs",logs.slice(-1000));34}35async function reNotify(payload,kind,target){36 try{let r=await Api.sendMessage(payload);if(r&&r.ok===false)throw new Error(String(r.description||"send_failed"));return true;}catch(e){let q=await db.bot.get("notification_retry_queue",[]);if(!Array.isArray(q))q=[];q.push({id:"NQ-"+Date.now()+"-"+Math.floor(Math.random()*100000),payload:payload,kind:String(kind||"notification"),target_user_id:Number(target||payload.chat_id||0),attempts:0,next_retry_at:Date.now()+5*60000,created_at:Date.now()});await db.bot.set("notification_retry_queue",q.slice(-500));return false;}37}38async function reSettings(){ let s=await db.bot.get("system_settings",{}); if(!s||typeof s!=="object")s={}; return s; }39function reDefaultNetworks(asset){40 asset=String(asset||"").toUpperCase();41 if(asset==="USDT")return ["TRON","ETHEREUM","SOLANA","TON"];42 if(asset==="ETH")return ["ETHEREUM"];43 if(asset==="BTC")return ["BITCOIN"];44 if(asset==="SOL")return ["SOLANA"];45 if(asset==="TON")return ["TON"];46 return ["MANUAL"];47}48async function reNetworksFor(asset){49 let s=await reSettings(); let map=s.asset_networks;50 if(map&&typeof map==="object"&&Array.isArray(map[String(asset||"").toUpperCase()])&&map[String(asset||"").toUpperCase()].length)return map[String(asset||"").toUpperCase()];51 return reDefaultNetworks(asset);52}53async function rePriceUSD(asset){54 asset=String(asset||"").toUpperCase();55 let paprika={BTC:"btc-bitcoin",ETH:"eth-ethereum",SOL:"sol-solana",TON:"ton-toncoin",USDT:"usdt-tether"};56 let gecko={BTC:"bitcoin",ETH:"ethereum",SOL:"solana",TON:"the-open-network",USDT:"tether"};57 if(!paprika[asset])return {ok:false,status:"manual_review",reason:"Unsupported automatic price asset"};58 try{let base=String((typeof process!=="undefined"&&process.env&&process.env.COINPAPRIKA_BASE_URL)||"https://api.coinpaprika.com/v1").replace(/\/+$/,""),r=await HTTP.get({url:base+"/tickers/"+encodeURIComponent(paprika[asset]),timeout:6500,responseType:"json"});let x=r&&r.ok&&r.data&&r.data.quotes&&r.data.quotes.USD?Number(r.data.quotes.USD.price):0;if(x>0)return {ok:true,price_usd:x,source:"coinpaprika"};}catch(e){}59 try{let id=gecko[asset],base=String((typeof process!=="undefined"&&process.env&&process.env.COINGECKO_BASE_URL)||"https://api.coingecko.com/api/v3").replace(/\/+$/,""),r=await HTTP.get({url:base+"/simple/price?ids="+encodeURIComponent(id)+"&vs_currencies=usd",timeout:6500,responseType:"json"});let x=r&&r.ok&&r.data&&r.data[id]?Number(r.data[id].usd):0;if(x>0)return {ok:true,price_usd:x,source:"coingecko"};}catch(e){}60 return {ok:false,status:"temporary_unavailable",reason:"Price providers unavailable"};61}62function reEvmAddress(a){return /^0x[a-fA-F0-9]{40}$/.test(String(a||"").trim());}63async function reBalance(wallet){64 let asset=String(wallet.asset||"").toUpperCase(),network=String(wallet.network||"").toUpperCase(),address=String(wallet.address||"").trim();65 if(!asset||!address)return {ok:false,status:"manual_review",reason:"Incomplete wallet"};66 if(asset==="BTC"||network.indexOf("BITCOIN")>=0){67 try{let base=String((typeof process!=="undefined"&&process.env&&process.env.MEMPOOL_API_URL)||"https://mempool.space/api").replace(/\/+$/,""),r=await HTTP.get({url:base+"/address/"+encodeURIComponent(address),timeout:7500,responseType:"json"});if(r&&r.ok&&r.data&&r.data.chain_stats){let st=r.data.chain_stats,b=(Number(st.funded_txo_sum||0)-Number(st.spent_txo_sum||0))/1e8;return {ok:true,balance:Math.max(0,b),source:"mempool.space"};}}catch(e){}68 return {ok:false,status:"temporary_unavailable",reason:"Bitcoin provider unavailable"};69 }70 if(asset==="ETH"&&(network.indexOf("ETH")>=0||network.indexOf("ERC")>=0)){71 if(!reEvmAddress(address))return {ok:false,status:"manual_review",reason:"Invalid EVM address"};72 let url=String((typeof process!=="undefined"&&process.env&&process.env.EVM_RPC_URL)||"https://cloudflare-eth.com");73 try{let r=await HTTP.post({url:url,timeout:7500,responseType:"json",body:{jsonrpc:"2.0",id:1,method:"eth_getBalance",params:[address,"latest"]}});let h=r&&r.ok&&r.data?String(r.data.result||""):"";if(/^0x[0-9a-fA-F]+$/.test(h)){let raw=Number(BigInt(h));return {ok:true,balance:raw/1e18,source:"evm_rpc"};}}catch(e){}74 return {ok:false,status:"temporary_unavailable",reason:"EVM provider unavailable"};75 }76 if(asset==="USDT"&&(network.indexOf("ETH")>=0||network.indexOf("ERC")>=0)){77 if(!reEvmAddress(address))return {ok:false,status:"manual_review",reason:"Invalid EVM address"};78 let url=String((typeof process!=="undefined"&&process.env&&process.env.EVM_RPC_URL)||"https://cloudflare-eth.com"),contract="0xdAC17F958D2ee523a2206206994597C13D831ec7",clean=address.slice(2).toLowerCase().padStart(64,"0");79 try{let r=await HTTP.post({url:url,timeout:7500,responseType:"json",body:{jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:contract,data:"0x70a08231"+clean},"latest"]}});let h=r&&r.ok&&r.data?String(r.data.result||""):"";if(/^0x[0-9a-fA-F]+$/.test(h)){let raw=Number(BigInt(h));return {ok:true,balance:raw/1e6,source:"erc20_rpc"};}}catch(e){}80 return {ok:false,status:"temporary_unavailable",reason:"USDT ERC20 provider unavailable"};81 }82 if(asset==="SOL"||network.indexOf("SOLANA")>=0){83 let url=String((typeof process!=="undefined"&&process.env&&process.env.SOLANA_RPC_URL)||"https://api.mainnet-beta.solana.com");84 try{let r=await HTTP.post({url:url,timeout:7500,responseType:"json",body:{jsonrpc:"2.0",id:1,method:"getBalance",params:[address]}});let v=r&&r.ok&&r.data&&r.data.result?Number(r.data.result.value):NaN;if(Number.isFinite(v))return {ok:true,balance:v/1e9,source:"solana_rpc"};}catch(e){}85 return {ok:false,status:"temporary_unavailable",reason:"Solana provider unavailable"};86 }87 if(asset==="TON"||network.indexOf("TON")>=0){88 let base=String((typeof process!=="undefined"&&process.env&&process.env.TONCENTER_API_URL)||"https://toncenter.com/api/v2").replace(/\/+$/,"");let key=String((typeof process!=="undefined"&&process.env&&process.env.TONCENTER_API_KEY)||"");let url=base+"/getAddressBalance?address="+encodeURIComponent(address)+(key?"&api_key="+encodeURIComponent(key):"");89 try{let r=await HTTP.get({url:url,timeout:7500,responseType:"json"});if(r&&r.ok&&r.data&&r.data.ok===true){let v=Number(r.data.result);if(Number.isFinite(v))return {ok:true,balance:v/1e9,source:"toncenter"};}}catch(e){}90 return {ok:false,status:"temporary_unavailable",reason:"TON provider unavailable"};91 }92 return {ok:false,status:"manual_review",reason:"Unsupported asset/network; manual review required"};93}94async function reVerifyWallet(wallet){95 let b=await reBalance(wallet); if(!b.ok)return {ok:false,status:b.status||"temporary_unavailable",reason:b.reason||"Provider unavailable",checked_at:Date.now()};96 let p=await rePriceUSD(wallet.asset); if(!p.ok)return {ok:false,status:p.status||"temporary_unavailable",reason:p.reason||"Pricing unavailable",balance:b.balance,balance_source:b.source,checked_at:Date.now()};97 return {ok:true,status:"verified",balance:b.balance,price_usd:p.price_usd,usd_value:b.balance*p.price_usd,balance_source:b.source,price_source:p.source,checked_at:Date.now()};98}99async function reVerifyWalletList(wallets){100 if(!Array.isArray(wallets))wallets=[];let out=[],total=0,auto=0,manual=0,temp=0;101 for(let w of wallets){let r=await reVerifyWallet(w||{}),n=Object.assign({},w||{},{auto_verification:r,verification_checked_at:Date.now()});if(r.ok){total+=Number(r.usd_value||0);auto++;}else if(r.status==="manual_review")manual++;else temp++;out.push(n);}102 return {wallets:out,total_usd:total,automatic_count:auto,manual_count:manual,temporary_count:temp,checked_at:Date.now()};103}104async function reAdminRecord(uid){105 let s=await reSettings(),owner=Number(s.owner_id||771142220);if(Number(uid)===owner)return {user_id:owner,role:"owner",revoked:false};106 let a=await db.bot.get("admin_registry",[]);if(!Array.isArray(a))a=[];return a.find(x=>x&&Number(x.user_id)===Number(uid)&&x.revoked!==true)||null;107}108function reRolePerms(role){109 let all=["dashboard","applications","review","approve","reject","more_info","override","members","wallets","reverify","alerts","blacklist","rules","settings","assets","p2p","announcements","analytics","admins","audit","backup","maintenance","system"];110 if(role==="owner"||role==="super_admin")return all;111 if(role==="verification_staff")return ["dashboard","applications","review","approve","reject","more_info","members","wallets","reverify","alerts","analytics"];112 if(role==="moderator")return ["dashboard","members","alerts","blacklist","rules","announcements","audit"];113 if(role==="support")return ["dashboard","applications","members"];114 return [];115}116async function reSessionOK(uid,role){117 let h=String(await db.user.get("staff_pin_hash","",{user_id:Number(uid)})||"");118 if(!h)return false;119 let until=Number(await db.user.get("staff_session_until",0,{user_id:Number(uid)})||0);return until>Date.now();120}121 122// ======================================================123// RED EYE PREMIUM UI LAYER124// ======================================================125function rePremiumKeyboard(kb){126 if(!Array.isArray(kb)) return kb;127 function styled(btn){128 if(!btn || typeof btn!=="object") return btn;129 let b=Object.assign({},btn);130 let t=String(b.text||"").toLowerCase();131 if(!b.style){132 if(/reject|delete|remove|blacklist|revoke|logout|cancel|under 18|disable|archive/.test(t)) b.style="danger";133 else if(/apply|continue|verify|approve|submit|confirm|save|done|join|enable|send|create|login|check/.test(t)) b.style="success";134 else if(/home|status|support|view|manage|settings|applications|members|wallet|rules|assets|analytics|audit|backup|network|admin|authentication|more info|re-verification|alerts/.test(t)) b.style="primary";135 }136 return b;137 }138 return kb.map(row=>Array.isArray(row)?row.map(styled):row);139}140 141async function userRouter(action) {142let uid = Number(user.telegramid || user.id);143let now = Date.now();144 145let s = await db.bot.get("system_settings", {});146if (!s || typeof s !== "object") s = {};147const OWNER_ID = Number(s.owner_id || 771142220);148const OFFICIAL_CHANNEL = String(s.official_channel || "@red_eye_official");149const OFFICIAL_CHANNEL_URL = String(s.official_channel_url || "https://t.me/red_eye_official");150const MIN_CRYPTO = Number(s.min_crypto_networth || 1000);151const MIN_DEALS = Number(s.min_deal_volume || 3000);152 153function ack(text, alert) {154 if (request && request.id) {155 Api.answerCallbackQuery({ callback_query_id: request.id, text: text || undefined, show_alert: !!alert });156 }157}158 159function edit(text, kb) {160 if (request && request.message) {161 return Api.editMessageText({162 chat_id: chat.id,163 message_id: request.message.message_id,164 text: text,165 parse_mode: "HTML",166 reply_markup: kb ? { inline_keyboard: rePremiumKeyboard(kb) } : undefined167 });168 }169 return Api.sendMessage({ chat_id: chat.id, text: text, parse_mode: "HTML", reply_markup: kb ? { inline_keyboard: rePremiumKeyboard(kb) } : undefined });170}171 172async function setStage(stage) {173 let t=Date.now();174 await db.user.set("application_stage", stage);175 await db.user.set("application_last_activity_at", t);176 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q){if(x&&Number(x.user_id)===uid&&x.status==="started")x.last_activity_at=t;}await db.bot.set("application_queue",q);}177}178 179async function loadList(key) {180 let v = await db.user.get(key, []);181 return Array.isArray(v) ? v : [];182}183 184async function renderActivities() {185 let items = await loadList("activities");186 let defs = [["p2p","P2P"],["otc","Limited OTC"],["nft","NFT Gifts"],["networking","Crypto Networking"],["advertising","Advertising"]];187 let rows = defs.map(d => [{ text: (items.includes(d[0]) ? "✓ " : "○ ") + d[1], callback_data: "user_core activity:" + d[0] }]);188 rows.push([{ text: "Continue →", callback_data: "user_core activity_done" }]);189 rows.push([{ text: "← Back", callback_data: "user_core age" }]);190 edit("💠 <b>STEP 4 • YOUR CRYPTO PROFILE</b>\n\nChoose every market you actively participate in.\n<i>You can select multiple options.</i>", rows);191}192 193async function renderAssets() {194 let items = await loadList("assets");195 let featured = s.featured_assets;196 if (!Array.isArray(featured) || !featured.length) featured = ["USDT","SOL","ETH","BTC","TON"];197 let rows = featured.map(a => [{ text: (items.includes(a) ? "✓ " : "○ ") + a, callback_data: "user_core asset:" + a }]);198 rows.push([{ text: "+ Other Cryptocurrency", callback_data: "user_core asset_other" }]);199 rows.push([{ text: "Continue →", callback_data: "user_core asset_done" }]);200 rows.push([{ text: "← Back", callback_data: "user_core activities" }]);201 edit("💎 <b>STEP 5 • ASSETS TO VERIFY</b>\n\nSelect the assets you want counted toward your verified portfolio.\n<i>Multiple assets and wallets are supported.</i>", rows);202}203 204if (!action || action === "home") {205 Bot.runCommand("/start");206 return;207}208 209if (action === "support") {210 await db.user.set("input_mode", "support_message");211 edit(212 "💬 <b>RED EYE • PRIVATE SUPPORT</b>\n\nSend your message, screenshot or document in the next reply.\n\n<i>Your request goes directly to the support queue.</i>",213 [[{ text: "⌂ Main Menu", callback_data: "user_core home" }]]214 );215 return;216}217 218if (action === "apply") {219 let status = String(await db.user.get("application_status", ""));220 if (["submitted","under_review","more_info_required"].includes(status)) {221 ack("You already have an active application.", true);222 await userRouter("status");223 return;224 }225 if (status === "approved") {226 ack("Your application is already approved.", true);227 await userRouter("status");228 return;229 }230 let blacklist = await db.bot.get("blacklist", []); if (!Array.isArray(blacklist)) blacklist=[];231 if (status === "blacklisted" || blacklist.some(x=>x&&Number(x.user_id)===uid)) {232 await db.user.set("application_status","blacklisted");233 ack("Applications are unavailable for this account.", true);234 return;235 }236 if (status === "rejected") {237 let reapply = Number(await db.user.get("reapply_after", 0));238 if (reapply && now < reapply) {239 ack("Reapplication cooldown is still active.", true);240 return;241 }242 }243 if (s.maintenance_applications_paused === true) {244 ack("New applications are temporarily paused.", true);245 edit("🛠 <b>APPLICATIONS TEMPORARILY PAUSED</b>\n\n" + String(s.maintenance_message || "Please check again later."), [[{text:"⌂ Main Menu",callback_data:"user_core home"}]]);246 return;247 }248 // A re-application is a fresh application. Preserve history, but never silently reuse old answers/proofs.249 if (["rejected","abandoned","cancelled"].includes(status)) {250 let oldSnapshot={application_id:String(await db.user.get("application_id","")||""),status:status,activities:await loadList("activities"),assets:await loadList("assets"),wallets:await loadList("wallets"),ownership_proof:await db.user.get("ownership_proof",null),deal_proofs:await loadList("deal_proofs"),archived_at:now};251 let arch=await db.user.get("application_archives",[]);if(!Array.isArray(arch))arch=[];arch.push(oldSnapshot);await db.user.set("application_archives",arch.slice(-20));252 for (let k of ["activities","assets","wallets","ownership_proof","deal_proofs","membership_verified","premium_verified","username_verified","age_confirmed_18plus","application_id","application_stage","application_started_at","application_submitted_at","more_info_request","more_info_responses","admin_verified_crypto","admin_verified_deals","private_invite_link","auto_verified_crypto_total"]) await db.user.del(k);253 await reAudit("reapplication_fresh_draft",uid,{previous_status:status},uid);254 }255 await db.user.set("application_status", "started");256 let startedAt = Number(await db.user.get("application_started_at", 0)); if (!startedAt || ["rejected","abandoned","cancelled"].includes(status)) { startedAt=now; await db.user.set("application_started_at", now); }257 let q0=await db.bot.get("application_queue",[]);if(!Array.isArray(q0))q0=[];let qi=q0.findIndex(x=>x&&Number(x.user_id)===uid&&x.status==="started");let rec={application_id:String(await db.user.get("application_id","")||("DRAFT-"+uid)),user_id:uid,username:user.username||"",first_name:user.first_name||"",status:"started",started_at:startedAt,last_activity_at:now};if(qi>=0)q0[qi]=Object.assign({},q0[qi],rec);else q0.push(rec);await db.bot.set("application_queue",q0);258 await setStage("membership");259 edit(260 "🔐 <b>STEP 1 • VERIFY YOUR ACCESS</b>\n\nJoin the official RED EYE channel, then tap verification below.\n\n<i>This takes only a moment.</i>",261 [262 [{ text: "↗ Join Official Channel", url: OFFICIAL_CHANNEL_URL }],263 [{ text: "✓ Check Membership", callback_data: "user_core membership" }],264 [{ text: "⌂ Main Menu", callback_data: "user_core home" }]265 ]266 );267 return;268}269 270if (action === "membership") {271 ack();272 let r = await Api.call("getChatMember", { chat_id: OFFICIAL_CHANNEL, user_id: uid });273 if (!r || !r.ok) {274 edit("⚠️ <b>VERIFICATION TEMPORARILY UNAVAILABLE</b>\n\nMembership could not be checked right now. Please try again.", [[{text:"↻ Try Again",callback_data:"user_core membership"}],[{text:"← Back",callback_data:"user_core apply"}]]);275 return;276 }277 let st = r.result && r.result.status;278 let ok = ["member","administrator","creator"].includes(st);279 await db.user.set("membership_verified", ok);280 if (!ok) {281 edit("❌ <b>MEMBERSHIP NOT VERIFIED</b>\n\nJoin the official channel, then verify again.", [[{text:"↗ Join Channel",url:OFFICIAL_CHANNEL_URL}],[{text:"↻ Verify Again",callback_data:"user_core membership"}]]);282 return;283 }284 await db.user.set("membership_verified_at", now);285 await setStage("eligibility");286 edit("✅ <b>CHANNEL ACCESS VERIFIED</b>\n\nPerfect. Your official-channel membership is confirmed.\n\nNext: Telegram identity check.", [[{text:"Continue →",callback_data:"user_core eligibility"}]]);287 return;288}289 290if (action === "eligibility") {291 let usernameOk = !!user.username;292 let premiumOk = user.is_premium === true;293 await db.user.set("username_verified", usernameOk);294 await db.user.set("premium_verified", premiumOk);295 let reqUsername = s.username_required !== false;296 let reqPremium = s.premium_required !== false;297 if ((reqUsername && !usernameOk) || (reqPremium && !premiumOk)) {298 let lines = [];299 if (reqUsername && !usernameOk) lines.push("• Public Telegram username is required.");300 if (reqPremium && !premiumOk) lines.push("• Telegram Premium is required.");301 edit("❌ <b>IDENTITY REQUIREMENTS NOT MET</b>\n\n" + lines.join("\n") + "\n\nFix the requirement and retry.", [[{text:"↻ Check Again",callback_data:"user_core eligibility"}],[{text:"⌂ Main Menu",callback_data:"user_core home"}]]);302 return;303 }304 if (s.age_required === false) { await db.user.set("age_confirmed_18plus", true); await setStage("activities"); edit("✅ <b>TELEGRAM IDENTITY VERIFIED</b>\n\nIdentity requirements are satisfied.", [[{text:"Continue →",callback_data:"user_core activities"}]]); return; }305 await setStage("age");306 edit("✅ <b>IDENTITY VERIFIED</b>\n\nTelegram Premium and public username checks are complete.\n\nNext: age confirmation.", [[{text:"Continue →",callback_data:"user_core age"}]]);307 return;308}309 310if (action === "age") {311 edit("🔞 <b>STEP 3 • AGE CONFIRMATION</b>\n\nYou must confirm that you are at least 18 years old to continue.", [[{text:"✓ I am 18+",callback_data:"user_core age_yes"}],[{text:"✕ I am under 18",callback_data:"user_core age_no"}]]);312 return;313}314if (action === "age_yes") {315 await db.user.set("age_confirmed_18plus", true);316 await setStage("activities");317 await renderActivities();318 return;319}320if (action === "age_no") {321 await db.user.set("age_confirmed_18plus", false);322 await db.user.set("application_status", "cancelled");323 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(x&&Number(x.user_id)===uid&&x.status==="started"){x.status="cancelled";x.cancelled_at=Date.now();}await db.bot.set("application_queue",q);}324 await reAudit("application_cancelled_under18",uid,{},uid);325 edit("⛔ <b>APPLICATION ENDED</b>\n\nRED EYE access is available only to users who confirm they are 18+.", [[{text:"⌂ Main Menu",callback_data:"user_core home"}]]);326 return;327}328 329if (action === "activities") { await renderActivities(); return; }330if (action.indexOf("activity:") === 0) {331 let key = action.split(":")[1];332 let items = await loadList("activities");333 if (items.includes(key)) items = items.filter(x => x !== key); else items.push(key);334 await db.user.set("activities", items);335 await renderActivities();336 return;337}338if (action === "activity_done") {339 let items = await loadList("activities");340 if (!items.length) { ack("Select at least one activity.", true); return; }341 await setStage("assets");342 await renderAssets();343 return;344}345 346if (action === "assets") { await renderAssets(); return; }347if (action.indexOf("asset:") === 0) {348 let key = action.slice(6).toUpperCase();349 let items = await loadList("assets");350 if (s.multiple_assets_allowed === false) { items = items.includes(key) ? [] : [key]; }351 else if (items.includes(key)) items = items.filter(x => x !== key); else items.push(key);352 await db.user.set("assets", items);353 await renderAssets();354 return;355}356if (action === "asset_other") {357 await db.user.set("input_mode", "other_asset_name");358 edit("+ <b>OTHER CRYPTOCURRENCY</b>\n\nSend the asset name/symbol as your next message. Example: <code>AVAX</code>.", [[{text:"← Back",callback_data:"user_core assets"}]]);359 return;360}361if (action === "asset_done") {362 let items = await loadList("assets");363 if (!items.length) { ack("Select at least one asset.", true); return; }364 await setStage("wallets");365 await userRouter("wallets");366 return;367}368 369if (action === "wallets") {370 let wallets = await loadList("wallets");371 let assets = await loadList("assets");372 let memberStatus=String(await db.user.get("member_status",""));let isMember=["active","approved_pending_join"].includes(memberStatus);373 if(isMember&&s.maintenance_wallet_changes_paused===true){edit("🛠 <b>WALLET CHANGES TEMPORARILY PAUSED</b>\n\nYour existing wallet history remains preserved. Please try again later.",[[{text:"‹ Status",callback_data:"user_core status"}]]);return;}374 let rows = assets.map(a => [{text:"+ Add " + a + " Wallet", callback_data:"user_core wallet_asset:" + a}]);375 if (wallets.length) rows.push([{text:"👛 View My Wallets (" + wallets.length + ")",callback_data:"user_core wallet_list"}]);376 if(isMember) rows.push([{text:"‹ Member Status",callback_data:"user_core status"}]);377 else {rows.push([{text:"Continue to Ownership Proof ›",callback_data:"user_core ownership"}]);rows.push([{text:"← Back",callback_data:"user_core assets"}]);}378 edit(isMember?"👛 <b>MEMBER WALLET MANAGEMENT</b>\n\nAdd or archive public wallets here. Any wallet change remains pending for admin verification; historical wallets are retained.":"👛 <b>STEP 6 • WALLET VERIFICATION</b>\n\nAdd one or more public wallet addresses. Never send a seed phrase, private key or password.", rows);379 return;380}381if (action.indexOf("wallet_asset:") === 0) {382 let memberStatus=String(await db.user.get("member_status",""));if(["active","approved_pending_join"].includes(memberStatus)&&s.maintenance_wallet_changes_paused===true){ack("Wallet changes are temporarily frozen.",true);return;}383 let existingWallets=await loadList("wallets"); if(s.multiple_wallets_allowed===false && existingWallets.length>=1){ack("Only one wallet is currently allowed by admin settings.",true);return;}384 let asset = action.slice(13).toUpperCase();385 await db.user.set("current_wallet_asset", asset);386 let networks = await reNetworksFor(asset);387 let rows = networks.map(n => [{text:n, callback_data:"user_core wallet_network:" + n}]);388 rows.push([{text:"← Back",callback_data:"user_core wallets"}]);389 edit("🌐 <b>SELECT NETWORK</b>\n\nAsset: <b>" + asset + "</b>\nChoose the network for this wallet.", rows);390 return;391}392if (action.indexOf("wallet_network:") === 0) {393 let network = action.slice(15).toUpperCase();394 await db.user.set("current_wallet_network", network);395 await db.user.set("input_mode", "wallet_address");396 let asset = String(await db.user.get("current_wallet_asset", ""));397 edit("📋 <b>SEND PUBLIC WALLET ADDRESS</b>\n\nAsset: <b>" + asset + "</b>\nNetwork: <b>" + network + "</b>\n\nSend only the public address. <b>Never</b> send a seed phrase or private key.", [[{text:"‹ Cancel",callback_data:"user_core wallets"}]]);398 return;399}400if (action === "wallet_list") {401 let wallets = await loadList("wallets");402 if (!wallets.length) { edit("👛 <b>MY WALLETS</b>\n\nNo wallets added yet.", [[{text:"+ Add Wallet",callback_data:"user_core wallets"}]]); return; }403 let body = wallets.map((w,i) => { let av=w&&w.auto_verification?w.auto_verification:{}; let status=av.ok?("✅ $"+Number(av.usd_value||0).toFixed(2)):(av.status==="manual_review"?"🟠 Manual review":"🟡 Verification unavailable"); return (i+1)+". <b>"+reHtml(w.asset)+"</b> • "+reHtml(w.network)+"\n<code>"+reHtml(w.address)+"</code>\n"+status; }).join("\n\n");404 let total=Number(await db.user.get("auto_verified_crypto_total",0)||0);405 let rows=[[{text:"+ Add Another",callback_data:"user_core wallets"}]];406 for(let i=0;i<wallets.length;i++) rows.push([{text:"Archive Wallet #"+(i+1),callback_data:"user_core wallet_archive:"+i}]);407 rows.push([{text:"↻ Recheck Wallet Values",callback_data:"user_core wallet_recheck"}]);408 let memberStatus=String(await db.user.get("member_status",""));if(["active","approved_pending_join"].includes(memberStatus))rows.push([{text:"‹ Member Status",callback_data:"user_core status"}]);else rows.push([{text:"Continue →",callback_data:"user_core ownership"}]);409 edit("👛 <b>MY WALLETS</b>\n\n"+body+"\n\nAutomatic verified total: <b>$"+total.toFixed(2)+"</b>\n<i>Unsupported or temporarily unavailable assets remain for manual admin review.</i>", rows);410 return;411}412 413if (action.indexOf("wallet_archive:")===0) {414 let s2=await reSettings(); if(s2.maintenance_wallet_changes_paused===true){ack("Wallet changes are temporarily frozen.",true);return;}415 let i=Number(action.split(":")[1]); let wallets=await loadList("wallets"); if(!wallets[i]){ack("Wallet not found.",true);return;}416 let history=await loadList("wallet_history"); history.push(Object.assign({},wallets[i],{archived_at:Date.now(),archived_reason:"user_change"})); await db.user.set("wallet_history",history.slice(-100));417 wallets.splice(i,1); await db.user.set("wallets",wallets); let vr=await reVerifyWalletList(wallets); await db.user.set("wallets",vr.wallets); await db.user.set("auto_verified_crypto_total",vr.total_usd); let ms=String(await db.user.get("member_status","")||"");if(["active","approved_pending_join"].includes(ms)){await db.user.set("wallet_change_pending",true);await db.user.set("reverification_status","requested");await db.user.set("reverification_type","wallet");let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];if(!rr.some(x=>x&&Number(x.user_id)===uid&&!['completed','cancelled'].includes(String(x.status))&&x.reason==="wallet_change")){rr.push({id:"RV-WALLET-"+uid+"-"+Date.now(),user_id:uid,type:"wallet",reason:"wallet_change",status:"requested",requested_at:Date.now(),requested_by:"system"});await db.bot.set("reverification_requests",rr);}Api.sendMessage({chat_id:OWNER_ID,text:"👛 <b>MEMBER WALLET CHANGE</b>\n\nMember <code>"+uid+"</code> archived a wallet. History is retained and the wallet set is pending admin verification.",parse_mode:"HTML"});}await reAudit("wallet_archived",uid,{index:i,member_change:["active","approved_pending_join"].includes(ms)},uid); await userRouter("wallet_list"); return;418}419if (action === "wallet_recheck") {420 let wallets=await loadList("wallets"); if(!wallets.length){ack("No wallets to check.",true);return;} ack("Checking public balances…",false); let vr=await reVerifyWalletList(wallets); await db.user.set("wallets",vr.wallets); await db.user.set("auto_verified_crypto_total",vr.total_usd); await db.user.set("wallet_last_checked_at",Date.now()); await userRouter("wallet_list"); return;421}422 423if (action === "ownership") {424 let wallets = await loadList("wallets");425 if (!wallets.length) { ack("Add at least one wallet first.", true); return; }426 await db.user.set("input_mode", "ownership_proof");427 await setStage("ownership_proof");428 edit("🎥 <b>STEP 7 • OWNERSHIP PROOF</b>\n\nSend a screen recording/video or document showing your Telegram account context together with the relevant wallet/address context.\n\n<i>Never reveal a seed phrase or private key.</i>", [[{text:"← Back",callback_data:"user_core wallets"}]]);429 return;430}431if (action === "deal_proof") {432 await db.user.set("input_mode", "deal_proof");433 await setStage("deal_proof");434 let proofs = await loadList("deal_proofs");435 edit("📊 <b>STEP 8 • DEAL HISTORY PROOF</b>\n\nSend screenshot(s), document(s) or video(s) showing your relevant P2P/deal stats. Multiple proofs are allowed.\n\nCurrent received: <b>"+proofs.length+"</b>", [[{text:"✓ Finish Proof Upload",callback_data:"user_core summary"}],[{text:"← Back",callback_data:"user_core ownership"}]]);436 return;437}438 439if (action === "summary") {440 let [ownership,proofs,wallets,activities,assets,membership,premium,username,age] = await Promise.all([441 db.user.get("ownership_proof", null), db.user.get("deal_proofs", []), db.user.get("wallets", []),442 db.user.get("activities", []), db.user.get("assets", []), db.user.get("membership_verified", false),443 db.user.get("premium_verified", false), db.user.get("username_verified", false), db.user.get("age_confirmed_18plus", false)444 ]);445 if(!Array.isArray(proofs))proofs=[]; if(!Array.isArray(wallets))wallets=[]; if(!Array.isArray(activities))activities=[]; if(!Array.isArray(assets))assets=[];446 let complete = membership && (s.premium_required===false || premium) && (s.username_required===false || username) && (s.age_required===false || age) && activities.length && assets.length && wallets.length && ownership && proofs.length;447 await setStage("summary");448 edit(449 "🧾 <b>APPLICATION SUMMARY</b>\n\n"+450 "Channel: <b>"+(membership?"✓":"Pending")+"</b>\n"+451 "Premium: <b>"+(premium?"✓":"Pending")+"</b>\n"+452 "Username: <b>"+(username?"✓":"Pending")+"</b>\n"+453 "18+: <b>"+(age?"✓":"Pending")+"</b>\n"+454 "Activities: <b>"+activities.length+"</b>\nAssets: <b>"+assets.length+"</b>\nWallets: <b>"+wallets.length+"</b>\n"+455 "Ownership Proof: <b>"+(ownership?"Received":"Pending")+"</b>\nDeal Proofs: <b>"+proofs.length+"</b>\n\n"+456 (complete ? "Everything required for submission is present." : "Complete the pending items before submitting."),457 complete ? [[{text:"🚀 Submit Application",callback_data:"user_core submit"}],[{text:"← Back",callback_data:"user_core deal_proof"}]] : [[{text:"‹ Continue Application",callback_data:"user_core apply"}]]458 );459 return;460}461 462if (action === "submit") {463 let membership = await db.user.get("membership_verified", false);464 // Re-check official-channel membership at the final submission boundary.465 try{let cm=await Api.call("getChatMember",{chat_id:OFFICIAL_CHANNEL,user_id:uid});let st=cm&&cm.ok&&cm.result?String(cm.result.status||""):"";membership=["creator","administrator","member","restricted"].includes(st);await db.user.set("membership_verified",membership);}catch(e){membership=false;}466 let premium = await db.user.get("premium_verified", false);467 let username = await db.user.get("username_verified", false);468 let age = await db.user.get("age_confirmed_18plus", false);469 let activities = await loadList("activities"), assets = await loadList("assets"), wallets = await loadList("wallets"), proofs = await loadList("deal_proofs");470 let ownership = await db.user.get("ownership_proof", null);471 if (!(membership && (s.premium_required===false || premium) && (s.username_required===false || username) && (s.age_required===false || age) && activities.length && assets.length && wallets.length && ownership && proofs.length)) { ack("Application is incomplete.", true); return; }472 let appId = "RE-" + uid + "-" + now;473 await db.user.set("application_id", appId);474 await db.user.set("application_status", "submitted");475 await db.user.set("application_submitted_at", now);476 await db.user.set("application_stage", "submitted");477 let queue = await db.bot.get("application_queue", []); if (!Array.isArray(queue)) queue = [];478 queue = queue.filter(x => Number(x.user_id) !== uid || !["started","submitted","under_review","more_info_required"].includes(x.status));479 queue.push({ application_id: appId, user_id: uid, username: user.username || "", first_name: user.first_name || "", status: "submitted", submitted_at: now });480 await db.bot.set("application_queue", queue);481 let ah=await db.user.get("application_history",[]);if(!Array.isArray(ah))ah=[];ah.push({application_id:appId,status:"submitted",at:now,username:user.username||"",first_name:user.first_name||""});await db.user.set("application_history",ah.slice(-50));482 await reAudit("application_submitted",uid,{application_id:appId},uid);483 await reNotify({ chat_id: OWNER_ID, text: "📥 <b>NEW RED EYE APPLICATION</b>\n\nUser: "+(user.username?"@"+user.username:(user.first_name||"Unknown"))+"\nID: <code>"+uid+"</code>\nApplication: <code>"+appId+"</code>", parse_mode:"HTML", reply_markup:{inline_keyboard:[[{text:"🧿 Review Application",callback_data:"admin_core app:"+uid,style:"primary"}]]} },"new_application",OWNER_ID);484 edit("🚀 <b>APPLICATION SECURED & SUBMITTED</b>\n\nYour RED EYE application is now in the private review queue.\n\n<i>You can check live status anytime from /start.</i>", [[{text:"📡 Live Application Status",callback_data:"user_core status"}],[{text:"⌂ Main Menu",callback_data:"user_core home"}]]);485 return;486}487 488if (action === "status") {489 let [stRaw,reasonRaw,moreRaw,inviteRaw,rvRaw,rvTypeRaw,memberStatusRaw,membership,premium,uname,age,acts,assets,wallets,own,proofs,stageRaw] = await Promise.all([490 db.user.get("application_status", "not_started"), db.user.get("rejection_reason", ""), db.user.get("more_info_request", ""),491 db.user.get("private_invite_link", ""), db.user.get("reverification_status", ""), db.user.get("reverification_type", ""),492 db.user.get("member_status", ""), db.user.get("membership_verified",false), db.user.get("premium_verified",false),493 db.user.get("username_verified",false), db.user.get("age_confirmed_18plus",false), db.user.get("activities",[]),494 db.user.get("assets",[]), db.user.get("wallets",[]), db.user.get("ownership_proof",null), db.user.get("deal_proofs",[]),495 db.user.get("application_stage","")496 ]);497 let st=String(stRaw||"not_started"), reason=String(reasonRaw||""), more=String(moreRaw||""), invite=String(inviteRaw||"");498 let rv=String(rvRaw||""), rvType=String(rvTypeRaw||""), memberStatus=String(memberStatusRaw||""), stage=String(stageRaw||"");499 if(!Array.isArray(acts))acts=[]; if(!Array.isArray(assets))assets=[]; if(!Array.isArray(wallets))wallets=[]; if(!Array.isArray(proofs))proofs=[];500 let extra = "";501 if (st === "rejected" && reason) extra = "\n\nReason: " + reason;502 if (st === "more_info_required" && more) extra = "\n\nAdmin request: " + more;503 if (["requested","in_progress","submitted"].includes(rv)) extra += "\n\nRe-verification: <b>" + reHtml(rv.toUpperCase()) + " • " + reHtml(rvType.toUpperCase()) + "</b>";504 let rows = [];505 if (["requested","in_progress"].includes(rv)) rows.push([{text:"🔄 Continue Re-verification",callback_data:"user_core reverify_start"}]);506 if (st === "more_info_required") rows.push([{text:"📝 Provide Information",callback_data:"user_core more_info",style:"success"}]);507 if (st === "approved" && invite) rows.push([{text:"🔐 Join Private Community",url:invite}]);508 if(["active","approved_pending_join"].includes(memberStatus))rows.push([{text:"👛 Manage Wallets",callback_data:"user_core wallets"}]);509 if (["not_started","cancelled","abandoned","rejected"].includes(st)) rows.push([{text:"✦ Apply for Private Access",callback_data:"user_core apply"}]);510 rows.push([{text:"⌂ Main Menu",callback_data:"user_core home"}]);511 let sec="\n\n<b>Verification progress</b>\n"+"Channel: "+(membership?"✅":"⏳")+"\n"+"Premium: "+((s.premium_required===false||premium)?"✅":"⏳")+"\n"+"Username: "+((s.username_required===false||uname)?"✅":"⏳")+"\n"+"18+: "+((s.age_required===false||age)?"✅":"⏳")+"\n"+"Activities: "+(acts.length?"✅":"⏳")+"\nAssets: "+(assets.length?"✅":"⏳")+"\nWallets: "+(wallets.length?"✅":"⏳")+"\nOwnership proof: "+(own?"✅":"⏳")+"\nDeal proof: "+(proofs.length?"✅":"⏳");512 let displayStatus=(st==="started"&&stage&&stage!=="membership")?"IN PROGRESS":st.split("_").join(" ").toUpperCase();513 edit("📡 <b>APPLICATION STATUS • LIVE</b>\n\nCurrent status: <b>"+displayStatus+"</b>"+extra+sec, rows);514 return;515}516 517if (action === "reverify_start") {518 let rv=String(await db.user.get("reverification_status","")),type=String(await db.user.get("reverification_type","full"));519 if(!["requested","in_progress"].includes(rv)){ack("No active re-verification request.",true);return;}520 if(s.maintenance_reverification_paused===true){edit("🛠 <b>RE-VERIFICATION TEMPORARILY PAUSED</b>\n\nPlease try again later.",[[{text:"‹ Status",callback_data:"user_core status"}]]);return;}521 await db.user.set("reverification_status","in_progress");522 let rows=[];523 if(type==="wallet"||type==="full")rows.push([{text:"👛 Update / Recheck Wallets",callback_data:"user_core wallets"}]);524 if(type==="deals"||type==="full")rows.push([{text:"📊 Upload Deal Proof",callback_data:"user_core reverify_deals"}]);525 if(type==="ownership"||type==="full")rows.push([{text:"🎥 Upload Ownership Proof",callback_data:"user_core reverify_ownership"}]);526 rows.push([{text:"✅ Submit Re-verification",callback_data:"user_core reverify_submit"}]); rows.push([{text:"‹ Status",callback_data:"user_core status"}]);527 edit("🔄 <b>RE-VERIFICATION</b>\n\nRequested type: <b>"+reHtml(type.toUpperCase())+"</b>\nComplete the required updated evidence, then submit.",rows);return;528}529if (action === "reverify_deals") { await db.user.set("input_mode","reverify_deal_proof"); let p=await loadList("reverify_deal_proofs"); edit("📊 <b>RE-VERIFICATION • DEAL HISTORY</b>\n\nSend updated screenshot(s), video(s) or document(s). Received: <b>"+p.length+"</b>",[[{text:"✅ Done",callback_data:"user_core reverify_start"}]]);return; }530if (action === "reverify_ownership") { await db.user.set("input_mode","reverify_ownership_proof"); edit("🎥 <b>RE-VERIFICATION • OWNERSHIP PROOF</b>\n\nSend a new screen recording/video or document showing Telegram identity and wallet context.",[[{text:"← Back",callback_data:"user_core reverify_start"}]]);return; }531if (action === "reverify_submit") {532 let type=String(await db.user.get("reverification_type","full")),wallets=await loadList("wallets"),dp=await loadList("reverify_deal_proofs"),op=await db.user.get("reverify_ownership_proof",null);533 if((type==="wallet"||type==="full")&&!wallets.length){ack("At least one wallet is required.",true);return;}534 if((type==="deals"||type==="full")&&!dp.length){ack("Updated deal proof is required.",true);return;}535 if((type==="ownership"||type==="full")&&!op){ack("Updated ownership proof is required.",true);return;}536 await db.user.set("reverification_status","submitted"); await db.user.set("reverification_submitted_at",Date.now());537 let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];for(let x of rr){if(x&&Number(x.user_id)===uid&&!['completed','cancelled'].includes(String(x.status))){x.status="submitted";x.submitted_at=Date.now();}}await db.bot.set("reverification_requests",rr);538 await reAudit("reverification_submitted",uid,{type:type},uid); Api.sendMessage({chat_id:OWNER_ID,text:"🔄 <b>RE-VERIFICATION SUBMITTED</b>\n\nUser: <code>"+uid+"</code>\nType: <b>"+reHtml(type.toUpperCase())+"</b>",parse_mode:"HTML",reply_markup:{inline_keyboard:[[{text:"🧿 Review Member",callback_data:"admin_core member:"+uid,style:"primary"}]]}}); edit("✅ <b>RE-VERIFICATION SUBMITTED</b>\n\nYour updated evidence is awaiting admin review.",[[{text:"📡 Live Status",callback_data:"user_core status",style:"primary"}]]);return;539}540 541if (action === "more_info") {542 await db.user.set("input_mode", "more_info_response");543 edit("📝 <b>PROVIDE ADDITIONAL INFORMATION</b>\n\nSend the requested information as your next message. Text, photo, video or document is accepted.", [[{text:"‹ Status",callback_data:"user_core status"}]]);544 return;545}546 547ack("Unknown action.", false);548 549}550 551async function adminRouter(action) {552let s = await db.bot.get("system_settings", {}); if (!s || typeof s !== "object") s = {};553const OWNER_ID = Number(s.owner_id || 771142220);554const PRIVATE_GROUP_ID = Number(s.private_group_id || -1004382007648);555const uid = (typeof user !== "undefined" && user) ? Number(user.telegramid || user.id) : 0;556 557function ack(text, alert) { if (request && request.id) Api.answerCallbackQuery({callback_query_id:request.id,text:text||undefined,show_alert:!!alert}); }558function show(text, kb) {559 if (request && request.message) return Api.editMessageText({chat_id:chat.id,message_id:request.message.message_id,text:text,parse_mode:"HTML",reply_markup:kb?{inline_keyboard:rePremiumKeyboard(kb)}:undefined});560 return Api.sendMessage({chat_id:chat.id,text:text,parse_mode:"HTML",reply_markup:kb?{inline_keyboard:rePremiumKeyboard(kb)}:undefined});561}562 563let adminRecord=await reAdminRecord(uid); if(!adminRecord){ if(uid) Api.sendMessage({chat_id:chat.id,text:"⛔ Admin access denied."}); return; }564let adminRole=String(adminRecord.role||"support"), adminPerms=reRolePerms(adminRole);565function hasPerm(p){return adminPerms.includes(p);}566let authActions=["auth","auth_setpin","auth_login","auth_logout"];567let sessionOK=await reSessionOK(uid,adminRole);568if(!sessionOK && !authActions.includes(action||"")){569 show("🔐 <b>STAFF AUTHENTICATION REQUIRED</b>\n\nYour Telegram identity is authorized, but a valid second-factor session is required.",[[{text:"🔑 Login",callback_data:"admin_core auth_login"}],[{text:"⚙ Authentication",callback_data:"admin_core auth"}]]);return;570}571if (action === "auth") { let hash=String(await db.user.get("staff_pin_hash","")||""); let until=Number(await db.user.get("staff_session_until",0)||0); show("🔐 <b>STAFF AUTHENTICATION</b>\n\nRole: <b>"+reHtml(adminRole)+"</b>\nPIN configured: <b>"+(hash?"YES":"NO")+"</b>\nSession: <b>"+(until>Date.now()?"ACTIVE":"LOCKED")+"</b>",[[{text:hash?"🔄 Change PIN":"➕ Set PIN",callback_data:"admin_core auth_setpin"}],[{text:until>Date.now()?"🚪 Logout":"🔑 Login",callback_data:until>Date.now()?"admin_core auth_logout":"admin_core auth_login"}],[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return; }572if (action === "auth_setpin") { let hash=String(await db.user.get("staff_pin_hash","")||"");let active=Number(await db.user.get("staff_session_until",0)||0)>Date.now();if(hash&&!active){ack("Login with your current PIN before changing it.",true);await adminRouter("auth");return;}await db.user.set("input_mode","staff_set_pin"); show("🔐 <b>SET STAFF PIN</b>\n\nSend a new 6–12 digit PIN. It will be stored using bcrypt hashing.",[[{text:"‹ Authentication",callback_data:"admin_core auth"}]]);return; }573if (action === "auth_login") { let lock=Number(await db.user.get("staff_auth_lock_until",0)||0); if(lock>Date.now()){ack("Login temporarily locked after failed attempts.",true);return;} let hash=String(await db.user.get("staff_pin_hash","")||""); if(!hash){ack("Set a staff PIN first.",true);await adminRouter("auth");return;} await db.user.set("input_mode","staff_login_pin"); show("🔑 <b>STAFF LOGIN</b>\n\nSend your staff PIN as the next message.",[[{text:"‹ Authentication",callback_data:"admin_core auth"}]]);return; }574if (action === "auth_logout") { await db.user.del("staff_session_until"); await reAudit("staff_logout",uid,{role:adminRole},uid); await adminRouter("auth");return; }575 576function actionPerm(a){577 a=String(a||"home");578 if(a==="home"||a.startsWith("auth"))return "dashboard";579 if(a==="applications"||a.startsWith("app:"))return "applications";580 if(a.startsWith("approve:"))return "approve";581 if(a.startsWith("reject"))return "reject";582 if(a.startsWith("moreinfo")||a.startsWith("message:"))return "more_info";583 if(a.startsWith("override"))return "override";584 if(a==="members"||a.startsWith("member:")||a.startsWith("note:"))return "members";585 if(a.startsWith("reverify")||a==="reverifications")return "reverify";586 if(a==="blacklist"||a.startsWith("blacklist")||a.startsWith("unblacklist"))return "blacklist";587 if(a.startsWith("rule")||a==="rules")return "rules";588 if(a==="settings"||a.startsWith("setting:")||a.startsWith("toggle:"))return "settings";589 if(a==="assets"||a.startsWith("asset_")||a==="networks"||a.startsWith("network_"))return "assets";590 if(a==="p2p"||a.startsWith("p2p_"))return "p2p";591 if(a.startsWith("announcement")||a==="announcements")return "announcements";592 if(a==="alerts"||a.startsWith("alert_")||a.startsWith("risk_"))return "alerts";593 if(a.startsWith("maintenance")||a.startsWith("mt_"))return "maintenance";594 if(a==="analytics")return "analytics";595 if(a==="audit")return "audit";596 if(a==="backup"||a.startsWith("backup_")||a.startsWith("export_"))return "backup";597 if(a==="monitor_scan"||a==="wallets_admin"||a.startsWith("wallet_user:")||a.startsWith("evidence:")||a.startsWith("setcrypto:")||a.startsWith("setdeals:"))return "wallets";598 if(a==="admins"||a.startsWith("admin_"))return "admins";599 if(a==="system"||a.startsWith("system_")||a==="provider_test"||a==="production_check"||a==="worker_webhook")return "system";600 if(a==="lifecycle_scan")return "system";601 return "dashboard";602}603let __need=actionPerm(action);if(__need&&!hasPerm(__need)){ack("Your admin role does not allow this action.",true);return;}604 605if (!action || action === "home") {606 let [q,members,alerts,reverify] = await Promise.all([607 db.bot.get("application_queue", []), db.bot.get("member_registry", []),608 db.bot.get("alerts", []), db.bot.get("reverification_requests", [])609 ]);610 if (!Array.isArray(q)) q=[]; if (!Array.isArray(members)) members=[];611 if (!Array.isArray(alerts)) alerts=[]; if (!Array.isArray(reverify)) reverify=[];612 let pending = q.filter(x=>x && ["submitted","under_review","more_info_required"].includes(x.status)).length;613 let openAlerts = alerts.filter(x=>x && x.status!=="resolved").length;614 let openReverify = reverify.filter(x=>x && x.status!=="completed" && x.status!=="cancelled").length;615 show("🛡️ <b>RED EYE • COMMAND CENTER</b>\n\nPending applications: <b>"+pending+"</b>\nActive members: <b>"+members.filter(x=>x&&x.status!=="removed").length+"</b>\nOpen alerts: <b>"+openAlerts+"</b>\nRe-verifications: <b>"+openReverify+"</b>\n\nEligibility: <b>$"+Number(s.min_crypto_networth||1000)+" crypto / $"+Number(s.min_deal_volume||3000)+" deals</b>", [616 [{text:"📥 Applications ("+pending+")",callback_data:"admin_core applications"},{text:"👥 Members",callback_data:"admin_core members"}],617 [{text:"👛 Wallets",callback_data:"admin_core wallets_admin"},{text:"🔄 Re-verification",callback_data:"admin_core reverifications"}],618 [{text:"🚨 Alerts ("+openAlerts+")",callback_data:"admin_core alerts"},{text:"🚫 Blacklist",callback_data:"admin_core blacklist"}],619 [{text:"📜 Rules",callback_data:"admin_core rules"},{text:"🪙 Assets",callback_data:"admin_core assets"}],620 [{text:"📣 Announcements",callback_data:"admin_core announcements"},{text:"📊 Analytics",callback_data:"admin_core analytics"}],621 [{text:"⚙ Eligibility Settings",callback_data:"admin_core settings"},{text:"🛠 Maintenance",callback_data:"admin_core maintenance_page"}],622 [{text:"🧾 Audit Logs",callback_data:"admin_core audit"},{text:"💾 Backup / Export",callback_data:"admin_core backup"}],623 [{text:"⌛ Lifecycle Scan",callback_data:"admin_core lifecycle_scan"},{text:"👛 Wallet Monitoring",callback_data:"admin_core monitor_scan"}],624 [{text:"🌐 Networks",callback_data:"admin_core networks"},{text:"🔗 P2P Group Manager",callback_data:"admin_core p2p"}],625 [{text:"👮 Admins & Roles",callback_data:"admin_core admins"},{text:"🔐 Authentication",callback_data:"admin_core auth"}],626 [{text:"⚙ System Settings",callback_data:"admin_core system"}]627 ]);628 return;629}630 631if (action === "applications") {632 let q = await db.bot.get("application_queue", []); if (!Array.isArray(q)) q=[];633 let pending = q.filter(x=>x && ["submitted","under_review","more_info_required"].includes(x.status)).slice(-20).reverse();634 let rows = pending.map(x=>[{text:(x.first_name||x.username||String(x.user_id))+" • "+x.status,callback_data:"admin_core app:"+x.user_id}]);635 rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);636 show("📥 <b>APPLICATION CONTROL • REVIEW QUEUE</b>\n\nSelect an applicant to open the full verification file.", rows);637 return;638}639 640if (action.indexOf("app:") === 0) {641 let target = Number(action.split(":")[1]); if (!target) {ack("Invalid applicant",true);return;}642 await db.user.set("admin_selected_user", target);643 let [stRaw,acts,assets,wallets,proofs,own,cRaw,dRaw] = await Promise.all([644 db.user.get("application_status","",{user_id:target}), db.user.get("activities",[],{user_id:target}),645 db.user.get("assets",[],{user_id:target}), db.user.get("wallets",[],{user_id:target}),646 db.user.get("deal_proofs",[],{user_id:target}), db.user.get("ownership_proof",null,{user_id:target}),647 db.user.get("admin_verified_crypto",0,{user_id:target}), db.user.get("admin_verified_deals",0,{user_id:target})648 ]);649 let st=String(stRaw||""); if(!Array.isArray(acts)) acts=[]; if(!Array.isArray(assets)) assets=[];650 if(!Array.isArray(wallets)) wallets=[]; if(!Array.isArray(proofs)) proofs=[]; let c=Number(cRaw||0), d=Number(dRaw||0);651 await db.user.set("application_status", st === "submitted" ? "under_review" : st, {user_id:target});652 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(Number(x.user_id)===target&&x.status==="submitted")x.status="under_review";await db.bot.set("application_queue",q);}653 show("🧿 <b>APPLICATION INTELLIGENCE • REVIEW</b>\n\nUser ID: <code>"+target+"</code>\nStatus: <b>"+st+"</b>\nActivities: <b>"+acts.join(", ")+"</b>\nAssets: <b>"+assets.join(", ")+"</b>\nWallets: <b>"+wallets.length+"</b>\nOwnership proof: <b>"+(own?"Received":"Missing")+"</b>\nDeal proofs: <b>"+proofs.length+"</b>\n\nVerified crypto: <b>$"+c+"</b>\nVerified deals: <b>$"+d+"</b>", [654 [{text:"💰 Set Verified Crypto",callback_data:"admin_core setcrypto:"+target},{text:"📊 Set Verified Deals",callback_data:"admin_core setdeals:"+target}],655 [{text:"✅ Approve",callback_data:"admin_core approve:"+target},{text:"❌ Reject",callback_data:"admin_core reject:"+target}],656 [{text:"⚠ Reject Failed Criteria",callback_data:"admin_core reject_auto:"+target},{text:"✉ Message Applicant",callback_data:"admin_core message:"+target}],657 [{text:"📝 Request More Info",callback_data:"admin_core moreinfo:"+target},{text:"👛 Wallets / Proofs",callback_data:"admin_core evidence:"+target}],658 [{text:"⚡ Admin Override",callback_data:"admin_core override:"+target},{text:"🚫 Blacklist",callback_data:"admin_core blacklist_user:"+target}],659 [{text:"‹ Applications",callback_data:"admin_core applications"}]660 ]);661 return;662}663 664if (action.indexOf("setcrypto:")===0 || action.indexOf("setdeals:")===0) {665 let target=Number(action.split(":")[1]); await db.user.set("admin_selected_user",target); await db.user.set("input_mode",action.startsWith("setcrypto")?"admin_set_crypto":"admin_set_deals");666 show(action.startsWith("setcrypto")?"💰 <b>VERIFIED CRYPTO VALUE</b>\n\nSend the verified USD value as your next message.":"📊 <b>VERIFIED DEAL VOLUME</b>\n\nSend the verified total USD deal volume as your next message.", [[{text:"← Back",callback_data:"admin_core app:"+target}]]);667 return;668}669 670if (action.indexOf("approve:")===0) {671 let target=Number(action.split(":")[1]);672 let c=Number(await db.user.get("admin_verified_crypto",0,{user_id:target})||0), d=Number(await db.user.get("admin_verified_deals",0,{user_id:target})||0);673 let minC=Number(s.min_crypto_networth||1000), minD=Number(s.min_deal_volume||3000);674 if(c<minC){ack("Verified crypto must be at least $"+minC,true);return;} if(d<minD){ack("Verified deals must be at least $"+minD,true);return;}675 let old=String(await db.user.get("private_invite_link","",{user_id:target})); if(old){try{await Api.call("revokeChatInviteLink",{chat_id:PRIVATE_GROUP_ID,invite_link:old});}catch(e){}}676 let exp=Math.floor(Date.now()/1000)+3600;677 let r=await Api.call("createChatInviteLink",{chat_id:PRIVATE_GROUP_ID,name:"RED EYE • "+target,expire_date:exp,creates_join_request:true});678 if(!r||!r.ok||!r.result||!r.result.invite_link){ack("Could not create secure invite link.",true);return;}679 let link=r.result.invite_link;680 await db.user.set("application_status","approved",{user_id:target}); await db.user.set("approved_at",Date.now(),{user_id:target}); await db.user.set("approved_by",uid,{user_id:target}); await db.user.set("private_invite_link",link,{user_id:target});681 let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];682 let mi=members.findIndex(x=>x&&Number(x.user_id)===target);683 let prof=await db.user.get("telegram_profile",{}, {user_id:target});if(!prof||typeof prof!=="object")prof={};684 let memberRecord={user_id:target,username:prof.username||"",first_name:prof.first_name||"",status:"approved_pending_join",approved_at:Date.now(),verified_at:Date.now(),verified_crypto:c,verified_deals:d,updated_at:Date.now()};685 if(mi>=0) members[mi]=Object.assign({},members[mi],memberRecord); else members.push(memberRecord);686 await db.bot.set("member_registry",members);687 await db.user.set("member_status","approved_pending_join",{user_id:target});688 let invites=await db.bot.get("secure_invites",[]);if(!Array.isArray(invites))invites=[];invites.push({user_id:target,invite_link:link,expires_at:exp,used:false,created_at:Date.now()});await db.bot.set("secure_invites",invites);689 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(Number(x.user_id)===target){x.status="approved";x.reviewed_at=Date.now();x.reviewed_by=uid;}await db.bot.set("application_queue",q);}690 let ah2=await db.user.get("application_history",[],{user_id:target});if(!Array.isArray(ah2))ah2=[];ah2.push({application_id:String(await db.user.get("application_id","",{user_id:target})),status:"approved",at:Date.now(),by:uid});await db.user.set("application_history",ah2.slice(-50),{user_id:target});691 let vh2=await db.user.get("verification_history",[],{user_id:target});if(!Array.isArray(vh2))vh2=[];vh2.push({type:"initial",status:"approved",verified_crypto:c,verified_deals:d,at:Date.now(),by:uid});await db.user.set("verification_history",vh2.slice(-100),{user_id:target});692 await reAudit("application_approved",target,{verified_crypto:c,verified_deals:d},uid);693 await reNotify({chat_id:target,text:"✅ <b>APPLICATION APPROVED</b>\n\nYour RED EYE application has been approved. This private access link is authorized only for your Telegram account and expires in 1 hour.",parse_mode:"HTML",reply_markup:{inline_keyboard:[[{text:"🔐 Enter Private Community",url:link,style:"success"}],[{text:"📡 Live Status",callback_data:"user_core status",style:"primary"}]]}},"application_approved",target);694 ack("Approved and secure invite created.",false); Bot.runCommand("/handle_callback_query",{route:"admin_core app:"+target}); return;695}696 697if(action.indexOf("reject_auto:")===0){let target=Number(action.split(":")[1]),reasons=[];let c=Number(await db.user.get("admin_verified_crypto",0,{user_id:target})||0),d=Number(await db.user.get("admin_verified_deals",0,{user_id:target})||0),minC=Number(s.min_crypto_networth||1000),minD=Number(s.min_deal_volume||3000);if(c<minC)reasons.push("Verified crypto value is below $"+minC+".");if(d<minD)reasons.push("Verified deal volume is below $"+minD+".");let own=await db.user.get("ownership_proof",null,{user_id:target}),proofs=await db.user.get("deal_proofs",[],{user_id:target});if(!own)reasons.push("Wallet ownership proof is missing.");if(!Array.isArray(proofs)||!proofs.length)reasons.push("Deal-history proof is missing.");if(!reasons.length){ack("No failed automatic criterion is currently recorded. Use custom rejection if needed.",true);return;}await adminRouter("reject_do:"+target+":"+encodeURIComponent(reasons.join(" ")));return;}698if(action.indexOf("message:")===0){let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_custom_message");show("✉ <b>MESSAGE APPLICANT</b>\n\nSend the custom message as your next message.",[[{text:"‹ Cancel",callback_data:"admin_core app:"+target}]]);return;}699if (action.indexOf("reject:")===0) { let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_reject_reason");show("❌ <b>REJECTION REASON</b>\n\nSend the reason as your next message.",[[{text:"‹ Cancel",callback_data:"admin_core app:"+target}]]);return; }700if (action.indexOf("reject_do:")===0) {701 let p=action.split(":"),target=Number(p[1]),reason=decodeURIComponent(p.slice(2).join(":"));702 let count=Number(await db.user.get("rejection_count",0,{user_id:target})||0)+1; let hours=count>=5?Number(s.extended_cooldown_hours||24):Number(s.rejection_cooldown_hours||1); let reapply=Date.now()+hours*3600000;703 await db.user.set("application_status","rejected",{user_id:target});await db.user.set("rejection_reason",reason,{user_id:target});await db.user.set("rejection_count",count,{user_id:target});await db.user.set("rejected_at",Date.now(),{user_id:target});await db.user.set("reapply_after",reapply,{user_id:target});704 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(Number(x.user_id)===target){x.status="rejected";x.reviewed_at=Date.now();x.reviewed_by=uid;}await db.bot.set("application_queue",q);}705 let ah=await db.user.get("application_history",[],{user_id:target});if(!Array.isArray(ah))ah=[];ah.push({application_id:String(await db.user.get("application_id","",{user_id:target})),status:"rejected",reason:reason,at:Date.now(),by:uid});await db.user.set("application_history",ah.slice(-50),{user_id:target});await reAudit("application_rejected",target,{reason:reason,cooldown_hours:hours,rejection_count:count},uid);706 await reNotify({chat_id:target,text:"❌ <b>APPLICATION REJECTED</b>\n\nReason: "+reHtml(reason)+"\n\nReapply cooldown: <b>"+hours+" hour(s)</b>.",parse_mode:"HTML"},"application_rejected",target);707 await adminRouter("applications");return;708}709 710if (action.indexOf("moreinfo:")===0) {let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_more_info");show("📝 <b>REQUEST MORE INFORMATION</b>\n\nSend the exact message/question for the applicant.",[[{text:"‹ Cancel",callback_data:"admin_core app:"+target}]]);return;}711if (action.indexOf("moreinfo_do:")===0) {712 let p=action.split(":"),target=Number(p[1]),msg=decodeURIComponent(p.slice(2).join(":"));713 await db.user.set("application_status","more_info_required",{user_id:target});await db.user.set("more_info_request",msg,{user_id:target});await db.user.set("more_info_requested_at",Date.now(),{user_id:target});714 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(Number(x.user_id)===target)x.status="more_info_required";await db.bot.set("application_queue",q);}715 let ah=await db.user.get("application_history",[],{user_id:target});if(!Array.isArray(ah))ah=[];ah.push({application_id:String(await db.user.get("application_id","",{user_id:target})),status:"more_info_required",message:msg,at:Date.now(),by:uid});await db.user.set("application_history",ah.slice(-50),{user_id:target});await reAudit("application_more_info_requested",target,{message:msg},uid);716 await reNotify({chat_id:target,text:"📝 <b>MORE INFORMATION REQUIRED</b>\n\n"+reHtml(msg),parse_mode:"HTML",reply_markup:{inline_keyboard:[[{text:"📝 Provide Information",callback_data:"user_core more_info",style:"success"}],[{text:"📡 Live Status",callback_data:"user_core status",style:"primary"}]]}},"more_info_required",target);717 Bot.runCommand("/handle_callback_query",{route:"admin_core app:"+target});return;718}719 720if (action === "settings") {721 if(!hasPerm("settings")){ack("Permission denied.",true);return;}722 let defs=[723 ["Minimum Crypto","min_crypto_networth",s.min_crypto_networth||1000],["Minimum Deals","min_deal_volume",s.min_deal_volume||3000],724 ["Low Wallet Threshold","low_wallet_threshold",s.low_wallet_threshold||500],["Low Wallet Clear","low_wallet_clear_threshold",s.low_wallet_clear_threshold||600],["Low Wallet Days","low_wallet_duration_days",s.low_wallet_duration_days||7],725 ["Normal Cooldown Hours","rejection_cooldown_hours",s.rejection_cooldown_hours||1],["Extended Cooldown Hours","extended_cooldown_hours",s.extended_cooldown_hours||24],726 ["Reminder Minutes","application_reminder_minutes",s.application_reminder_minutes||60],["Expiry Hours","application_expiry_hours",s.application_expiry_hours||24],["Verification Expiry Days","verification_expiry_days",s.verification_expiry_days||30]727 ];728 let rows=defs.map(d=>[{text:d[0]+": "+d[2],callback_data:"admin_core setting:"+d[1]}]);729 rows.push([{text:"Premium: "+(s.premium_required===false?"OFF":"ON"),callback_data:"admin_core toggle:premium_required"},{text:"Username: "+(s.username_required===false?"OFF":"ON"),callback_data:"admin_core toggle:username_required"}]);730 rows.push([{text:"18+: "+(s.age_required===false?"OFF":"ON"),callback_data:"admin_core toggle:age_required"},{text:"Multi Wallets: "+(s.multiple_wallets_allowed===false?"OFF":"ON"),callback_data:"admin_core toggle:multiple_wallets_allowed"}]);731 rows.push([{text:"Multi Assets: "+(s.multiple_assets_allowed===false?"OFF":"ON"),callback_data:"admin_core toggle:multiple_assets_allowed"},{text:"Verification Expiry: "+(s.verification_expiry_enabled===true?"ON":"OFF"),callback_data:"admin_core toggle:verification_expiry_enabled"}]);732 rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);733 show("⚙ <b>ELIGIBILITY & LIFECYCLE SETTINGS</b>\n\nAll important thresholds and requirements are database-configurable.",rows);return;734}735if (action.indexOf("setting:")===0){if(!hasPerm("settings")){ack("Permission denied.",true);return;}let key=action.slice(8);await db.user.set("input_mode","admin_setting_"+key);show("⚙ <b>UPDATE SETTING</b>\n\nSend the new numeric value as your next message.",[[{text:"← Back",callback_data:"admin_core settings"}]]);return;}736if(action.indexOf("toggle:")===0){if(!hasPerm("settings")){ack("Permission denied.",true);return;}let key=action.slice(7),allowed=["premium_required","username_required","age_required","multiple_wallets_allowed","multiple_assets_allowed","verification_expiry_enabled"];if(!allowed.includes(key)){ack("Unknown setting.",true);return;}let old=s[key];s[key]=!(old===true);if(typeof old==="undefined")s[key]=false;await db.bot.set("system_settings",s);await reAudit("setting_toggled",0,{key:key,old:old,new_value:s[key]},uid);await adminRouter("settings");return;}737 738if (action === "maintenance") {s.maintenance_applications_paused=!s.maintenance_applications_paused;await db.bot.set("system_settings",s);ack(s.maintenance_applications_paused?"New applications paused.":"New applications resumed.",false);await adminRouter("home");return;}739 740if (action.indexOf("evidence:")===0) {741 let target=Number(action.split(":")[1]);742 let wallets=await db.user.get("wallets",[],{user_id:target}); if(!Array.isArray(wallets))wallets=[];743 let proofs=await db.user.get("deal_proofs",[],{user_id:target}); if(!Array.isArray(proofs))proofs=[];744 let own=await db.user.get("ownership_proof",null,{user_id:target});745 let body=wallets.length?wallets.map((w,i)=>(i+1)+". <b>"+reHtml(w.asset)+"</b> • "+reHtml(w.network)+"\n<code>"+reHtml(w.address)+"</code>").join("\n\n"):"No wallets submitted.";746 let rows=[]; if(own)rows.push([{text:"🎥 Open Ownership Proof",callback_data:"admin_core evidence_file:"+target+":ownership:0"}]); for(let i=0;i<proofs.length;i++)rows.push([{text:"📊 Open Deal Proof #"+(i+1),callback_data:"admin_core evidence_file:"+target+":deal:"+i}]); rows.push([{text:"‹ Application",callback_data:"admin_core app:"+target}]);747 show("👛 <b>WALLETS & PROOFS</b>\n\n"+body+"\n\nOwnership proof: <b>"+(own?"Received":"Missing")+"</b>\nDeal proofs: <b>"+proofs.length+"</b>\n\nProof files remain referenced by Telegram file ID and are only sent to authorized staff on request.",rows);return;748}749if(action.indexOf("evidence_file:")===0){750 let p=action.split(":"),target=Number(p[1]),kind=String(p[2]),index=Number(p[3]||0),item=null;if(kind==="ownership")item=await db.user.get("ownership_proof",null,{user_id:target});else{let arr=await db.user.get("deal_proofs",[],{user_id:target});if(Array.isArray(arr))item=arr[index];}if(!item||!item.file_id){ack("Proof file not found.",true);return;}let method=item.type==="photo"?"sendPhoto":item.type==="video"?"sendVideo":item.type==="animation"?"sendAnimation":"sendDocument",key=item.type==="photo"?"photo":item.type==="video"?"video":item.type==="animation"?"animation":"document",payload={chat_id:chat.id,caption:"RED EYE proof • user "+target};payload[key]=item.file_id;await Api.call(method,payload);ack("Proof sent below.",false);return;751}752 753if (action.indexOf("override:")===0) { let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_override_reason");show("⚡ <b>ADMIN OVERRIDE</b>\n\nThis bypasses eligibility thresholds for an exceptional case. Send the mandatory override reason as your next message.",[[{text:"‹ Cancel",callback_data:"admin_core app:"+target}]]);return; }754if (action.indexOf("override_do:")===0) {755 let p=action.split(":"),target=Number(p[1]),reason=decodeURIComponent(p.slice(2).join(":"));756 let old=String(await db.user.get("private_invite_link","",{user_id:target}));if(old){try{await Api.call("revokeChatInviteLink",{chat_id:PRIVATE_GROUP_ID,invite_link:old});}catch(e){}}757 let exp=Math.floor(Date.now()/1000)+3600;let r=await Api.call("createChatInviteLink",{chat_id:PRIVATE_GROUP_ID,name:"RED EYE OVERRIDE • "+target,expire_date:exp,creates_join_request:true});758 if(!r||!r.ok||!r.result||!r.result.invite_link){ack("Could not create invite.",true);return;} let link=r.result.invite_link;759 await db.user.set("application_status","approved",{user_id:target});await db.user.set("approved_at",Date.now(),{user_id:target});await db.user.set("approved_by",uid,{user_id:target});await db.user.set("admin_override_reason",reason,{user_id:target});await db.user.set("private_invite_link",link,{user_id:target});await db.user.set("member_status","approved_pending_join",{user_id:target});760 let invites=await db.bot.get("secure_invites",[]);if(!Array.isArray(invites))invites=[];invites.push({user_id:target,invite_link:link,expires_at:exp,used:false,override:true,created_at:Date.now()});await db.bot.set("secure_invites",invites);761 let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let i=members.findIndex(x=>x&&Number(x.user_id)===target);let mr={user_id:target,status:"approved_pending_join",approved_at:Date.now(),verified_at:Date.now(),override_reason:reason,updated_at:Date.now()};if(i>=0)members[i]=Object.assign({},members[i],mr);else members.push(mr);await db.bot.set("member_registry",members);762 let q=await db.bot.get("application_queue",[]);if(Array.isArray(q)){for(let x of q)if(Number(x.user_id)===target){x.status="approved";x.reviewed_at=Date.now();x.reviewed_by=uid;x.override=true;}await db.bot.set("application_queue",q);}763 let ah=await db.user.get("application_history",[],{user_id:target});if(!Array.isArray(ah))ah=[];ah.push({application_id:String(await db.user.get("application_id","",{user_id:target})),status:"approved_override",reason:reason,at:Date.now(),by:uid});await db.user.set("application_history",ah.slice(-50),{user_id:target});764 let vh=await db.user.get("verification_history",[],{user_id:target});if(!Array.isArray(vh))vh=[];vh.push({type:"admin_override",status:"approved",reason:reason,at:Date.now(),by:uid});await db.user.set("verification_history",vh.slice(-100),{user_id:target});765 await reAudit("admin_override_approval",target,{reason:reason},uid);766 await reNotify({chat_id:target,text:"✅ <b>APPLICATION APPROVED</b>\n\nYour application was approved by an administrator. Your personal access link expires in 1 hour.",parse_mode:"HTML",reply_markup:{inline_keyboard:[[{text:"🔐 Enter Private Community",url:link,style:"success"}]]}},"application_override_approved",target);Bot.runCommand("/handle_callback_query",{route:"admin_core app:"+target});return;767}768 769if(action==="wallets_admin"){let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let rows=[];for(let m of members.slice(-40).reverse()){if(!m||!m.user_id)continue;let total=Number(await db.user.get("auto_verified_crypto_total",0,{user_id:Number(m.user_id)})||0);rows.push([{text:String(m.user_id)+" • $"+total.toFixed(2),callback_data:"admin_core wallet_user:"+m.user_id}]);}rows.push([{text:"↻ Run Monitoring Scan",callback_data:"admin_core monitor_scan"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("👛 <b>MEMBER WALLETS</b>\n\nSelect a member. Values shown are latest automatic public checks; admin-verified values remain separate.",rows);return;}770if(action.indexOf("wallet_user:")===0){let target=Number(action.split(":")[1]),wallets=await db.user.get("wallets",[],{user_id:target});if(!Array.isArray(wallets))wallets=[];let hist=await db.user.get("wallet_history",[],{user_id:target});if(!Array.isArray(hist))hist=[];let body=wallets.map((w,i)=>{let av=w.auto_verification||{};return (i+1)+". <b>"+reHtml(w.asset)+"</b> • "+reHtml(w.network)+"\n<code>"+reHtml(w.address)+"</code>\n"+(av.ok?("$"+Number(av.usd_value||0).toFixed(2)+" • verified public data"):reHtml(av.status||"pending"));}).join("\n\n")||"No current wallets.";show("👛 <b>MEMBER WALLETS</b>\n\nUser: <code>"+target+"</code>\nArchived history: <b>"+hist.length+"</b>\n\n"+body,[[{text:"‹ Member",callback_data:"admin_core member:"+target}]]);return;}771 772if (action === "members") {773 let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let list=members.filter(x=>x&&x.status!=="removed").slice(-30).reverse();let rows=list.map(x=>[{text:String(x.user_id)+" • "+String(x.status||"active"),callback_data:"admin_core member:"+x.user_id}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("👥 <b>MEMBERS</b>\n\nSelect a member.",rows);return;774}775if (action.indexOf("member:")===0) {776 let target=Number(action.split(":")[1]);let status=String(await db.user.get("member_status","active",{user_id:target}));let c=Number(await db.user.get("admin_verified_crypto",0,{user_id:target})||0),d=Number(await db.user.get("admin_verified_deals",0,{user_id:target})||0),auto=Number(await db.user.get("auto_verified_crypto_total",0,{user_id:target})||0);let wallets=await db.user.get("wallets",[],{user_id:target});if(!Array.isArray(wallets))wallets=[];let notes=await db.user.get("admin_notes",[],{user_id:target});if(!Array.isArray(notes))notes=[];let rv=String(await db.user.get("reverification_status","",{user_id:target})),joined=Number(await db.user.get("community_joined_at",0,{user_id:target})||0),alerts=await db.bot.get("alerts",[]);if(!Array.isArray(alerts))alerts=[];let ac=alerts.filter(a=>a&&Number(a.user_id)===target&&a.status!=="resolved").length;let prof=await db.user.get("telegram_profile",{},{user_id:target});if(!prof||typeof prof!=="object")prof={};let ah=await db.user.get("application_history",[],{user_id:target});if(!Array.isArray(ah))ah=[];let vh=await db.user.get("verification_history",[],{user_id:target});if(!Array.isArray(vh))vh=[];777 let rows=[[{text:"👛 Wallets",callback_data:"admin_core wallet_user:"+target},{text:"📋 Application",callback_data:"admin_core app:"+target}],[{text:"🔄 Request Re-verification",callback_data:"admin_core reverify:"+target},{text:"🚫 Blacklist",callback_data:"admin_core blacklist_user:"+target}],[{text:"📝 Add Note",callback_data:"admin_core note:"+target}]];778 if(rv==="submitted")rows.push([{text:"✅ Complete Re-verification",callback_data:"admin_core reverify_complete:"+target},{text:"✕ Cancel",callback_data:"admin_core reverify_cancel:"+target}]);779 rows.push([{text:"‹ Members",callback_data:"admin_core members"}]);780 show("👤 <b>MEMBER PROFILE</b>\n\nUser ID: <code>"+target+"</code>\nTelegram: <b>"+reHtml(prof.first_name||"")+"</b> "+(prof.username?("@"+reHtml(prof.username)):"—")+"\nStatus: <b>"+reHtml(status)+"</b>\nJoined: <b>"+(joined?new Date(joined).toISOString():"Pending/unknown")+"</b>\nVerified crypto (admin): <b>$"+c+"</b>\nAutomatic public total: <b>$"+auto.toFixed(2)+"</b>\nVerified deals: <b>$"+d+"</b>\nWallets: <b>"+wallets.length+"</b>\nVerification history: <b>"+vh.length+"</b>\nApplication history: <b>"+ah.length+"</b>\nOpen alerts: <b>"+ac+"</b>\nNotes: <b>"+notes.length+"</b>\nRe-verification: <b>"+reHtml(rv||"none")+"</b>",rows);return;781}782if (action.indexOf("note:")===0){let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_member_note");show("📝 <b>MEMBER NOTE</b>\n\nSend the private admin note.",[[{text:"‹ Cancel",callback_data:"admin_core member:"+target}]]);return;}783if (action.indexOf("reverify:")===0){let target=Number(action.split(":")[1]);show("🔄 <b>RE-VERIFICATION TYPE</b>",[[{text:"Wallet Only",callback_data:"admin_core reverify_do:"+target+":wallet"},{text:"Deal History",callback_data:"admin_core reverify_do:"+target+":deals"}],[{text:"Ownership Proof",callback_data:"admin_core reverify_do:"+target+":ownership"},{text:"Full Verification",callback_data:"admin_core reverify_do:"+target+":full"}],[{text:"‹ Member",callback_data:"admin_core member:"+target}]]);return;}784if (action.indexOf("reverify_do:")===0){let p=action.split(":"),target=Number(p[1]),type=String(p[2]||"full");let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];let id="RV-"+target+"-"+Date.now();rr.push({id:id,user_id:target,type:type,status:"requested",requested_at:Date.now(),requested_by:uid});await db.bot.set("reverification_requests",rr);await db.user.set("reverification_status","requested",{user_id:target});await db.user.set("reverification_type",type,{user_id:target});await reNotify({chat_id:target,text:"🔄 <b>RE-VERIFICATION REQUESTED</b>\n\nType: <b>"+reHtml(type.toUpperCase())+"</b>\n\nOpen /start and use Application Status to continue. An administrator requested updated verification evidence.",parse_mode:"HTML"},"reverification_requested",target);ack("Re-verification requested.",false);Bot.runCommand("/handle_callback_query",{route:"admin_core member:"+target});return;}785if(action.indexOf("reverify_complete:")===0){let target=Number(action.split(":")[1]),type=String(await db.user.get("reverification_type","full",{user_id:target}));await db.user.set("reverification_status","completed",{user_id:target});if(type==="wallet"||type==="full")await db.user.del("wallet_change_pending",{user_id:target});await db.user.set("reverification_completed_at",Date.now(),{user_id:target});let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];for(let x of rr)if(x&&Number(x.user_id)===target&&!['completed','cancelled'].includes(String(x.status))){x.status="completed";x.completed_at=Date.now();x.completed_by=uid;}await db.bot.set("reverification_requests",rr);let vh=await db.user.get("verification_history",[],{user_id:target});if(!Array.isArray(vh))vh=[];vh.push({type:type,status:"completed",at:Date.now(),by:uid});await db.user.set("verification_history",vh.slice(-100),{user_id:target});let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let mi=members.findIndex(x=>x&&Number(x.user_id)===target);if(mi>=0){members[mi].verified_at=Date.now();members[mi].updated_at=Date.now();await db.bot.set("member_registry",members);}await reAudit("reverification_completed",target,{type:type},uid);await reNotify({chat_id:target,text:"✅ <b>RE-VERIFICATION COMPLETED</b>\n\nYour updated verification has been accepted.",parse_mode:"HTML"},"reverification_completed",target);await adminRouter("member:"+target);return;}786if(action.indexOf("reverify_cancel:")===0){let target=Number(action.split(":")[1]);await db.user.set("reverification_status","cancelled",{user_id:target});let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];for(let x of rr)if(x&&Number(x.user_id)===target&&!['completed','cancelled'].includes(String(x.status))){x.status="cancelled";x.cancelled_at=Date.now();x.cancelled_by=uid;}await db.bot.set("reverification_requests",rr);await reAudit("reverification_cancelled",target,{},uid);await adminRouter("member:"+target);return;}787if (action === "reverifications"){let rr=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rr))rr=[];let open=rr.filter(x=>x&&!["completed","cancelled"].includes(x.status)).slice(-30).reverse();let rows=open.map(x=>[{text:String(x.user_id)+" • "+String(x.type)+" • "+String(x.status),callback_data:"admin_core member:"+x.user_id}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🔄 <b>RE-VERIFICATIONS</b>\n\nOpen requests: <b>"+open.length+"</b>",rows);return;}788 789if (action === "blacklist") {let bl=await db.bot.get("blacklist",[]);if(!Array.isArray(bl))bl=[];let rows=bl.slice(-30).reverse().map(x=>[{text:String(x.user_id)+" • Remove",callback_data:"admin_core unblacklist:"+x.user_id}]);rows.unshift([{text:"+ Add User",callback_data:"admin_core blacklist_add"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🚫 <b>BLACKLIST</b>\n\nBlocked users: <b>"+bl.length+"</b>",rows);return;}790if (action === "blacklist_add"){await db.user.set("input_mode","admin_blacklist_id");show("🚫 <b>BLACKLIST USER</b>\n\nSend the Telegram numeric user ID.",[[{text:"← Back",callback_data:"admin_core blacklist"}]]);return;}791if (action.indexOf("blacklist_user:")===0){let target=Number(action.split(":")[1]);await db.user.set("admin_selected_user",target);await db.user.set("input_mode","admin_blacklist_reason");show("🚫 <b>BLACKLIST REASON</b>\n\nSend the reason for user <code>"+target+"</code>.",[[{text:"‹ Cancel",callback_data:"admin_core member:"+target}]]);return;}792if (action.indexOf("unblacklist:")===0){let target=Number(action.split(":")[1]);let bl=await db.bot.get("blacklist",[]);if(!Array.isArray(bl))bl=[];let rec=bl.find(x=>x&&Number(x.user_id)===target)||{};bl=bl.filter(x=>Number(x.user_id)!==target);await db.bot.set("blacklist",bl);let prevApp=String(await db.user.get("pre_blacklist_application_status","",{user_id:target})||rec.previous_application_status||"not_started"),prevMember=String(await db.user.get("pre_blacklist_member_status","",{user_id:target})||rec.previous_member_status||"");await db.user.set("application_status",prevApp||"not_started",{user_id:target});if(prevMember)await db.user.set("member_status",prevMember,{user_id:target});else await db.user.del("member_status",{user_id:target});let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];for(let m of members)if(m&&Number(m.user_id)===target){m.status=String(m.pre_blacklist_status||prevMember||"active");delete m.pre_blacklist_status;m.updated_at=Date.now();}await db.bot.set("member_registry",members);await db.user.del("pre_blacklist_application_status",{user_id:target});await db.user.del("pre_blacklist_member_status",{user_id:target});await db.user.del("blacklist_reason",{user_id:target});await reAudit("user_unblacklisted",target,{restored_application_status:prevApp,restored_member_status:prevMember},uid);ack("Removed from blacklist.",false);await adminRouter("blacklist");return;}793 794if (action === "rules"){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let rules=await db.bot.get("rules",[]);if(!Array.isArray(rules))rules=[];let rows=rules.map((r,i)=>[{text:(r.enabled===false?"○ ":"✓ ")+(i+1)+". "+String(r.title||"Rule").slice(0,28),callback_data:"admin_core rule_view:"+i}]);rows.unshift([{text:"+ Add Rule",callback_data:"admin_core rule_add"}]);rows.push([{text:"📚 Version History",callback_data:"admin_core rule_history"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("📜 <b>COMMUNITY RULES</b>\n\nRules can be added, edited, enabled/disabled, reordered and deleted. Every change is written to history/audit.",rows);return;}795if (action === "rule_add"){if(!hasPerm("rules")){ack("Permission denied.",true);return;}await db.user.set("input_mode","admin_rule_add");show("+ <b>ADD RULE</b>\n\nSend: <code>Category | Title | Full rule text</code>\nCategories: General, P2P, OTC, NFT, Advertising, DM, Scam/Fraud, Conduct",[[{text:"← Back",callback_data:"admin_core rules"}]]);return;}796if (action.indexOf("rule_view:")===0){let i=Number(action.split(":")[1]);let rules=await db.bot.get("rules",[]);if(!Array.isArray(rules)||!rules[i]){ack("Rule not found",true);return;}let r=rules[i];show("📜 <b>RULE #"+(i+1)+"</b>\n\nCategory: <b>"+reHtml(r.category||"General")+"</b>\nTitle: <b>"+reHtml(r.title||"Rule")+"</b>\nStatus: <b>"+(r.enabled===false?"DISABLED":"ENABLED")+"</b>\nVersion: <b>"+Number(r.version||1)+"</b>\n\n"+reHtml(r.text||""),[[{text:r.enabled===false?"✅ Enable":"⏸ Disable",callback_data:"admin_core rule_toggle:"+i}],[{text:"✏ Edit Title",callback_data:"admin_core rule_edit_title:"+i},{text:"✏ Edit Text",callback_data:"admin_core rule_edit_text:"+i}],[{text:"⬆ Move Up",callback_data:"admin_core rule_up:"+i},{text:"⬇ Move Down",callback_data:"admin_core rule_down:"+i}],[{text:"🗑 Delete",callback_data:"admin_core rule_delete:"+i}],[{text:"‹ Rules",callback_data:"admin_core rules"}]]);return;}797if (action.indexOf("rule_toggle:")===0){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let i=Number(action.split(":")[1]);let rules=await db.bot.get("rules",[]);if(!Array.isArray(rules)||!rules[i]){ack("Rule not found",true);return;}let old=rules[i].enabled!==false;rules[i].enabled=!old;rules[i].version=Number(rules[i].version||1)+1;rules[i].updated_at=Date.now();rules[i].updated_by=uid;await db.bot.set("rules",rules);let h=await db.bot.get("rule_history",[]);if(!Array.isArray(h))h=[];h.push({rule_id:rules[i].id,change:"toggle",old_value:old,new_value:!old,version:rules[i].version,by:uid,at:Date.now()});await db.bot.set("rule_history",h.slice(-500));await reAudit("rule_toggled",0,{rule_id:rules[i].id,enabled:!old},uid);await adminRouter("rule_view:"+i);return;}798if (action.indexOf("rule_edit_title:")===0||action.indexOf("rule_edit_text:")===0){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let i=Number(action.split(":")[1]);await db.user.set("admin_selected_rule",i);await db.user.set("input_mode",action.startsWith("rule_edit_title")?"admin_rule_edit_title":"admin_rule_edit_text");show("✏ <b>EDIT RULE</b>\n\nSend the new "+(action.startsWith("rule_edit_title")?"title":"rule text")+" as your next message.",[[{text:"‹ Cancel",callback_data:"admin_core rule_view:"+i}]]);return;}799if (action.indexOf("rule_up:")===0||action.indexOf("rule_down:")===0){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let i=Number(action.split(":")[1]),rules=await db.bot.get("rules",[]);if(!Array.isArray(rules)||!rules[i]){ack("Rule not found",true);return;}let j=action.startsWith("rule_up")?i-1:i+1;if(j<0||j>=rules.length){ack("Already at edge.",false);return;}let t=rules[i];rules[i]=rules[j];rules[j]=t;await db.bot.set("rules",rules);await reAudit("rule_reordered",0,{from:i,to:j},uid);await adminRouter("rules");return;}800if (action.indexOf("rule_delete:")===0){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let i=Number(action.split(":")[1]);show("🗑 <b>DELETE RULE?</b>\n\nThis removes the active rule but keeps history/audit records.",[[{text:"✅ Delete",callback_data:"admin_core rule_delete_do:"+i},{text:"✕ Cancel",callback_data:"admin_core rule_view:"+i}]]);return;}801if (action.indexOf("rule_delete_do:")===0){if(!hasPerm("rules")){ack("Permission denied.",true);return;}let i=Number(action.split(":")[1]),rules=await db.bot.get("rules",[]);if(!Array.isArray(rules)||!rules[i]){ack("Rule not found",true);return;}let old=rules.splice(i,1)[0];await db.bot.set("rules",rules);let h=await db.bot.get("rule_history",[]);if(!Array.isArray(h))h=[];h.push({rule_id:old.id,change:"deleted",snapshot:old,by:uid,at:Date.now()});await db.bot.set("rule_history",h.slice(-500));await reAudit("rule_deleted",0,{rule_id:old.id,title:old.title},uid);await adminRouter("rules");return;}802if (action === "rule_history"){let h=await db.bot.get("rule_history",[]);if(!Array.isArray(h))h=[];let b=h.slice(-15).reverse().map(x=>"• <b>"+reHtml(x.change||"change")+"</b> • "+reHtml(x.rule_id||"")+" • <code>"+new Date(Number(x.at||Date.now())).toISOString()+"</code>").join("\n")||"No history yet.";show("📚 <b>RULE VERSION HISTORY</b>\n\n"+b,[[{text:"‹ Rules",callback_data:"admin_core rules"}]]);return;}803 804if (action === "assets"){let assets=Array.isArray(s.featured_assets)?s.featured_assets:["USDT","SOL","ETH","BTC","TON"];let rows=assets.map(a=>[{text:"− "+a,callback_data:"admin_core asset_remove:"+a}]);rows.unshift([{text:"+ Add Featured Asset",callback_data:"admin_core asset_add"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🪙 <b>FEATURED ASSETS</b>\n\nThese appear in the applicant asset selector. Other cryptocurrencies are still allowed for manual review.",rows);return;}805if (action === "asset_add"){await db.user.set("input_mode","admin_asset_add");show("🪙 <b>ADD FEATURED ASSET</b>\n\nSend the symbol, e.g. <code>AVAX</code>.",[[{text:"← Back",callback_data:"admin_core assets"}]]);return;}806if (action.indexOf("asset_remove:")===0){let a=action.slice(13).toUpperCase();let assets=Array.isArray(s.featured_assets)?s.featured_assets:["USDT","SOL","ETH","BTC","TON"];s.featured_assets=assets.filter(x=>String(x).toUpperCase()!==a);await db.bot.set("system_settings",s);await reAudit("asset_removed",0,{symbol:a},uid);await adminRouter("assets");return;}807 808if (action === "announcements"){await db.user.set("input_mode","admin_announcement");show("📣 <b>ANNOUNCEMENT</b>\n\nSend the announcement text as your next message. It will be broadcast only after a confirmation button.",[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}809if (action === "announcement_confirm"){let text=String(await db.user.get("pending_announcement",""));if(!text){ack("No pending announcement",true);return;}let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let sent=0,queued=0;for(let m of members){if(!m||!m.user_id||["removed","blacklisted"].includes(String(m.status)))continue;let ok=await reNotify({chat_id:Number(m.user_id),text:"📣 <b>RED EYE ANNOUNCEMENT</b>\n\n"+text,parse_mode:"HTML"},"announcement",Number(m.user_id));if(ok)sent++;else queued++;}await db.user.del("pending_announcement");let hist=await db.bot.get("announcements",[]);if(!Array.isArray(hist))hist=[];hist.push({text:text,sent_at:Date.now(),sent_by:uid,delivered_now:sent,retry_queued:queued});await db.bot.set("announcements",hist.slice(-100));await reAudit("announcement_sent",0,{delivered_now:sent,retry_queued:queued},uid);show("✅ <b>ANNOUNCEMENT PROCESSED</b>\n\nDelivered now: <b>"+sent+"</b>\nQueued for safe retry: <b>"+queued+"</b>",[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}810if (action === "announcement_cancel"){await db.user.del("pending_announcement");await adminRouter("home");return;}811 812if (action === "alerts"){let alerts=await db.bot.get("alerts",[]);if(!Array.isArray(alerts))alerts=[];let flags=await db.bot.get("risk_flags",[]);if(!Array.isArray(flags))flags=[];let open=alerts.filter(x=>x&&x.status!=="resolved").slice(-30).reverse(),openFlags=flags.filter(x=>x&&x.status!=="resolved").length;let rows=open.map((x,i)=>[{text:(x.type||"Alert")+" • "+String(x.user_id||"system"),callback_data:"admin_core alert_resolve:"+String(x.id||i)}]);rows.unshift([{text:"⚑ Risk Flags ("+openFlags+")",callback_data:"admin_core risk_flags"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🚨 <b>ALERTS</b>\n\nOpen alerts: <b>"+open.length+"</b>\nRisk flags: <b>"+openFlags+"</b>\n\nRisk flags are review signals only and never automatically label or remove a member.",rows);return;}813if(action==="risk_flags"){let f=await db.bot.get("risk_flags",[]);if(!Array.isArray(f))f=[];let open=f.filter(x=>x&&x.status!=="resolved").slice(-30).reverse();let rows=open.map(x=>[{text:String(x.type||"Risk")+" • "+String(x.user_id||""),callback_data:"admin_core risk_resolve:"+String(x.id)}]);rows.push([{text:"‹ Alerts",callback_data:"admin_core alerts"}]);show("⚑ <b>RISK FLAGS</b>\n\nSignals for admin review: <b>"+open.length+"</b>\n\nNo risk flag causes automatic rejection/removal.",rows);return;}814if(action.indexOf("risk_resolve:")===0){let id=action.slice(13),f=await db.bot.get("risk_flags",[]);if(!Array.isArray(f))f=[];for(let x of f)if(x&&String(x.id)===id){x.status="resolved";x.resolved_at=Date.now();x.resolved_by=uid;}await db.bot.set("risk_flags",f);await reAudit("risk_flag_resolved",0,{id:id},uid);await adminRouter("risk_flags");return;}815if (action.indexOf("alert_resolve:")===0){let id=action.slice(14);let alerts=await db.bot.get("alerts",[]);if(!Array.isArray(alerts))alerts=[];for(let a of alerts)if(String(a.id)===id){a.status="resolved";a.resolved_at=Date.now();a.resolved_by=uid;}await db.bot.set("alerts",alerts);await reAudit("alert_resolved",0,{id:id},uid);await adminRouter("alerts");return;}816 817if (action === "maintenance_page"){show("🛠 <b>MAINTENANCE</b>\n\nNew applications: <b>"+(s.maintenance_applications_paused?"PAUSED":"OPEN")+"</b>\nWallet changes: <b>"+(s.maintenance_wallet_changes_paused?"PAUSED":"OPEN")+"</b>\nRe-verification: <b>"+(s.maintenance_reverification_paused?"PAUSED":"OPEN")+"</b>",[[{text:"Toggle Applications",callback_data:"admin_core mt_app"}],[{text:"Toggle Wallet Changes",callback_data:"admin_core mt_wallet"}],[{text:"Toggle Re-verification",callback_data:"admin_core mt_reverify"}],[{text:"✏ Maintenance Message",callback_data:"admin_core mt_message"}],[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}818if (["mt_app","mt_wallet","mt_reverify"].includes(action)){if(action==="mt_app")s.maintenance_applications_paused=!s.maintenance_applications_paused;if(action==="mt_wallet")s.maintenance_wallet_changes_paused=!s.maintenance_wallet_changes_paused;if(action==="mt_reverify")s.maintenance_reverification_paused=!s.maintenance_reverification_paused;await db.bot.set("system_settings",s);await reAudit("maintenance_toggle",0,{action:action,value:action==="mt_app"?s.maintenance_applications_paused:action==="mt_wallet"?s.maintenance_wallet_changes_paused:s.maintenance_reverification_paused},uid);await adminRouter("maintenance_page");return;}819if (action === "mt_message"){await db.user.set("input_mode","admin_maintenance_message");show("✏ <b>MAINTENANCE MESSAGE</b>\n\nSend the message applicants should see while applications are paused.",[[{text:"← Back",callback_data:"admin_core maintenance_page"}]]);return;}820 821if (action === "analytics"){let q=await db.bot.get("application_queue",[]);if(!Array.isArray(q))q=[];let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let count={};for(let x of q)if(x)count[x.status]=(count[x.status]||0)+1;show("📊 <b>ANALYTICS</b>\n\nApplications total: <b>"+q.length+"</b>\nSubmitted/review: <b>"+((count.submitted||0)+(count.under_review||0))+"</b>\nApproved: <b>"+(count.approved||0)+"</b>\nRejected: <b>"+(count.rejected||0)+"</b>\nAbandoned: <b>"+(count.abandoned||0)+"</b>\nMembers: <b>"+members.length+"</b>",[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}822if (action === "audit"){let logs=await db.bot.get("audit_logs",[]);if(!Array.isArray(logs))logs=[];let recent=logs.slice(-15).reverse();let body=recent.length?recent.map(x=>"• <b>"+String(x.action||"event")+"</b> • "+String(x.target_user_id||"")+"\n<code>"+new Date(Number(x.at||Date.now())).toISOString()+"</code>").join("\n\n"):"No audit records yet.";show("🧾 <b>AUDIT LOGS</b>\n\n"+body,[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}823if (action === "backup"){let backups=await db.bot.get("backups",[]);if(!Array.isArray(backups))backups=[];show("💾 <b>BACKUP / SAFE EXPORT</b>\n\nSnapshots retained: <b>"+backups.length+"</b>\n\nExports intentionally exclude proof file IDs, private credentials and wallet addresses from casual output.",[[{text:"💾 Create Backup",callback_data:"admin_core backup_create"}],[{text:"👥 Export Members",callback_data:"admin_core export_members"},{text:"📥 Export Applications",callback_data:"admin_core export_applications"}],[{text:"✅ Export Verification History",callback_data:"admin_core export_verifications"},{text:"🧾 Export Audit",callback_data:"admin_core export_audit"}],[{text:"⚙ Export Settings & Rules",callback_data:"admin_core export_settings"}],[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}824if(action==="backup_create"){let q=await db.bot.get("application_queue",[]);if(!Array.isArray(q))q=[];let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let rules=await db.bot.get("rules",[]);if(!Array.isArray(rules))rules=[];let audit=await db.bot.get("audit_logs",[]);if(!Array.isArray(audit))audit=[];let blacklist=await db.bot.get("blacklist",[]);if(!Array.isArray(blacklist))blacklist=[];let alerts=await db.bot.get("alerts",[]);if(!Array.isArray(alerts))alerts=[];let rv=await db.bot.get("reverification_requests",[]);if(!Array.isArray(rv))rv=[];let admins=await db.bot.get("admin_registry",[]);if(!Array.isArray(admins))admins=[];let p2p=await db.bot.get("p2p_groups",[]);if(!Array.isArray(p2p))p2p=[];let backups=await db.bot.get("backups",[]);if(!Array.isArray(backups))backups=[];let safeMembers=members.map(m=>({user_id:m.user_id,username:m.username||"",first_name:m.first_name||"",status:m.status,joined_at:m.joined_at||0,approved_at:m.approved_at||0,verified_at:m.verified_at||0,verified_crypto:m.verified_crypto||0,verified_deals:m.verified_deals||0})),safeQueue=q.map(x=>({application_id:x.application_id,user_id:x.user_id,username:x.username||"",status:x.status,started_at:x.started_at||0,submitted_at:x.submitted_at||0,reviewed_at:x.reviewed_at||0}));let b={id:"BKP-"+Date.now(),created_at:Date.now(),created_by:uid,summary:{applications:q.length,members:members.length,rules:rules.length,audit_events:audit.length,blacklist:blacklist.length,alerts:alerts.length,reverifications:rv.length,admins:admins.length},settings:s,rules:rules,application_queue:safeQueue,member_registry:safeMembers,blacklist:blacklist,alerts:alerts.slice(-500),reverification_requests:rv.slice(-500),admin_registry:admins.map(a=>({user_id:a.user_id,role:a.role,revoked:a.revoked===true,created_at:a.created_at||0})),p2p_groups:p2p};backups.push(b);await db.bot.set("backups",backups.slice(-30));await reAudit("backup_created",0,{id:b.id,summary:b.summary},uid);show("✅ <b>BACKUP CREATED</b>\n\nID: <code>"+b.id+"</code>\nApplications: <b>"+q.length+"</b>\nMembers: <b>"+members.length+"</b>\nRules: <b>"+rules.length+"</b>\n\n<i>Sensitive proof file IDs, private credentials and wallet addresses are intentionally excluded from this safe snapshot.</i>",[[{text:"‹ Backup / Export",callback_data:"admin_core backup"}]]);return;}825async function sendExport(title,data){let raw=JSON.stringify(data,null,2),max=3200,total=Math.max(1,Math.ceil(raw.length/max));for(let i=0;i<total;i++){await Api.sendMessage({chat_id:chat.id,text:"📦 <b>"+reHtml(title)+"</b> • "+(i+1)+"/"+total+"\n<pre>"+reHtml(raw.slice(i*max,(i+1)*max))+"</pre>",parse_mode:"HTML"});}}826if(action==="export_members"){let members=await db.bot.get("member_registry",[]);if(!Array.isArray(members))members=[];let safe=members.map(m=>({user_id:m.user_id,username:m.username||"",first_name:m.first_name||"",status:m.status,joined_at:m.joined_at||0,approved_at:m.approved_at||0,verified_crypto:m.verified_crypto||0,verified_deals:m.verified_deals||0}));await sendExport("MEMBERS EXPORT",safe);await reAudit("export_members",0,{count:safe.length},uid);return;}827if(action==="export_applications"){let q=await db.bot.get("application_queue",[]);if(!Array.isArray(q))q=[];let safe=q.map(x=>({application_id:x.application_id,user_id:x.user_id,username:x.username||"",first_name:x.first_name||"",status:x.status,started_at:x.started_at||0,submitted_at:x.submitted_at||0,reviewed_at:x.reviewed_at||0}));await sendExport("APPLICATIONS EXPORT",safe);await reAudit("export_applications",0,{count:safe.length},uid);return;}828if(action==="export_audit"){let a=await db.bot.get("audit_logs",[]);if(!Array.isArray(a))a=[];await sendExport("AUDIT EXPORT",a.slice(-500));await reAudit("export_audit",0,{count:Math.min(a.length,500)},uid);return;}829if(action==="export_settings"){let r=await db.bot.get("rules",[]);if(!Array.isArray(r))r=[];await sendExport("SETTINGS & RULES EXPORT",{settings:s,rules:r});await reAudit("export_settings_rules",0,{rules:r.length},uid);return;}830if(action==="export_verifications"){let users=await Bot.getUsers({chatType:"private"});if(!Array.isArray(users))users=[];let out=[];for(let u of users.slice(0,500)){let id=Number(typeof u==="object"?u.user_id:u);if(!id)continue;let h=await db.user.get("verification_history",[],{user_id:id});if(Array.isArray(h)&&h.length)out.push({user_id:id,history:h});}await sendExport("VERIFICATION HISTORY EXPORT",out);await reAudit("export_verifications",0,{users:out.length},uid);return;}831 832if (action === "networks") { if(!hasPerm("assets")){ack("Permission denied.",true);return;} let map=s.asset_networks; if(!map||typeof map!=="object")map={USDT:["TRON","ETHEREUM","SOLANA","TON"],ETH:["ETHEREUM"],BTC:["BITCOIN"],SOL:["SOLANA"],TON:["TON"]}; let rows=[]; for(let a of Object.keys(map)){rows.push([{text:"🌐 "+a+" • "+map[a].join(", ").slice(0,35),callback_data:"admin_core network_asset:"+a}]);} rows.unshift([{text:"+ Add / Configure Asset Networks",callback_data:"admin_core network_add"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🌐 <b>ASSETS & NETWORKS</b>\n\nConfigure which networks appear for each asset.",rows);return; }833if(action==="network_add"){await db.user.set("input_mode","admin_network_add");show("🌐 <b>CONFIGURE NETWORKS</b>\n\nSend: <code>ASSET | NETWORK1, NETWORK2</code>\nExample: <code>USDT | TRON, ETHEREUM</code>",[[{text:"← Back",callback_data:"admin_core networks"}]]);return;}834if(action.indexOf("network_asset:")===0){let a=action.slice(14).toUpperCase(),map=s.asset_networks||{},list=Array.isArray(map[a])?map[a]:[];show("🌐 <b>"+reHtml(a)+" NETWORKS</b>\n\n"+reHtml(list.join(", ")||"None"),[[{text:"✏ Replace Networks",callback_data:"admin_core network_add"}],[{text:"‹ Networks",callback_data:"admin_core networks"}]]);return;}835 836if(action==="p2p"){if(!hasPerm("p2p")){ack("Permission denied.",true);return;}let g=await db.bot.get("p2p_groups",[]);if(!Array.isArray(g))g=[];let rows=g.map((x,i)=>[{text:(x.enabled===false?"○ ":"✓ ")+String(x.name||x.username||x.chat_id),callback_data:"admin_core p2p_view:"+i}]);rows.unshift([{text:"+ Add P2P Group",callback_data:"admin_core p2p_add"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("🔗 <b>P2P GROUP MANAGER</b>\n\nReserved for future eligibility use; current entry flow does not require membership in these groups.",rows);return;}837if(action==="p2p_add"){await db.user.set("input_mode","admin_p2p_add");show("🔗 <b>ADD P2P GROUP</b>\n\nSend: <code>Name | @username_or_chat_id</code>",[[{text:"← Back",callback_data:"admin_core p2p"}]]);return;}838if(action.indexOf("p2p_view:")===0){let i=Number(action.split(":")[1]),g=await db.bot.get("p2p_groups",[]);if(!Array.isArray(g)||!g[i]){ack("Group not found.",true);return;}let x=g[i];show("🔗 <b>P2P GROUP</b>\n\nName: <b>"+reHtml(x.name)+"</b>\nReference: <code>"+reHtml(x.reference)+"</code>\nStatus: <b>"+(x.enabled===false?"DISABLED":"ENABLED")+"</b>",[[{text:x.enabled===false?"✅ Enable":"⏸ Disable",callback_data:"admin_core p2p_toggle:"+i}],[{text:"🗑 Delete",callback_data:"admin_core p2p_delete:"+i}],[{text:"‹ Groups",callback_data:"admin_core p2p"}]]);return;}839if(action.indexOf("p2p_toggle:")===0){let i=Number(action.split(":")[1]),g=await db.bot.get("p2p_groups",[]);if(!Array.isArray(g)||!g[i])return;g[i].enabled=g[i].enabled===false;g[i].updated_at=Date.now();await db.bot.set("p2p_groups",g);await reAudit("p2p_group_toggled",0,{index:i,enabled:g[i].enabled},uid);await adminRouter("p2p_view:"+i);return;}840if(action.indexOf("p2p_delete:")===0){let i=Number(action.split(":")[1]),g=await db.bot.get("p2p_groups",[]);if(!Array.isArray(g)||!g[i])return;let old=g.splice(i,1)[0];await db.bot.set("p2p_groups",g);await reAudit("p2p_group_deleted",0,{name:old.name},uid);await adminRouter("p2p");return;}841 842if(action==="admins"){if(adminRole!=="owner"){ack("Owner permission required.",true);return;}let a=await db.bot.get("admin_registry",[]);if(!Array.isArray(a))a=[];let rows=a.map((x,i)=>[{text:(x.revoked===true?"🚫 ":"✅ ")+String(x.user_id)+" • "+String(x.role),callback_data:"admin_core admin_view:"+i}]);rows.unshift([{text:"+ Add Admin",callback_data:"admin_core admin_add"}]);rows.push([{text:"‹ Admin Home",callback_data:"admin_core home"}]);show("👮 <b>ADMINS & ROLES</b>\n\nOwner: <code>"+OWNER_ID+"</code>\nAdditional admins: <b>"+a.length+"</b>",rows);return;}843if(action==="admin_add"){if(adminRole!=="owner"){ack("Owner permission required.",true);return;}await db.user.set("input_mode","admin_add_staff_id");show("+ <b>ADD ADMIN</b>\n\nSend the Telegram numeric user ID.",[[{text:"← Back",callback_data:"admin_core admins"}]]);return;}844if(action.indexOf("admin_view:")===0){if(adminRole!=="owner"){ack("Owner permission required.",true);return;}let i=Number(action.split(":")[1]),a=await db.bot.get("admin_registry",[]);if(!Array.isArray(a)||!a[i])return;let x=a[i];show("👮 <b>ADMIN PROFILE</b>\n\nUser: <code>"+Number(x.user_id)+"</code>\nRole: <b>"+reHtml(x.role)+"</b>\nStatus: <b>"+(x.revoked===true?"REVOKED":"ACTIVE")+"</b>",[[{text:"👑 Super Admin",callback_data:"admin_core admin_role:"+i+":super_admin"}],[{text:"🧾 Verification Staff",callback_data:"admin_core admin_role:"+i+":verification_staff"}],[{text:"🛡 Moderator",callback_data:"admin_core admin_role:"+i+":moderator"}],[{text:"💬 Support",callback_data:"admin_core admin_role:"+i+":support"}],[{text:x.revoked===true?"✅ Restore":"🚫 Revoke",callback_data:"admin_core admin_revoke:"+i}],[{text:"‹ Admins",callback_data:"admin_core admins"}]]);return;}845if(action.indexOf("admin_role:")===0){if(adminRole!=="owner")return;let p=action.split(":"),i=Number(p[1]),role=String(p[2]),allowed=["super_admin","verification_staff","moderator","support"],a=await db.bot.get("admin_registry",[]);if(!allowed.includes(role)||!Array.isArray(a)||!a[i])return;let old=a[i].role;a[i].role=role;a[i].updated_at=Date.now();await db.bot.set("admin_registry",a);await reAudit("admin_role_changed",a[i].user_id,{old_role:old,new_role:role},uid);await adminRouter("admin_view:"+i);return;}846if(action.indexOf("admin_revoke:")===0){if(adminRole!=="owner")return;let i=Number(action.split(":")[1]),a=await db.bot.get("admin_registry",[]);if(!Array.isArray(a)||!a[i])return;a[i].revoked=a[i].revoked!==true;a[i].session_revoked_at=Date.now();await db.bot.set("admin_registry",a);await db.user.del("staff_session_until",{user_id:Number(a[i].user_id)});await reAudit("admin_access_toggled",a[i].user_id,{revoked:a[i].revoked},uid);await adminRouter("admin_view:"+i);return;}847 848if(action==="system"){if(!hasPerm("system")){ack("Permission denied.",true);return;}let last=Number(await db.bot.get("scheduler_last_run",0)||0),backs=await db.bot.get("backups",[]);if(!Array.isArray(backs))backs=[];show("⚙ <b>SYSTEM SETTINGS / HEALTH</b>\n\nOfficial channel: <code>"+reHtml(String(s.official_channel||"@red_eye_official"))+"</code>\nPrivate group: <code>"+reHtml(String(s.private_group_id||-1004382007648))+"</code>\nLast lifecycle scan: <b>"+(last?new Date(last).toISOString():"Never")+"</b>\nBackups retained: <b>"+backs.length+"</b>\n\nProvider failures never automatically reject applicants.",[[{text:"📝 Set Channel",callback_data:"admin_core system_channel"},{text:"📝 Set Private Group",callback_data:"admin_core system_group"}],[{text:"🧪 Provider Test",callback_data:"admin_core provider_test"},{text:"✅ Production Check",callback_data:"admin_core production_check"}],[{text:"⏱ Background Worker URL",callback_data:"admin_core worker_webhook"}],[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}849if(action==="worker_webhook"){if(typeof Webhook==="undefined"||!Webhook||typeof Webhook.getGlobalUrl!=="function"){show("⏱ <b>BACKGROUND WORKER</b>\n\nGlobal Webhook is unavailable in this runtime. Lifecycle still runs opportunistically on updates and can be launched manually from Admin.",[[{text:"‹ System",callback_data:"admin_core system"}]]);return;}let url=Webhook.getGlobalUrl("/worker",{options:{worker:true}});show("⏱ <b>BACKGROUND WORKER URL</b>\n\nUse this signed URL with a cron/system trigger every 5–15 minutes. When invoked without a Telegram user, the @ hook performs lifecycle work, notification retries, wallet monitoring and daily snapshots.\n\n<code>"+reHtml(String(url||""))+"</code>",[[{text:"‹ System",callback_data:"admin_core system"}]]);return;}850if(action==="provider_test"){let btc=await rePriceUSD("BTC"),eth=await rePriceUSD("ETH"),sol=await rePriceUSD("SOL"),ton=await rePriceUSD("TON"),usdt=await rePriceUSD("USDT");show("🧪 <b>PROVIDER TEST</b>\n\nBTC pricing: <b>"+(btc.ok?"OK • "+reHtml(btc.source):reHtml(btc.status))+"</b>\nETH pricing: <b>"+(eth.ok?"OK • "+reHtml(eth.source):reHtml(eth.status))+"</b>\nSOL pricing: <b>"+(sol.ok?"OK • "+reHtml(sol.source):reHtml(sol.status))+"</b>\nTON pricing: <b>"+(ton.ok?"OK • "+reHtml(ton.source):reHtml(ton.status))+"</b>\nUSDT pricing: <b>"+(usdt.ok?"OK • "+reHtml(usdt.source):reHtml(usdt.status))+"</b>\n\nFailure here does not reject applicants; affected wallets fall back to temporary-unavailable/manual review.",[[{text:"‹ System",callback_data:"admin_core system"}]]);return;}851if(action==="production_check"){let checks=[];checks.push(["Owner configured",!!OWNER_ID]);checks.push(["Official channel configured",!!String(s.official_channel||"@red_eye_official")]);checks.push(["Private group configured",Number(s.private_group_id||-1004382007648)<0]);checks.push(["Minimum crypto valid",Number(s.min_crypto_networth||1000)>0]);checks.push(["Minimum deals valid",Number(s.min_deal_volume||3000)>0]);checks.push(["Reminder valid",Number(s.application_reminder_minutes||60)>0]);checks.push(["Expiry valid",Number(s.application_expiry_hours||24)>0]);checks.push(["Low wallet thresholds valid",Number(s.low_wallet_threshold||500)>0&&Number(s.low_wallet_clear_threshold||600)>Number(s.low_wallet_threshold||500)]);checks.push(["Staff 2FA configured",!!String(await db.user.get("staff_pin_hash","")||"")]);let rules=await db.bot.get("rules",[]);checks.push(["Rules manager available",Array.isArray(rules)]);let passed=checks.filter(x=>x[1]).length,body=checks.map(x=>(x[1]?"✅ ":"⚠️ ")+x[0]).join("\n");show("✅ <b>PRODUCTION CHECK</b>\n\nPassed: <b>"+passed+"/"+checks.length+"</b>\n\n"+body+"\n\n<i>This diagnostic is non-destructive.</i>",[[{text:"‹ System",callback_data:"admin_core system"}]]);return;}852if(action==="system_channel"){await db.user.set("input_mode","admin_system_channel");show("📝 Send official channel username, e.g. <code>@red_eye_official</code>.",[[{text:"← Back",callback_data:"admin_core system"}]]);return;}853if(action==="system_group"){await db.user.set("input_mode","admin_system_group");show("📝 Send private community numeric chat ID, e.g. <code>-100...</code>.",[[{text:"← Back",callback_data:"admin_core system"}]]);return;}854 855if(action==="monitor_scan"){if(!hasPerm("wallets")){ack("Permission denied.",true);return;}let users=await Bot.getUsers({full:true,chatType:"private",excludeBlocked:true,limit:10000});if(!Array.isArray(users))users=[];let low=Number(s.low_wallet_threshold||500),clear=Number(s.low_wallet_clear_threshold||600),days=Number(s.low_wallet_duration_days||7),now=Date.now(),scanned=0,members=0,alerts=await db.bot.get("alerts",[]);if(!Array.isArray(alerts))alerts=[];for(let u of users){let id=Number(u&&u.user_id);if(!id)continue;let ms=String(await db.user.get("member_status","",{user_id:id}));if(!["active","approved_pending_join"].includes(ms))continue;members++;let wallets=await db.user.get("wallets",[],{user_id:id});if(!Array.isArray(wallets)||!wallets.length)continue;let vr=await reVerifyWalletList(wallets);await db.user.set("wallets",vr.wallets,{user_id:id});await db.user.set("auto_verified_crypto_total",vr.total_usd,{user_id:id});scanned++;let since=Number(await db.user.get("low_wallet_since",0,{user_id:id})||0);if(vr.total_usd<low){if(!since){since=now;await db.user.set("low_wallet_since",since,{user_id:id});}if(now-since>=days*86400000&&!alerts.some(a=>a&&a.status!=="resolved"&&a.type==="low_wallet"&&Number(a.user_id)===id)){alerts.push({id:"ALERT-"+id+"-"+now,type:"low_wallet",user_id:id,status:"open",value:vr.total_usd,threshold:low,since:since,created_at:now});await reNotify({chat_id:OWNER_ID,text:"🚨 <b>LOW WALLET ALERT</b>\n\nMember: <code>"+id+"</code>\nVerified public value: <b>$"+vr.total_usd.toFixed(2)+"</b>\nBelow threshold for configured duration. No automatic removal was performed.",parse_mode:"HTML"},"low_wallet_alert",OWNER_ID);}}else if(since&&vr.total_usd>=clear){await db.user.del("low_wallet_since",{user_id:id});for(let a of alerts)if(a&&a.type==="low_wallet"&&Number(a.user_id)===id&&a.status!=="resolved"){a.status="resolved";a.resolved_at=now;a.resolve_reason="balance_recovered";}}}await db.bot.set("alerts",alerts.slice(-1000));await db.bot.set("wallet_monitor_last_run",now);await reAudit("wallet_monitor_scan",0,{members:members,scanned:scanned},uid);show("👛 <b>WALLET MONITOR COMPLETE</b>\n\nMembers considered: <b>"+members+"</b>\nWallet sets checked: <b>"+scanned+"</b>\nLow threshold: <b>$"+low+"</b>\nClear threshold: <b>$"+clear+"</b>\n\nNo member is automatically removed by monitoring.",[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;}856 857if (action === "lifecycle_scan") {858 let now=Date.now(),q=await db.bot.get("application_queue",[]);if(!Array.isArray(q))q=[];let reminderMs=Number(s.application_reminder_minutes||60)*60000,expiryMs=Number(s.application_expiry_hours||24)*3600000,rem=0,exp=0;859 for(let item of q){if(!item||!item.user_id)continue;let status=String(item.status||"");if(status!=="started")continue;let started=Number(item.started_at||item.last_activity_at||0),last=Number(item.last_activity_at||started);if(started&&now-started>=expiryMs){item.status="abandoned";item.abandoned_at=now;await db.user.set("application_status","abandoned",{user_id:Number(item.user_id)});let ah=await db.user.get("application_history",[],{user_id:Number(item.user_id)});if(!Array.isArray(ah))ah=[];ah.push({application_id:item.application_id||"",status:"abandoned",at:now,reason:"expiry"});await db.user.set("application_history",ah.slice(-50),{user_id:Number(item.user_id)});await reNotify({chat_id:Number(item.user_id),text:"⌛ Your RED EYE application expired after the configured inactivity window."},"application_expired",Number(item.user_id));exp++;}else if(last&&!item.reminder_sent_at&&now-last>=reminderMs){item.reminder_sent_at=now;await reNotify({chat_id:Number(item.user_id),text:"⏰ Reminder: your RED EYE application is still incomplete. Open /start to continue."},"application_reminder",Number(item.user_id));rem++;}}860 await db.bot.set("application_queue",q);await db.bot.set("scheduler_last_run",now);show("⌛ <b>LIFECYCLE SCAN COMPLETE</b>\n\nReminders sent: <b>"+rem+"</b>\nApplications expired: <b>"+exp+"</b>",[[{text:"‹ Admin Home",callback_data:"admin_core home"}]]);return;861}862 863ack("Unknown admin action.",false);864 865}866 867let data = (options && options.route) ? String(options.route) : "";868if (!data && update && update.callback_query) data = String(update.callback_query.data || "").trim();869if (!data) return;870 871if (data === "user_core" || data.startsWith("user_core ")) {872 let action = data === "user_core" ? "home" : data.slice(10).trim();873 await userRouter(action);874 return;875}876 877if (data === "admin_core" || data.startsWith("admin_core ")) {878 let action = data === "admin_core" ? "home" : data.slice(11).trim();879 await adminRouter(action);880 return;881}882 883Api.answerCallbackQuery({ callback_query_id: update.callback_query.id, text: "This action is unavailable." });