Skip to content

Commit

Permalink
chore: seperate concerns
Browse files Browse the repository at this point in the history
  • Loading branch information
sudotx committed Jul 21, 2024
1 parent 25d8479 commit fcd918b
Show file tree
Hide file tree
Showing 10 changed files with 2,354 additions and 220 deletions.
205 changes: 5 additions & 200 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,7 @@ import bot from '@/helpers/bot'
import startMongo from '@/helpers/startMongo'
import attachUser from '@/middlewares/attachUser'
import { run } from '@grammyjs/runner'
import { InlineKeyboard } from 'grammy'
import { ignoreOld, sequentialize } from 'grammy-middlewares'
import { fetchNeko, getNsfwNeko } from './helpers/utils'

const mainMenu = new InlineKeyboard()
.text('Connect Wallet', 'connect_wallet')
.row()
.text('Check Balance', 'check_balance')
.row()
.text('View Strategies', 'view_strategies')
.row()
.text('Performance', 'performance');

bot.api.setMyCommands([
{ command: 'menu', description: 'Show main menu' },
Expand All @@ -26,197 +15,13 @@ bot.api.setMyCommands([
{ command: 'invest', description: 'Invest in a strategy' },
]);

const strategies = [
{ id: 1, name: "Deposit USDC to Aave" },
{ id: 2, name: "Create ETH-USDC LP on Uniswap" },
{ id: 3, name: "Swap ETH to USDC on 1inch" },
];

bot.command('menu', (ctx) => {
ctx.reply('Welcome! Please choose an option:', {
reply_markup: mainMenu
});
});

bot.command('help', (ctx) => {
ctx.reply(`
Available commands:
/menu - Show main menu
/help - Show this help message
Use the menu buttons to:
- Connect your wallet
- Check your balance
- View available strategies
- Check your investment performance
`);
});

bot.command('invest', async (ctx) => {
// if (!ctx.session.walletAddress) {
// return ctx.reply("Please connect your wallet first using the menu.");
// }

// const parts = ctx.message.text.split(' ');
// if (parts.length !== 3) {
// return ctx.reply("Invalid format. Use: /invest <strategy_id> <amount>");
// }

// const strategyId = Number(parts[1]);
// const amount = Number(parts[2]);

// if (isNaN(strategyId) || isNaN(amount)) {
// return ctx.reply("Invalid strategy ID or amount.");
// }

// const strategy = strategies.find(s => s.id === strategyId);
// if (!strategy) {
// return ctx.reply("Invalid strategy ID.");
// }

// // Here you would implement the actual investment logic
// ctx.reply(`Simulating investment of ${amount} USDC in strategy: ${strategy.name}`);
// Implement actual blockchain interaction here
});

bot.command('invest', async (ctx) => {
// if (!ctx.session.walletAddress || !ctx.session.walletPrivateKey) {
// return ctx.reply("You don't have a connected wallet. Use the 'Connect Wallet' option to create one.");
// }

// const parts = ctx.message.text.split(' ');
// if (parts.length !== 3) {
// return ctx.reply("Invalid format. Use: /invest <strategy_id> <amount>");
// }

// const strategyId = Number(parts[1]);
// const amount = Number(parts[2]);

// if (isNaN(strategyId) || isNaN(amount)) {
// return ctx.reply("Invalid strategy ID or amount.");
// }

// const strategy = strategies.find(s => s.id === strategyId);
// if (!strategy) {
// return ctx.reply("Invalid strategy ID.");
// }

// Here you would implement the actual investment logic
// You can use ctx.session.walletAddress and ctx.session.walletPrivateKey to sign transactions
// const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_RPC_URL);
// const wallet = new ethers.Wallet(ctx.session.walletPrivateKey, provider);

// ctx.reply(`Simulating investment of ${amount} USDC in strategy: ${strategy.name} from wallet ${wallet.address}`);
// Implement actual blockchain interaction here using the wallet
});

bot.command('wallet', async (ctx) => {
// if (ctx.session.walletAddress) {
// await ctx.reply(`Your wallet address: ${ctx.session.walletAddress}`);
// } else {
// await ctx.reply("You don't have a connected wallet. Use the 'Connect Wallet' option to create one.");
// }
});

bot.callbackQuery('get_neko', async (ctx) => {
try {
const imageUrl = await fetchNeko();

await ctx.reply(imageUrl)
} catch (error) {
await ctx.reply('An error occurred while fetching the neko image.');
}
await ctx.answerCallbackQuery();
});

bot.callbackQuery('get_nsfw_neko', async (ctx) => {
try {
const imageUrl = await getNsfwNeko();

await ctx.reply(imageUrl)
} catch (error) {
await ctx.reply('An error occurred while fetching the neko image.');
}
await ctx.answerCallbackQuery();
});

bot.callbackQuery('earn', async (ctx) => {
try {
ctx.reply("Okay earning")
} catch (error) {
await ctx.reply('An Error Occurred While Earning.');
}
await ctx.answerCallbackQuery();
});

bot.callbackQuery('connect_wallet', async (ctx) => {
// ctx.session.awaitingWalletAddress = true;
// await ctx.reply("Please send your Ethereum wallet address.");
// await ctx.answerCallbackQuery();
});

bot.callbackQuery('check_balance', async (ctx) => {
// if (!ctx.session.walletAddress) {
// await ctx.reply("Please connect your wallet first.");
// await ctx.answerCallbackQuery();
// return;
// }

// const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_RPC_URL);
// try {
// const balance = await provider.getBalance(ctx.session.walletAddress);
// await ctx.reply(`Your ETH balance: ${ethers.utils.formatEther(balance)} ETH`);
// } catch (error) {
// await ctx.reply('An error occurred while fetching your balance.');
// }
// await ctx.answerCallbackQuery();
});

bot.callbackQuery('view_strategies', async (ctx) => {
const strategyList = strategies.map(s => `${s.id}. ${s.name}`).join('\n');
await ctx.reply(`Available strategies:\n${strategyList}\n\nTo invest, use /invest <strategy_id> <amount>`);
await ctx.answerCallbackQuery();
});

bot.callbackQuery('performance', async (ctx) => {
// For MVP, we'll just return a placeholder message
await ctx.reply("Performance tracking is coming soon!");
await ctx.answerCallbackQuery();
});

bot.callbackQuery('connect_wallet', async (ctx) => {
// if (ctx.session.walletAddress) {
// await ctx.reply("You already have a connected wallet.");
// } else {
// // Generate a new wallet
// const wallet = ethers.Wallet.createRandom();

// ctx.session.walletAddress = wallet.address;
// ctx.session.walletPrivateKey = wallet.privateKey;

// await ctx.reply(`New wallet generated for you!\nAddress: ${wallet.address}\n\nIMPORTANT: Please store this recovery phrase safely and never share it:\n${wallet.mnemonic.phrase}`);
// await ctx.reply("Your wallet is now connected and ready to use.");
// }
// await ctx.answerCallbackQuery();
});

bot.on('message:text', async (ctx) => {
// if (ctx.session.awaitingWalletAddress) {
// if (ethers.utils.isAddress(ctx.message.text)) {
// ctx.session.walletAddress = ctx.message.text;
// ctx.session.awaitingWalletAddress = false;
// await ctx.reply(`Wallet connected: ${ctx.session.walletAddress}`);
// } else {
// await ctx.reply("Invalid address. Please send a valid Ethereum address.");
// }
// }
});

(async function () {
console.log('Starting up...')

try {
await startMongo()
console.log('Database connected')
await startMongo().then(() => {
console.log('Database connected')
}).finally(() => {
console.log('Starting up...')
})

bot
.use(sequentialize())
Expand Down
10 changes: 10 additions & 0 deletions src/callbacks/check_balances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Bot } from 'grammy';
import strategies from '../config';

export const viewStrategiesCallback = (bot: Bot) => {
bot.callbackQuery('view_strategies', async (ctx) => {
const strategyList = strategies.strategies.map(s => `${s.id}. ${s.name}`).join('\n');
await ctx.reply(`Available strategies:\n${strategyList}\n\nTo invest, use /invest <strategy_id> <amount>`);
await ctx.answerCallbackQuery();
});
};
19 changes: 19 additions & 0 deletions src/callbacks/generate_wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { fetchNeko } from '@/helpers/utils';
import { ethers } from 'ethers';
import { Bot } from 'grammy';

export const viewStrategiesCallback = (bot: Bot) => {
bot.callbackQuery('generate_wallet', async (ctx) => {
await ctx.reply("You already have a connected wallet.");

// Generate a new wallet
const wallet = ethers.Wallet.createRandom();

const imageUrl = await fetchNeko();

await ctx.reply(imageUrl)
await ctx.reply(`New wallet generated for you!\nAddress: ${wallet.address}\n\nIMPORTANT: Please store this recovery phrase safely and never share it:\n${wallet.mnemonic?.phrase}`);
await ctx.reply("Your wallet is now connected and ready to use.");
await ctx.answerCallbackQuery();
});
};
10 changes: 10 additions & 0 deletions src/callbacks/view_strategies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Bot } from 'grammy';
import strategies from '../config';

export const viewStrategiesCallback = (bot: Bot) => {
bot.callbackQuery('view_strategies', async (ctx) => {
const strategyList = strategies.strategies.map(s => `${s.id}. ${s.name}`).join('\n');
await ctx.reply(`Available strategies:\n${strategyList}\n\nTo invest, use /invest <strategy_id> <amount>`);
await ctx.answerCallbackQuery();
});
};
16 changes: 16 additions & 0 deletions src/commands/help.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Bot } from 'grammy';

export const helpCommand = (bot: Bot) => {
bot.command('help', (ctx) => {
ctx.reply(`
Available commands:
/menu - Show main menu
/help - Show this help message
Use the menu buttons to:
- Connect your wallet
- Check your balance
- View available strategies
- Check your investment performance
`);
});
};
44 changes: 44 additions & 0 deletions src/commands/invest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Bot } from 'grammy';
import { ethers } from 'ethers';
import strategies from '../config';


export const investCommand = (bot: Bot) => {
bot.command('invest', async (ctx) => {
if (!ctx.message || !ctx.message.text) {
return ctx.reply("Invalid command format.");
}

const parts = ctx.message.text.split(' ');
if (parts.length !== 3) {
return ctx.reply("Invalid format. Use: /invest <strategy_id> <amount>");
}

const strategyId = Number(parts[1]);
const amount = Number(parts[2]);

if (isNaN(strategyId) || isNaN(amount)) {
return ctx.reply("Invalid strategy ID or amount.");
}

const strategy = strategies.strategies.find((s: { id: number; }) => s.id === strategyId);
if (!strategy) {
return ctx.reply("Invalid strategy ID.");
}

ctx.reply(`Simulating investment of ${amount} USDC in strategy: ${strategy.name}`);
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_RPC_URL);
const wallet = new ethers.Wallet("ctx.session.walletPrivateKey", provider);

try {
const tx = await wallet.sendTransaction({
to: "strategyAddress",
value: ethers.parseUnits(amount.toString(), 'usdc'), // Assuming amount is in USDC
});
await ctx.reply(`Investment successful! Transaction hash: ${tx.hash}`);
} catch (error) {
console.error('Investment error:', error);
await ctx.reply('An error occurred while processing your investment.');
}
});
};
18 changes: 18 additions & 0 deletions src/commands/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Bot, InlineKeyboard } from "grammy";

export const menuCommand = (bot: Bot) => {
bot.command('menu', (ctx) => {
const mainMenu = new InlineKeyboard()
.text('Connect Wallet', 'connect_wallet')
.row()
.text('Check Balance', 'check_balance')
.row()
.text('View Strategies', 'view_strategies')
.row()
.text('Performance', 'performance');

ctx.reply('Welcome! Please choose an option:', {
reply_markup: mainMenu
});
});
};
9 changes: 7 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "dotenv"

module.exports = {
export default {
environment: process.env.NODE_ENV || "development",
logLevel: process.env.LOG_LEVEL || "info",

Expand All @@ -20,5 +20,10 @@ module.exports = {
token: process.env.TELEGRAM_TOKEN || "",
chatId: process.env.TELEGRAM_CHAT_ID || ""
}
}
},
strategies: [
{ id: 1, name: "Deposit USDC to Aave" },
{ id: 2, name: "Create ETH-USDC LP on Uniswap" },
{ id: 3, name: "Swap ETH to USDC on 1inch" },
]
}
5 changes: 5 additions & 0 deletions src/models/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { DocumentType } from '@typegoose/typegoose'
import { I18nContext } from '@grammyjs/i18n/dist/source'
import { User } from '@/models/User'

interface SessionData {
walletAddress?: string;
walletPrivateKey?: string;
}

class Context extends BaseContext {
readonly i18n!: I18nContext
dbuser!: DocumentType<User>
Expand Down
Loading

0 comments on commit fcd918b

Please sign in to comment.