alerts v3 wip
This commit is contained in:
parent
9a31a83af3
commit
6b31263632
|
@ -3,9 +3,6 @@
|
|||
"version": "1.0.0",
|
||||
"main": "build/index",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "12.14.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"postinstall": "tsc",
|
||||
|
@ -33,7 +30,7 @@
|
|||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-client": "https://github.com/blockworks-foundation/mango-client-ts.git#5_tokens",
|
||||
"@blockworks-foundation/mango-client": "^3.2.9",
|
||||
"@koa/cors": "^3.1.0",
|
||||
"@solana/web3.js": "^1.2.6",
|
||||
"dotenv": "^8.2.0",
|
||||
|
@ -47,6 +44,7 @@
|
|||
"node-fetch": "^2.6.1",
|
||||
"node-telegram-bot-api": "^0.52.0",
|
||||
"nodemailer": "^6.5.0",
|
||||
"nodemailer-mailjet-transport": "^1.0.4",
|
||||
"twilio": "^3.60.0",
|
||||
"winston": "^3.3.3",
|
||||
"winston-discord-transport": "^1.3.0"
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
import * as dotenv from 'dotenv';
|
||||
import * as dotenv from "dotenv"
|
||||
|
||||
dotenv.config();
|
||||
dotenv.config()
|
||||
|
||||
export default {
|
||||
rpcEndpoint: process.env.RPC_ENDPOINT || '',
|
||||
dbConnectionString: (process.env.NODE_ENV == 'production') ?
|
||||
`mongodb://${process.env.DB_USER}:${encodeURIComponent(process.env.DB_PASS || '')}@${process.env.DB_HOSTS}/${process.env.DB}${process.env.DB_OPTIONS}`:
|
||||
'mongodb://localhost:27017/mango_alerts',
|
||||
db: process.env.DB || '',
|
||||
rpcEndpoint: process.env.RPC_ENDPOINT || "",
|
||||
dbConnectionString:
|
||||
`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@${process.env.DB_CLUSTER}.fqb1s.mongodb.net/${process.env.DB}?retryWrites=true&w=majority` ||
|
||||
"",
|
||||
db: process.env.DB || "",
|
||||
port: process.env.PORT || 3000,
|
||||
|
||||
twilioSid: process.env.TWILIO_ACCOUNT_SID || '',
|
||||
twilioToken: process.env.TWILIO_AUTH_TOKEN || '',
|
||||
twilioNumber: process.env.TWILIO_PHONE_NUMBER || '',
|
||||
twilioSid: process.env.TWILIO_ACCOUNT_SID || "",
|
||||
twilioToken: process.env.TWILIO_AUTH_TOKEN || "",
|
||||
twilioNumber: process.env.TWILIO_PHONE_NUMBER || "",
|
||||
|
||||
mailUser: process.env.MAIL_USER || '',
|
||||
mailPass: process.env.MAIL_PASS || '',
|
||||
|
||||
tgToken: process.env.TG_TOKEN || '',
|
||||
|
||||
discordWebhook: process.env.DISCORD_WEBHOOK || ''
|
||||
mailUser: process.env.MAIL_USER || "",
|
||||
mailJetKey: process.env.MAILJET_KEY || "",
|
||||
mailJetSecret: process.env.MAILJET_SECRET || "",
|
||||
// tgToken: process.env.TG_TOKEN || '',
|
||||
// discordWebhook: process.env.DISCORD_WEBHOOK || ''
|
||||
}
|
||||
|
|
285
src/index.ts
285
src/index.ts
|
@ -1,149 +1,222 @@
|
|||
import Koa from "koa"
|
||||
import Router from "koa-router"
|
||||
import mongo from "koa-mongo"
|
||||
import bodyParser from "koa-bodyparser"
|
||||
import cors from "@koa/cors"
|
||||
import * as cron from "node-cron"
|
||||
import { MongoClient, ObjectId } from "mongodb"
|
||||
|
||||
import Koa from "koa";
|
||||
import Router from "koa-router";
|
||||
import mongo from "koa-mongo";
|
||||
import bodyParser from "koa-bodyparser";
|
||||
import cors from "@koa/cors";
|
||||
import * as cron from "node-cron";
|
||||
import {MongoClient, ObjectId} from "mongodb";
|
||||
import {
|
||||
Cluster,
|
||||
Config,
|
||||
GroupConfig,
|
||||
MangoClient,
|
||||
MangoAccount,
|
||||
IDS,
|
||||
} from "@blockworks-foundation/mango-client"
|
||||
import { Commitment, Connection, PublicKey } from "@solana/web3.js"
|
||||
|
||||
import { MangoClient, MarginAccount, IDS } from '@blockworks-foundation/mango-client';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { UserError } from "./errors"
|
||||
// import { sendLogsToDiscord } from "./logger"
|
||||
import {
|
||||
// initiateTelegramBot,
|
||||
// generateTelegramCode,
|
||||
validateMangoAccount,
|
||||
// validatePhoneNumber,
|
||||
validateEmail,
|
||||
reduceMangoGroups,
|
||||
sendAlert,
|
||||
} from "./utils"
|
||||
import config from "./environment"
|
||||
|
||||
import { UserError } from './errors';
|
||||
import { sendLogsToDiscord } from './logger';
|
||||
import { initiateTelegramBot, generateTelegramCode, validateMarginAccount, validatePhoneNumber, validateEmail, reduceMangoGroups, sendAlert } from './utils';
|
||||
import config from './environment';
|
||||
const MESSAGE = "Your health ratio is at or below @ratio@% \n"
|
||||
|
||||
const MESSAGE = 'Your collateral ratio is at or below @ratio@% \n';
|
||||
const app = new Koa()
|
||||
const router = new Router()
|
||||
|
||||
const app = new Koa();
|
||||
const router = new Router;
|
||||
// const rpcUrl = "https://mango.rpcpool.com/946ef7337da3f5b8d3e4a34e7f88"
|
||||
|
||||
const cluster = 'mainnet-beta';
|
||||
const client = new MangoClient();
|
||||
const clusterIds = IDS[cluster];
|
||||
const connection = new Connection(config.rpcEndpoint || IDS.cluster_urls[cluster], 'singleGossip');
|
||||
const dexProgramId = new PublicKey(clusterIds.dex_program_id);
|
||||
const mangoProgramId = new PublicKey(clusterIds.mango_program_id);
|
||||
let db: any;
|
||||
const clientConfig = new Config(IDS)
|
||||
|
||||
app.use(cors());
|
||||
app.use(bodyParser());
|
||||
app.use(mongo({ uri: config.dbConnectionString }, { useUnifiedTopology: true }));
|
||||
const cluster = (process.env.CLUSTER || "mainnet") as Cluster
|
||||
const groupName = process.env.GROUP || "mainnet.1"
|
||||
const groupIds = clientConfig.getGroup(cluster, groupName)
|
||||
if (!groupIds) {
|
||||
throw new Error(`Group ${groupName} not found`)
|
||||
}
|
||||
|
||||
initiateTelegramBot();
|
||||
const mangoProgramId = groupIds.mangoProgramId
|
||||
// const mangoGroupKey = groupIds.publicKey
|
||||
|
||||
router.post('/alerts', async(ctx, next) => {
|
||||
const connection = new Connection(
|
||||
process.env.ENDPOINT_URL || clientConfig.cluster_urls[cluster],
|
||||
"processed" as Commitment
|
||||
)
|
||||
|
||||
const client = new MangoClient(connection, mangoProgramId)
|
||||
|
||||
let db: any
|
||||
|
||||
app.use(cors())
|
||||
app.use(bodyParser())
|
||||
app.use(
|
||||
mongo(
|
||||
{
|
||||
uri: config.dbConnectionString,
|
||||
},
|
||||
{ useUnifiedTopology: true }
|
||||
)
|
||||
)
|
||||
|
||||
// initiateTelegramBot()
|
||||
|
||||
router.post("/alerts", async (ctx, next) => {
|
||||
try {
|
||||
const alert: any = ctx.request.body;
|
||||
await validateMarginAccount(client, connection, dexProgramId, alert);
|
||||
if (alert.alertProvider == 'sms') {
|
||||
const phoneNumber = `+${alert.phoneNumber.code}${alert.phoneNumber.phone}`;
|
||||
await validatePhoneNumber(phoneNumber);
|
||||
ctx.body = { status: 'success' };
|
||||
} else if (alert.alertProvider == 'mail') {
|
||||
validateEmail(alert.email);
|
||||
ctx.body = { status: 'success' };
|
||||
} else if (alert.alertProvider == 'tg') {
|
||||
const code = generateTelegramCode();
|
||||
alert.tgCode = code;
|
||||
ctx.body = { code };
|
||||
const alert: any = ctx.request.body
|
||||
// await validateMangoAccount(client, alert)
|
||||
if (alert.alertProvider == "mail") {
|
||||
validateEmail(alert.email)
|
||||
ctx.body = { status: "success" }
|
||||
} else {
|
||||
throw new UserError('Invalid alert provider');
|
||||
throw new UserError("Invalid alert provider")
|
||||
}
|
||||
alert.open = true;
|
||||
alert.timestamp = Date.now();
|
||||
ctx.db.collection('alerts').insertOne(alert);
|
||||
} catch (e) {
|
||||
let errorMessage = 'Something went wrong';
|
||||
if (e.name == 'UserError') {
|
||||
errorMessage = e.message;
|
||||
alert.open = true
|
||||
alert.timestamp = Date.now()
|
||||
ctx.db.collection("alerts").insertOne(alert)
|
||||
} catch (e: any) {
|
||||
let errorMessage = "Something went wrong"
|
||||
if (e.name == "UserError") {
|
||||
errorMessage = e.message
|
||||
} else {
|
||||
sendLogsToDiscord(null, e);
|
||||
// sendLogsToDiscord(null, e)
|
||||
}
|
||||
ctx.throw(400, errorMessage);
|
||||
ctx.throw(400, errorMessage)
|
||||
}
|
||||
await next();
|
||||
});
|
||||
await next()
|
||||
})
|
||||
|
||||
router.get('/alerts/:marginAccountPk', async(ctx, next) => {
|
||||
router.post("/delete-alert", async (ctx, next) => {
|
||||
try {
|
||||
const { marginAccountPk } = ctx.params;
|
||||
if (!marginAccountPk) {
|
||||
throw new UserError('Missing margin account');
|
||||
const id: any = new ObjectId(ctx.request.body.id)
|
||||
if (id) {
|
||||
ctx.body = { status: "success" }
|
||||
}
|
||||
const alerts = await ctx.db.collection('alerts').find(
|
||||
{ marginAccountPk },
|
||||
{ projection: {
|
||||
'_id': 0,
|
||||
'collateralRatioThresh': 1,
|
||||
'alertProvider': 1,
|
||||
'open': 1,
|
||||
'timestamp': 1,
|
||||
'triggeredTimestamp': 1
|
||||
}}).toArray();
|
||||
ctx.body = { alerts };
|
||||
} catch (e) {
|
||||
let errorMessage = 'Something went wrong';
|
||||
if (e.name == 'UserError') {
|
||||
errorMessage = e.message;
|
||||
ctx.db.collection("alerts").deleteOne({ _id: id })
|
||||
} catch (e: any) {
|
||||
let errorMessage = "Something went wrong"
|
||||
if (e.name == "UserError") {
|
||||
errorMessage = e.message
|
||||
}
|
||||
ctx.throw(400, errorMessage)
|
||||
}
|
||||
await next()
|
||||
})
|
||||
|
||||
router.get("/alerts/:mangoAccountPk", async (ctx, next) => {
|
||||
try {
|
||||
const { mangoAccountPk } = ctx.params
|
||||
if (!mangoAccountPk) {
|
||||
throw new UserError("Missing margin account")
|
||||
}
|
||||
const alerts = await ctx.db
|
||||
.collection("alerts")
|
||||
.find(
|
||||
{ mangoAccountPk },
|
||||
{
|
||||
projection: {
|
||||
_id: 1,
|
||||
health: 1,
|
||||
alertProvider: 1,
|
||||
open: 1,
|
||||
timestamp: 1,
|
||||
triggeredTimestamp: 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.toArray()
|
||||
ctx.body = { alerts }
|
||||
} catch (e: any) {
|
||||
let errorMessage = "Something went wrong"
|
||||
if (e.name == "UserError") {
|
||||
errorMessage = e.message
|
||||
} else {
|
||||
sendLogsToDiscord(null, e);
|
||||
// sendLogsToDiscord(null, e)
|
||||
}
|
||||
ctx.throw(400, errorMessage);
|
||||
ctx.throw(400, errorMessage)
|
||||
}
|
||||
})
|
||||
|
||||
app.use(router.allowedMethods());
|
||||
app.use(router.routes());
|
||||
app.use(router.allowedMethods())
|
||||
app.use(router.routes())
|
||||
|
||||
app.listen(config.port, () => {
|
||||
const readyMessage = `> Server ready on http://localhost:${config.port}`;
|
||||
const readyMessage = `> Server ready on http://localhost:${config.port}`
|
||||
console.log(readyMessage)
|
||||
sendLogsToDiscord(readyMessage, null);
|
||||
});
|
||||
// sendLogsToDiscord(readyMessage, null)
|
||||
})
|
||||
|
||||
const handleAlert = async (alert: any, mangoGroups: any[], db: any) => {
|
||||
const handleAlert = async (alert: any, db: any) => {
|
||||
try {
|
||||
const mangoGroupMapping = mangoGroups[alert.mangoGroupPk];
|
||||
const marginAccountPk = new PublicKey(alert.marginAccountPk);
|
||||
const marginAccount = mangoGroupMapping.marginAccounts.find((ma: MarginAccount) => ma.publicKey.equals(marginAccountPk));
|
||||
const collateralRatio = marginAccount.getCollateralRatio(mangoGroupMapping['mangoGroup'], mangoGroupMapping['prices']);
|
||||
if ((100 * collateralRatio) <= alert.collateralRatioThresh) {
|
||||
let message = MESSAGE.replace('@ratio@', alert.collateralRatioThresh);
|
||||
message += marginAccount.toPrettyString(
|
||||
mangoGroupMapping['mangoGroup'],
|
||||
mangoGroupMapping['prices']
|
||||
);
|
||||
message += '\nVisit https://trade.mango.markets/'
|
||||
const alertSent = await sendAlert(alert, message);
|
||||
const mangoAccountPk = new PublicKey(alert.mangoAccountPk)
|
||||
const mangoGroupPk = new PublicKey(alert.mangoGroupPk)
|
||||
const mangoGroup = await client.getMangoGroup(mangoGroupPk)
|
||||
const mangoCache = await mangoGroup.loadCache(connection)
|
||||
const mangoAccount = await client.getMangoAccount(
|
||||
mangoAccountPk,
|
||||
mangoGroup.dexProgramId
|
||||
)
|
||||
const health = await mangoAccount.getHealthRatio(
|
||||
mangoGroup,
|
||||
mangoCache,
|
||||
"Maint"
|
||||
)
|
||||
if (health.toNumber() <= parseFloat(alert.health)) {
|
||||
let message = MESSAGE.replace("@ratio@", alert.health)
|
||||
message += mangoAccount.name || alert.mangoAccountPk
|
||||
message += "\nVisit https://trade.mango.markets/"
|
||||
const alertSent = await sendAlert(alert, message)
|
||||
if (alertSent) {
|
||||
db.collection('alerts').updateOne({ _id: new ObjectId(alert._id) }, { '$set': { open: false, triggeredTimestamp: Date.now() } });
|
||||
db.collection("alerts").updateOne(
|
||||
{ _id: new ObjectId(alert._id) },
|
||||
{ $set: { open: false, triggeredTimestamp: Date.now() } }
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
sendLogsToDiscord(null, e);
|
||||
console.log(e)
|
||||
// sendLogsToDiscord(null, e)
|
||||
}
|
||||
}
|
||||
|
||||
const runCron = async () => {
|
||||
const mongoConnection = await MongoClient.connect(config.dbConnectionString, { useUnifiedTopology: true });
|
||||
if (!db) db = mongoConnection.db(config.db);
|
||||
const uri = config.dbConnectionString
|
||||
const mongoClient = new MongoClient(uri, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
})
|
||||
const mongoConnection = await mongoClient.connect()
|
||||
if (!db) db = mongoConnection.db("mango")
|
||||
cron.schedule("* * * * *", async () => {
|
||||
try {
|
||||
const alerts: any[] = await db.collection('alerts').find({open: true}).toArray();
|
||||
const uniqueMangoGroupPks: string[] = [...new Set(alerts.map(alert => alert.mangoGroupPk))];
|
||||
const mangoGroups:any = await reduceMangoGroups(client, connection, mangoProgramId, uniqueMangoGroupPks);
|
||||
const alerts: any[] = await db
|
||||
.collection("alerts")
|
||||
.find({ open: true })
|
||||
.toArray()
|
||||
console.log(alerts)
|
||||
// const uniqueMangoGroupPks: string[] = [
|
||||
// ...new Set(alerts.map((alert) => alert.mangoGroupPk)),
|
||||
// ]
|
||||
// const mangoGroups: any = await reduceMangoGroups(
|
||||
// client,
|
||||
// uniqueMangoGroupPks
|
||||
// )
|
||||
alerts.forEach(async (alert) => {
|
||||
handleAlert(alert, mangoGroups, db);
|
||||
});
|
||||
const expiryTime = Date.now() - (1000 * 60 * 15); // 15 Minutes
|
||||
db.collection('alerts').deleteMany({ alertProvider: 'tg', tgChatId: { '$exists': false }, timestamp: { '$lt': expiryTime } });
|
||||
handleAlert(alert, db)
|
||||
})
|
||||
} catch (e) {
|
||||
sendLogsToDiscord(null, e);
|
||||
// sendLogsToDiscord(null, e)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
runCron();
|
||||
runCron()
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
import winston from "winston";
|
||||
import DiscordTransport from "winston-discord-transport";
|
||||
import config from './environment';
|
||||
import winston from "winston"
|
||||
import DiscordTransport from "winston-discord-transport"
|
||||
import config from "./environment"
|
||||
|
||||
const logger = winston.createLogger({
|
||||
transports: [
|
||||
new DiscordTransport({
|
||||
webhook: config.discordWebhook,
|
||||
defaultMeta: { service: "mango_alerts_server" },
|
||||
level: "info"
|
||||
})
|
||||
]
|
||||
});
|
||||
// const logger = winston.createLogger({
|
||||
// transports: [
|
||||
// new DiscordTransport({
|
||||
// webhook: config.discordWebhook,
|
||||
// defaultMeta: { service: "mango_alerts_server" },
|
||||
// level: "info"
|
||||
// })
|
||||
// ]
|
||||
// });
|
||||
|
||||
export const sendLogsToDiscord = async (message: string | null, error: Error | null) => {
|
||||
if (message) {
|
||||
logger.log({
|
||||
level: "info",
|
||||
message: message,
|
||||
});
|
||||
} else if (error) {
|
||||
logger.log({
|
||||
level: "error",
|
||||
message: error.message,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
}
|
||||
// export const sendLogsToDiscord = async (message: string | null, error: Error | null) => {
|
||||
// if (message) {
|
||||
// logger.log({
|
||||
// level: "info",
|
||||
// message: message,
|
||||
// });
|
||||
// } else if (error) {
|
||||
// logger.log({
|
||||
// level: "error",
|
||||
// message: error.message,
|
||||
// error: error
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
|
224
src/utils.ts
224
src/utils.ts
|
@ -1,132 +1,158 @@
|
|||
import { Twilio } from "twilio";
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import * as TelegramBot from 'node-telegram-bot-api';
|
||||
import * as EmailValidator from 'email-validator';
|
||||
import { MongoClient } from "mongodb";
|
||||
// import { Twilio } from "twilio"
|
||||
// import * as mailjetTransport from 'nodemailer-mailjet-transport'
|
||||
// import * as TelegramBot from "node-telegram-bot-api"
|
||||
// import { MongoClient } from "mongodb"
|
||||
import * as nodemailer from "nodemailer"
|
||||
import * as EmailValidator from "email-validator"
|
||||
|
||||
import { MangoClient } from '@blockworks-foundation/mango-client';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { MangoClient } from "@blockworks-foundation/mango-client"
|
||||
import { PublicKey } from "@solana/web3.js"
|
||||
|
||||
import { UserError } from './errors';
|
||||
import { UserError } from "./errors"
|
||||
|
||||
import config from './environment';
|
||||
import config from "./environment"
|
||||
|
||||
// This needs to be global because it uses event listeners
|
||||
const bot = new TelegramBot.default(config.tgToken, {polling: true});
|
||||
const twilioClient = new Twilio(config.twilioSid, config.twilioToken);
|
||||
const mailjetTransport = require("nodemailer-mailjet-transport")
|
||||
|
||||
export const validateMarginAccount = (client: MangoClient, connection: Connection, dexProgramId: PublicKey, alert: any) => {
|
||||
// // This needs to be global because it uses event listeners
|
||||
// // const bot = new TelegramBot.default(config.tgToken, {polling: true});
|
||||
// const twilioClient = new Twilio(config.twilioSid, config.twilioToken)
|
||||
|
||||
export const validateMangoAccount = (client: MangoClient, alert: any) => {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
try {
|
||||
const mangoGroupPk = new PublicKey(alert.mangoGroupPk);
|
||||
const marginAccountPk = new PublicKey(alert.marginAccountPk);
|
||||
const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk);
|
||||
const marginAccount = await client.getMarginAccount(connection, marginAccountPk, dexProgramId);
|
||||
if (!mangoGroup || !marginAccount) {
|
||||
reject(new UserError('Invalid margin account or mango group'));
|
||||
const mangoGroupPk = new PublicKey(alert.mangoGroupPk)
|
||||
const mangoAccountPk = new PublicKey(alert.marginAccountPk)
|
||||
const mangoGroup = await client.getMangoGroup(mangoGroupPk)
|
||||
const mangoAccount = await client.getMangoAccount(
|
||||
mangoAccountPk,
|
||||
mangoGroup.dexProgramId
|
||||
)
|
||||
if (!mangoGroup || !mangoAccount) {
|
||||
reject(new UserError("Invalid margin account or mango group"))
|
||||
} else {
|
||||
resolve();
|
||||
resolve()
|
||||
}
|
||||
} catch (e) {
|
||||
reject(new UserError('Invalid margin account or mango group'));
|
||||
reject(new UserError("Invalid margin account or mango group"))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const validatePhoneNumber = (phoneNumber: string) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
twilioClient.lookups.phoneNumbers(phoneNumber).fetch((e, _) => {
|
||||
if (e) {
|
||||
reject(new UserError('The entered phone number is incorrect'));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// export const validatePhoneNumber = (phoneNumber: string) => {
|
||||
// return new Promise<void>((resolve, reject) => {
|
||||
// twilioClient.lookups.phoneNumbers(phoneNumber).fetch((e, _) => {
|
||||
// if (e) {
|
||||
// reject(new UserError("The entered phone number is incorrect"))
|
||||
// } else {
|
||||
// resolve()
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
|
||||
export const validateEmail = (email: string) => {
|
||||
if (!EmailValidator.validate(email)) {
|
||||
throw new UserError('The entered email is incorrect');
|
||||
throw new UserError("The entered email is incorrect")
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const sendSms = (phoneNumber: string, message: string) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
twilioClient.messages
|
||||
.create({
|
||||
from: config.twilioNumber,
|
||||
to: phoneNumber,
|
||||
body: message,
|
||||
// const sendSms = (phoneNumber: string, message: string) => {
|
||||
// return new Promise<void>((resolve, reject) => {
|
||||
// twilioClient.messages
|
||||
// .create({
|
||||
// from: config.twilioNumber,
|
||||
// to: phoneNumber,
|
||||
// body: message,
|
||||
// })
|
||||
// .then((_) => resolve())
|
||||
// .catch((e) => reject(e))
|
||||
// })
|
||||
// }
|
||||
|
||||
const sendEmail = async (email: string, message: string) => {
|
||||
const transport = nodemailer.createTransport(
|
||||
mailjetTransport({
|
||||
auth: {
|
||||
apiKey: config.mailJetKey,
|
||||
apiSecret: config.mailJetSecret,
|
||||
},
|
||||
})
|
||||
.then(_ => resolve())
|
||||
.catch(e => reject(e))
|
||||
});
|
||||
}
|
||||
|
||||
const sendEmail = (email: string, message: string) => {
|
||||
const transporter = nodemailer.createTransport(
|
||||
`smtps://${config.mailUser}%40gmail.com:${config.mailPass}@smtp.gmail.com`
|
||||
);
|
||||
)
|
||||
const mailOptions = {
|
||||
from : `${config.mailUser}@gmail.com`,
|
||||
to : email,
|
||||
subject : 'Mango Markets Alerts',
|
||||
text: message
|
||||
};
|
||||
transporter.sendMail( mailOptions );
|
||||
from: `${config.mailUser}@mango.markets`,
|
||||
to: email,
|
||||
subject: "Mango Alerts",
|
||||
text: message,
|
||||
}
|
||||
|
||||
try {
|
||||
const info = await transport.sendMail(mailOptions)
|
||||
console.log(info)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
transport.sendMail(mailOptions)
|
||||
}
|
||||
|
||||
export const sendAlert = async (alert: any, message: string) => {
|
||||
if (alert.alertProvider == 'sms') {
|
||||
const phoneNumber = `+${alert.phoneNumber.code}${alert.phoneNumber.phone}`;
|
||||
await sendSms(phoneNumber, message);
|
||||
} else if (alert.alertProvider == 'mail') {
|
||||
const email = alert.email;
|
||||
sendEmail(email, message);
|
||||
} else if (alert.alertProvider == 'tg') {
|
||||
if (!alert.tgChatId) return false;
|
||||
bot.sendMessage(alert.tgChatId, message);
|
||||
if (alert.alertProvider == "mail") {
|
||||
const email = alert.email
|
||||
sendEmail(email, message)
|
||||
}
|
||||
return true;
|
||||
// else if (alert.alertProvider == "sms") {
|
||||
// const phoneNumber = `+${alert.phoneNumber.code}${alert.phoneNumber.phone}
|
||||
// await sendSms(phoneNumber, message)
|
||||
// }
|
||||
// else if (alert.alertProvider == 'tg') {
|
||||
// if (!alert.tgChatId) return false;
|
||||
// bot.sendMessage(alert.tgChatId, message);
|
||||
// }
|
||||
return true
|
||||
}
|
||||
|
||||
export const reduceMangoGroups = async (client: MangoClient, connection: Connection, mangoProgramId: PublicKey, mangoGroupPks: string[]) => {
|
||||
const mangoGroups:any = {};
|
||||
export const reduceMangoGroups = async (
|
||||
client: MangoClient,
|
||||
// connection: Connection,
|
||||
// mangoProgramId: PublicKey,
|
||||
mangoGroupPks: string[]
|
||||
) => {
|
||||
const mangoGroups: any = {}
|
||||
for (let mangoGroupPk of mangoGroupPks) {
|
||||
const mangoGroup = await client.getMangoGroup(connection, new PublicKey(mangoGroupPk));
|
||||
const marginAccounts = await client.getAllMarginAccounts(connection, mangoProgramId, mangoGroup);
|
||||
const mangoGroup = await client.getMangoGroup(new PublicKey(mangoGroupPk))
|
||||
const mangoAccounts = await client.getAllMangoAccounts(mangoGroup)
|
||||
mangoGroups[mangoGroupPk] = {
|
||||
mangoGroup,
|
||||
marginAccounts,
|
||||
prices: await mangoGroup.getPrices(connection),
|
||||
};
|
||||
}
|
||||
return mangoGroups;
|
||||
}
|
||||
|
||||
export const initiateTelegramBot = () => {
|
||||
bot.on('message', async (message: any) => {
|
||||
const mongoConnection = await MongoClient.connect(config.dbConnectionString, { useUnifiedTopology: true });
|
||||
const db = mongoConnection.db(config.db);
|
||||
const tgCode = message.text;
|
||||
const alert = await db.collection('alerts').findOne({tgCode});
|
||||
if (alert) {
|
||||
await db.collection('alerts').updateOne({ tgCode }, {'$set': { tgChatId: message.chat.id } } );
|
||||
bot.sendMessage(message.chat.id, 'Thanks, You have successfully claimed your alert\nYou can now close the dialogue on website');
|
||||
} else {
|
||||
bot.sendMessage(message.chat.id, 'Sorry, this code is either invalid or expired');
|
||||
mangoAccounts,
|
||||
// prices: await mangoGroup.getPrices(connection),
|
||||
}
|
||||
mongoConnection.close();
|
||||
});
|
||||
}
|
||||
return mangoGroups
|
||||
}
|
||||
|
||||
export const generateTelegramCode = () => {
|
||||
var text = "";
|
||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (let i = 0; i < 5; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
// export const initiateTelegramBot = () => {
|
||||
// bot.on('message', async (message: any) => {
|
||||
// const mongoConnection = await MongoClient.connect(config.dbConnectionString, { useUnifiedTopology: true });
|
||||
// const db = mongoConnection.db(config.db);
|
||||
// const tgCode = message.text;
|
||||
// const alert = await db.collection('alerts').findOne({tgCode});
|
||||
// if (alert) {
|
||||
// await db.collection('alerts').updateOne({ tgCode }, {'$set': { tgChatId: message.chat.id } } );
|
||||
// bot.sendMessage(message.chat.id, 'Thanks, You have successfully claimed your alert\nYou can now close the dialogue on website');
|
||||
// } else {
|
||||
// bot.sendMessage(message.chat.id, 'Sorry, this code is either invalid or expired');
|
||||
// }
|
||||
// mongoConnection.close();
|
||||
// });
|
||||
// }
|
||||
|
||||
// export const generateTelegramCode = () => {
|
||||
// var text = ""
|
||||
// var possible =
|
||||
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
// for (let i = 0; i < 5; i++) {
|
||||
// text += possible.charAt(Math.floor(Math.random() * possible.length))
|
||||
// }
|
||||
// return text
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue