const moment = require("moment-timezone"); module.exports = { config: { name: "bank", aliases: [], version: "2.4.71", author: "ST BOT", countDown: 5, role: 0, description: { en: "ST BOT Banking System - Complete banking solution with loans, investments, games, and more" }, category: "economy", guide: { en: " {pn} register - Register for bank account\n" + " {pn} balance [@mention] - Check bank balance\n" + " {pn} deposit [duration] - Deposit money (duration: 1h, 1d, 1w, 1m, permanent)\n" + " {pn} withdraw - Withdraw money from bank\n" + " {pn} tobank - Move money from wallet to bank (1% fee per $1000)\n" + " {pn} towallet - Move money from bank to wallet (1% fee per $1000)\n" + " {pn} transfer <@mention|reply> - Transfer money\n" + " {pn} loan - Take a loan (5% interest)\n" + " {pn} payloan - Pay back loan\n" + " {pn} invest - Invest money (1h-1m)\n" + " {pn} daily - Claim daily reward\n" + " {pn} lottery - Play free daily lottery\n" + " {pn} spin - Spin slot machine\n" + " {pn} coinflip - Flip a coin\n" + " {pn} trade - Trade coins\n" + " {pn} transactions - View transaction history\n" + " {pn} leaderboard - View bank rankings" } }, langs: { en: { notRegistered: "āŒ You don't have a bank account! Use '/bank register' to create one.", registered: "āœ… Bank account created successfully!\nšŸ’° Welcome bonus: $500", alreadyRegistered: "āŒ You already have a bank account!", balance: "šŸ¦ Bank Balance\n━━━━━━━━━━━━━━━\nšŸ‘¤ User: %1\nšŸ’° Balance: $%2\nšŸ“Š Total Deposited: $%3\nšŸ“¤ Total Withdrawn: $%4\nšŸ’³ Loan: $%5\nšŸ“… Member Since: %6", depositSuccess: "āœ… Deposited $%1 to your bank account!\nšŸ’° New Balance: $%2", withdrawSuccess: "āœ… Withdrawn $%1 from your bank account!\nšŸ’° New Balance: $%2", insufficientFunds: "āŒ Insufficient funds in your wallet!", insufficientBank: "āŒ Insufficient funds in your bank account!", transferSuccess: "āœ… Transferred $%1 to %2\nšŸ’° Your New Balance: $%3", loanTaken: "āœ… Loan of $%1 approved!\nšŸ’³ Interest Rate: 5%\nāš ļø Total to repay: $%2", hasLoan: "āŒ You already have an active loan! Pay it back first.", loanPaid: "āœ… Paid $%1 towards your loan!\nšŸ’³ Remaining: $%2", noLoan: "āŒ You don't have any active loan!", investSuccess: "āœ… Invested $%1 for %2\nšŸ“ˆ Expected Return: $%3\nā° Matures at: %4", dailyClaimed: "šŸŽ Daily Reward Claimed!\nšŸ’° +$%1\nšŸ”„ Streak: %2 days\nā° Come back tomorrow!", alreadyClaimed: "āŒ You already claimed your daily reward!\nā° Come back in %1", lotteryWon: "šŸŽ‰ JACKPOT! You won $%1 from the lottery!\nšŸ€ Lucky number: %2", lotteryLost: "šŸ˜” Better luck next time!\nšŸ€ Your number: %1 | Winning number: %2", alreadyPlayedLottery: "āŒ You already played lottery today!\nā° Come back tomorrow!", spinResult: "šŸŽ° SLOT MACHINE\n━━━━━━━━━━━━\n%1\n━━━━━━━━━━━━\n%2", coinflipWin: "šŸŖ™ Coin landed on %1!\nāœ… You won $%2!", coinflipLose: "šŸŖ™ Coin landed on %1!\nāŒ You lost $%2!", tradeSuccess: "šŸ“Š Trade executed!\n%1 %2 coins\nšŸ’° New Balance: $%3" } }, ST: async function ({ args, message, event, usersData, getLang, api }) { const { bankData } = global.db; const { senderID, messageReply } = event; const command = args[0]?.toLowerCase(); // Register if (command === "register") { const existingBankData = await bankData.get(senderID); if (existingBankData && existingBankData.userID) { return message.reply(getLang("alreadyRegistered")); } await bankData.create(senderID); await usersData.addMoney(senderID, 500); return message.reply(getLang("registered")); } // Check if user is registered const userBankDataCheck = await bankData.get(senderID); if (!userBankDataCheck || !userBankDataCheck.userID) { return message.reply(getLang("notRegistered")); } const userData = await usersData.get(senderID); const userBankData = await bankData.get(senderID); switch (command) { case "balance": case "bal": { let targetID = senderID; if (Object.keys(event.mentions).length > 0) { targetID = Object.keys(event.mentions)[0]; } else if (messageReply) { targetID = messageReply.senderID; } const targetBankDataCheck = await bankData.get(targetID); if (!targetBankDataCheck || !targetBankDataCheck.userID) { return message.reply("āŒ User doesn't have a bank account!"); } const targetBankData = await bankData.get(targetID); const targetUserData = await usersData.get(targetID); const memberSince = moment(targetBankData.registeredAt).format("MMM DD, YYYY"); return message.reply(getLang("balance", targetUserData.name, targetBankData.bankBalance.toLocaleString(), targetBankData.totalDeposited.toLocaleString(), targetBankData.totalWithdrawn.toLocaleString(), targetBankData.loan.amount.toLocaleString(), memberSince )); } case "deposit": { const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userData.money < amount) { return message.reply(getLang("insufficientFunds")); } const duration = args[2]; const depositData = { amount, depositedAt: new Date(), duration: duration || "permanent", withdrawable: !duration || duration === "permanent" }; if (duration && duration !== "permanent") { const durationMs = parseDuration(duration); if (!durationMs) { return message.reply("āŒ Invalid duration! Use: 1h, 1d, 1w, 1m, or permanent"); } depositData.maturesAt = new Date(Date.now() + durationMs); depositData.interest = calculateInterest(amount, duration); } await usersData.subtractMoney(senderID, amount); userBankData.deposits.push(depositData); userBankData.bankBalance += amount; userBankData.totalDeposited += amount; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "deposit", amount, duration: duration || "permanent" }); return message.reply(getLang("depositSuccess", amount.toLocaleString(), userBankData.bankBalance.toLocaleString())); } case "withdraw": { const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userBankData.bankBalance < amount) { return message.reply(getLang("insufficientBank")); } // Check for locked deposits const availableBalance = calculateAvailableBalance(userBankData); if (availableBalance < amount) { return message.reply(`āŒ Only $${availableBalance.toLocaleString()} is available for withdrawal!\nSome funds are locked in time deposits.`); } await usersData.addMoney(senderID, amount); userBankData.bankBalance -= amount; userBankData.totalWithdrawn += amount; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "withdraw", amount }); return message.reply(getLang("withdrawSuccess", amount.toLocaleString(), userBankData.bankBalance.toLocaleString())); } case "transfer": { let targetID = Object.keys(event.mentions)[0]; let amount = parseInt(args[2]); if (messageReply) { targetID = messageReply.senderID; amount = parseInt(args[1]); } if (!targetID) { return message.reply("āŒ Please mention someone or reply to their message!"); } if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userBankData.bankBalance < amount) { return message.reply(getLang("insufficientBank")); } const targetBankCheck = await bankData.get(targetID); if (!targetBankCheck || !targetBankCheck.userID) { return message.reply("āŒ Target user doesn't have a bank account!"); } const targetBankData = await bankData.get(targetID); const targetUserData = await usersData.get(targetID); userBankData.bankBalance -= amount; targetBankData.bankBalance += amount; await bankData.set(senderID, userBankData); await bankData.set(targetID, targetBankData); await bankData.addTransaction(senderID, { type: "transfer_out", amount, to: targetID }); await bankData.addTransaction(targetID, { type: "transfer_in", amount, from: senderID }); return message.reply(getLang("transferSuccess", amount.toLocaleString(), targetUserData.name, userBankData.bankBalance.toLocaleString())); } case "loan": { const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userBankData.banned.isBanned) { const canUnban = new Date(userBankData.banned.canUnbanAt); const now = new Date(); if (now < canUnban) { return message.reply(`āŒ You are banned from bank services!\nšŸ“› Reason: ${userBankData.banned.reason}\nā° Can request unban after: ${moment(canUnban).format("MMM DD, YYYY HH:mm")}`); } } if (userBankData.loan.amount > 0) { return message.reply(getLang("hasLoan")); } if (userBankData.loanRequests.some(r => r.status === "pending")) { return message.reply("āŒ You already have a pending loan request!"); } const interestAmount = Math.floor(amount * 0.05); const totalRepay = amount + interestAmount; const requestID = Date.now().toString(); const loanRequest = { requestID, amount, totalRepay, requestedAt: new Date(), status: "pending", threadID: event.threadID }; userBankData.loanRequests.push(loanRequest); await bankData.set(senderID, userBankData); // Send to admin thread const mainThreadID = global.GoatBot.config.mainThreadId; const threadData = await api.getThreadInfo(event.threadID); const threadName = threadData.threadName || "Unknown Thread"; api.sendMessage( `šŸ¦ NEW LOAN REQUEST\n━━━━━━━━━━━━━━━━\n` + `šŸ‘¤ User: ${userData.name}\n` + `šŸ’° Amount: $${amount.toLocaleString()}\n` + `šŸ’³ Total to Repay: $${totalRepay.toLocaleString()}\n` + `šŸ“ Thread: ${threadName}\n` + `šŸ†” Request ID: ${requestID}\n` + `ā° Requested: ${moment().format("MMM DD, YYYY HH:mm")}\n\n` + `Reply "yes" to approve or "no" to reject`, mainThreadID, (err, info) => { if (!err) { global.GoatBot.onReply.set(info.messageID, { commandName: "bank", messageID: info.messageID, author: senderID, requestID, type: "loanApproval", amount, totalRepay, threadID: event.threadID }); } } ); return message.reply(`āœ… Loan request submitted!\nšŸ’° Amount: $${amount.toLocaleString()}\nšŸ’³ Total to Repay: $${totalRepay.toLocaleString()}\nā° Waiting for admin approval...`); } case "payloan": { if (userBankData.loan.amount === 0) { return message.reply(getLang("noLoan")); } let payAmount; // Check if user wants to pay full amount (no args or "full" or "all") if (!args[1] || args[1].toLowerCase() === "full" || args[1].toLowerCase() === "all") { payAmount = userBankData.loan.amount; if (userBankData.bankBalance < payAmount) { return message.reply(`āŒ Insufficient bank balance to pay full loan!\nšŸ’³ Loan Amount: $${userBankData.loan.amount.toLocaleString()}\nšŸ’° Your Balance: $${userBankData.bankBalance.toLocaleString()}\nšŸ“ Use: bank payloan to pay partial`); } } else { // Manual amount entry const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount! Use a number or leave empty to pay full loan."); } if (userBankData.bankBalance < amount) { return message.reply(getLang("insufficientBank")); } payAmount = Math.min(amount, userBankData.loan.amount); } userBankData.bankBalance -= payAmount; userBankData.loan.amount -= payAmount; const isFullyPaid = userBankData.loan.amount === 0; if (isFullyPaid) { userBankData.loan.takenAt = null; userBankData.loan.dueDate = null; userBankData.loan.threadID = null; } await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "loan_payment", amount: payAmount }); if (isFullyPaid) { return message.reply(`āœ… Loan fully paid!\nšŸ’° Paid: $${payAmount.toLocaleString()}\nšŸŽ‰ You're debt-free!\nšŸ’° New Balance: $${userBankData.bankBalance.toLocaleString()}`); } else { return message.reply(getLang("loanPaid", payAmount.toLocaleString(), userBankData.loan.amount.toLocaleString())); } } case "tobank": { const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userData.money < amount) { return message.reply(getLang("insufficientFunds")); } // 1% fee per $1000 const fee = Math.floor((amount / 1000) * 10); const totalCost = amount + fee; if (userData.money < totalCost) { return message.reply(`āŒ You need $${totalCost.toLocaleString()} (including $${fee.toLocaleString()} fee)!`); } await usersData.subtractMoney(senderID, totalCost); userBankData.bankBalance += amount; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "wallet_to_bank", amount }); return message.reply(`āœ… Transferred $${amount.toLocaleString()} to bank!\nšŸ’ø Fee: $${fee.toLocaleString()}\nšŸ’° New Bank Balance: $${userBankData.bankBalance.toLocaleString()}`); } case "towallet": { const amount = parseInt(args[1]); if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userBankData.bankBalance < amount) { return message.reply(getLang("insufficientBank")); } // 1% fee per $1000 const fee = Math.floor((amount / 1000) * 10); const amountAfterFee = amount - fee; if (amountAfterFee <= 0) { return message.reply("āŒ Amount too small after fee deduction!"); } userBankData.bankBalance -= amount; await usersData.addMoney(senderID, amountAfterFee); await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "bank_to_wallet", amount: amountAfterFee }); return message.reply(`āœ… Transferred $${amountAfterFee.toLocaleString()} to wallet!\nšŸ’ø Fee: $${fee.toLocaleString()}\nšŸ’µ New Wallet Balance: $${(userData.money + amountAfterFee).toLocaleString()}`); } case "invest": { const amount = parseInt(args[1]); const duration = args[2]; if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } if (userBankData.bankBalance < amount) { return message.reply(getLang("insufficientBank")); } if (!duration) { return message.reply("āŒ Please specify duration! (1h, 1d, 1w, 1m)"); } const durationMs = parseDuration(duration); if (!durationMs) { return message.reply("āŒ Invalid duration! Use: 1h, 1d, 1w, 1m"); } const returnRate = getInvestmentReturn(duration); const expectedReturn = Math.floor(amount * returnRate); const maturesAt = new Date(Date.now() + durationMs); const investment = { amount, investedAt: new Date(), maturesAt, expectedReturn, duration }; userBankData.investments.push(investment); userBankData.bankBalance -= amount; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "investment", amount, duration }); return message.reply(getLang("investSuccess", amount.toLocaleString(), duration, expectedReturn.toLocaleString(), moment(maturesAt).format("MMM DD, YYYY HH:mm") )); } case "daily": { const today = moment.tz("Asia/Dhaka").format("DD/MM/YYYY"); if (userBankData.dailyClaim.lastClaimed === today) { const tomorrow = moment.tz("Asia/Dhaka").add(1, 'day').startOf('day'); const timeLeft = tomorrow.diff(moment.tz("Asia/Dhaka")); const hours = Math.floor(timeLeft / (1000 * 60 * 60)); const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)); return message.reply(getLang("alreadyClaimed", `${hours}h ${minutes}m`)); } userBankData.dailyClaim.streak += 1; userBankData.dailyClaim.lastClaimed = today; const reward = 100 + (userBankData.dailyClaim.streak * 10); userBankData.bankBalance += reward; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "daily_claim", amount: reward }); return message.reply(getLang("dailyClaimed", reward.toLocaleString(), userBankData.dailyClaim.streak)); } case "lottery": { const today = moment.tz("Asia/Dhaka").format("DD/MM/YYYY"); if (userBankData.lottery.lastPlayed === today) { return message.reply(getLang("alreadyPlayedLottery")); } const userNumber = Math.floor(Math.random() * 100); const winningNumber = Math.floor(Math.random() * 100); if (Math.abs(userNumber - winningNumber) <= 10) { const prize = 1000; userBankData.bankBalance += prize; userBankData.lottery.totalWins += 1; userBankData.lottery.lastPlayed = today; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "lottery_win", amount: prize }); return message.reply(getLang("lotteryWon", prize.toLocaleString(), winningNumber)); } userBankData.lottery.lastPlayed = today; await bankData.set(senderID, userBankData); return message.reply(getLang("lotteryLost", userNumber, winningNumber)); } case "spin": { const bet = parseInt(args[1]); if (isNaN(bet) || bet <= 0) { return message.reply("āŒ Invalid bet amount!"); } if (userBankData.bankBalance < bet) { return message.reply(getLang("insufficientBank")); } // Send initial spinning message const spinningMsg = await message.reply("šŸŽ° SPINNING...\n━━━━━━━━━━━━\nšŸ”„ šŸ”„ šŸ”„\n━━━━━━━━━━━━\nā³ Please wait..."); // Wait for dramatic effect await new Promise(resolve => setTimeout(resolve, 2000)); const slots = ["šŸ’", "šŸ‹", "šŸŠ", "šŸ‡", "šŸ’Ž", "⭐"]; let winnings = 0; let resultText = ""; let result = []; // 30% win rate, 70% lose rate const winChance = Math.random(); if (winChance < 0.30) { // WIN - 30% chance const winType = Math.random(); if (winType < 0.05) { // 5% chance for jackpot const jackpotSlot = slots[4]; // šŸ’Ž result = [jackpotSlot, jackpotSlot, jackpotSlot]; winnings = bet * 10; resultText = `šŸ’Ž JACKPOT! šŸ’Ž\nāœ… You won $${winnings.toLocaleString()}!\nšŸ’° New Balance: $${(userBankData.bankBalance + winnings).toLocaleString()}`; } else if (winType < 0.20) { // 15% chance for triple match const tripleSlot = slots[Math.floor(Math.random() * 3)]; // Lower value slots result = [tripleSlot, tripleSlot, tripleSlot]; winnings = bet * 5; resultText = `šŸŽ‰ Triple Match!\nāœ… You won $${winnings.toLocaleString()}!\nšŸ’° New Balance: $${(userBankData.bankBalance + winnings).toLocaleString()}`; } else { // 80% chance for double match (within wins) const doubleSlot = slots[Math.floor(Math.random() * slots.length)]; result = [doubleSlot, doubleSlot, slots[Math.floor(Math.random() * slots.length)]]; winnings = bet * 2; resultText = `šŸ‘ Double Match!\nāœ… You won $${winnings.toLocaleString()}!\nšŸ’° New Balance: $${(userBankData.bankBalance + winnings).toLocaleString()}`; } } else { // LOSE - 70% chance result = [ slots[Math.floor(Math.random() * slots.length)], slots[Math.floor(Math.random() * slots.length)], slots[Math.floor(Math.random() * slots.length)] ]; // Ensure no matches while ((result[0] === result[1] && result[1] === result[2]) || (result[0] === result[1] || result[1] === result[2] || result[0] === result[2])) { result = [ slots[Math.floor(Math.random() * slots.length)], slots[Math.floor(Math.random() * slots.length)], slots[Math.floor(Math.random() * slots.length)] ]; } winnings = -bet; resultText = `šŸ˜” No match!\nāŒ You lost $${bet.toLocaleString()}!\nšŸ’° New Balance: $${(userBankData.bankBalance + winnings).toLocaleString()}`; } userBankData.bankBalance += winnings; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "slot_game", amount: winnings }); // Edit message with result const finalMsg = `šŸŽ° SLOT MACHINE\n━━━━━━━━━━━━\n${result.join(" | ")}\n━━━━━━━━━━━━\n${resultText}`; return api.editMessage(finalMsg, spinningMsg.messageID); } case "coinflip": { const bet = parseInt(args[1]); const choice = args[2]?.toLowerCase(); if (isNaN(bet) || bet <= 0) { return message.reply("āŒ Invalid bet amount!"); } if (!["heads", "tails"].includes(choice)) { return message.reply("āŒ Choose heads or tails!"); } if (userBankData.bankBalance < bet) { return message.reply(getLang("insufficientBank")); } const result = Math.random() < 0.5 ? "heads" : "tails"; const won = result === choice; if (won) { userBankData.bankBalance += bet; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "coinflip_win", amount: bet }); return message.reply(getLang("coinflipWin", result, bet.toLocaleString())); } else { userBankData.bankBalance -= bet; await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: "coinflip_loss", amount: bet }); return message.reply(getLang("coinflipLose", result, bet.toLocaleString())); } } case "trade": { const action = args[1]?.toLowerCase(); const amount = parseInt(args[2]); if (!["buy", "sell"].includes(action)) { return message.reply("āŒ Use 'buy' or 'sell'!"); } if (isNaN(amount) || amount <= 0) { return message.reply("āŒ Invalid amount!"); } const rate = 1 + (Math.random() * 0.2 - 0.1); // ±10% fluctuation const cost = Math.floor(amount * rate); if (action === "buy") { if (userBankData.bankBalance < cost) { return message.reply(getLang("insufficientBank")); } userBankData.bankBalance -= cost; userBankData.premiumCurrency += amount; } else { if (userBankData.premiumCurrency < amount) { return message.reply("āŒ Insufficient premium currency!"); } userBankData.premiumCurrency -= amount; userBankData.bankBalance += cost; } await bankData.set(senderID, userBankData); await bankData.addTransaction(senderID, { type: `trade_${action}`, amount: action === "buy" ? cost : amount }); return message.reply(getLang("tradeSuccess", action === "buy" ? "Bought" : "Sold", amount, userBankData.bankBalance.toLocaleString() )); } case "transactions": case "history": { if (!userBankData.transactions || userBankData.transactions.length === 0) { return message.reply("āŒ No transactions yet!"); } let msg = "šŸ“œ Transaction History (Last 10)\n━━━━━━━━━━━━━━━━\n"; userBankData.transactions.slice(0, 10).forEach((tx, i) => { const time = moment(tx.timestamp).format("MMM DD, HH:mm"); const sign = tx.type.includes("win") || tx.type.includes("deposit") || tx.type.includes("in") ? "+" : "-"; msg += `${i + 1}. ${tx.type.toUpperCase()}: ${sign}$${Math.abs(tx.amount).toLocaleString()} - ${time}\n`; }); return message.reply(msg); } case "leaderboard": case "top": { const allBanks = global.db.allBankData.sort((a, b) => b.bankBalance - a.bankBalance).slice(0, 10); let msg = "šŸ† Bank Leaderboard (Top 10)\n━━━━━━━━━━━━━━━━\n"; for (let i = 0; i < allBanks.length; i++) { const user = await usersData.get(allBanks[i].userID); const medal = i === 0 ? "šŸ„‡" : i === 1 ? "🄈" : i === 2 ? "šŸ„‰" : `${i + 1}.`; msg += `${medal} ${user.name}: $${allBanks[i].bankBalance.toLocaleString()}\n`; } return message.reply(msg); } default: return message.SyntaxError(); } }, onReply: async function ({ event, Reply, message, usersData, api }) { const { bankData } = global.db; const adminConfig = global.GoatBot.config.adminBot; if (!adminConfig.includes(event.senderID)) { return; } if (Reply.type === "loanApproval") { const response = event.body.toLowerCase().trim(); const { requestID, amount, totalRepay, threadID, author: requesterID } = Reply; if (!["yes", "no"].includes(response)) { return message.reply("āŒ Reply 'yes' to approve or 'no' to reject!"); } const requesterBankData = await bankData.get(requesterID); const requestIndex = requesterBankData.loanRequests.findIndex(r => r.requestID === requestID); if (requestIndex === -1) { return message.reply("āŒ Loan request not found!"); } const requesterUserData = await usersData.get(requesterID); const LOAN_DUE_DAYS = 7; if (response === "yes") { // Approve loan const dueDate = new Date(); dueDate.setDate(dueDate.getDate() + LOAN_DUE_DAYS); requesterBankData.loan = { amount: totalRepay, takenAt: new Date(), interestRate: 5, dueDate, threadID }; requesterBankData.loanRequests[requestIndex].status = "approved"; requesterBankData.bankBalance += amount; await bankData.set(requesterID, requesterBankData); await bankData.addTransaction(requesterID, { type: "loan_approved", amount, totalRepay }); // Notify user with mention const requesterUserData = await usersData.get(requesterID); api.sendMessage( { body: `@${requesterUserData.name} āœ… LOAN APPROVED!\n━━━━━━━━━━━━━━━━\n` + `šŸ’° Amount: $${amount.toLocaleString()}\n` + `šŸ’³ Total to Repay: $${totalRepay.toLocaleString()}\n` + `šŸ“… Due Date: ${moment(dueDate).format("MMM DD, YYYY")}\n` + `āš ļø Pay within ${LOAN_DUE_DAYS} days or face ban!`, mentions: [{ tag: `@${requesterUserData.name}`, id: requesterID }] }, threadID ); return message.reply(`āœ… Loan approved for ${requesterUserData.name}!`); } else { // Reject loan requesterBankData.loanRequests[requestIndex].status = "rejected"; await bankData.set(requesterID, requesterBankData); // Notify user with mention const requesterUserData = await usersData.get(requesterID); api.sendMessage( { body: `@${requesterUserData.name} āŒ LOAN REJECTED\n━━━━━━━━━━━━━━━━\n` + `Your loan request for $${amount.toLocaleString()} was rejected.\n` + `You can reapply for a loan anytime.`, mentions: [{ tag: `@${requesterUserData.name}`, id: requesterID }] }, threadID ); return message.reply(`āŒ Loan rejected for ${requesterUserData.name}.`); } } } }; function parseDuration(duration) { const units = { 'h': 60 * 60 * 1000, 'd': 24 * 60 * 60 * 1000, 'w': 7 * 24 * 60 * 60 * 1000, 'm': 30 * 24 * 60 * 60 * 1000 }; const match = duration.match(/^(\d+)([hdwm])$/); if (!match) return null; const value = parseInt(match[1]); const unit = match[2]; return value * units[unit]; } function calculateInterest(amount, duration) { const rates = { '1h': 0.01, '1d': 0.02, '1w': 0.05, '1m': 0.15 }; return Math.floor(amount * (rates[duration] || 0)); } function getInvestmentReturn(duration) { const rates = { '1h': 1.05, '1d': 1.1, '1w': 1.25, '1m': 1.5 }; return rates[duration] || 1.1; } function calculateAvailableBalance(userBankData) { let locked = 0; const now = new Date(); userBankData.deposits.forEach(deposit => { if (!deposit.withdrawable && deposit.maturesAt && new Date(deposit.maturesAt) > now) { locked += deposit.amount; } }); return userBankData.bankBalance - locked; }