initial commit
This commit is contained in:
commit
d6336f26c9
|
@ -0,0 +1,26 @@
|
||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
.idea
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Mango Alerts Server
|
||||||
|
|
||||||
|
Backend logic for the mango alerts provider
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run ```yarn``` to install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
An example ```.env``` file -
|
||||||
|
```
|
||||||
|
DB_USER=<DB_USER>
|
||||||
|
DB_PASS=<DB_PASS>
|
||||||
|
DB_HOSTS=<DB_HOST>
|
||||||
|
DB=<DB>
|
||||||
|
DB_OPTIONS=<DB_OPTIONS>
|
||||||
|
PORT=3010
|
||||||
|
TWILIO_ACCOUNT_SID=<TWILIO_ACCOUNT_SID>
|
||||||
|
TWILIO_AUTH_TOKEN=<TWILIO_AUTH_TOKEN>
|
||||||
|
TWILIO_PHONE_NUMBER=<TWILIO_PHONE_NUMBER>
|
||||||
|
MAIL_USER=<MAIL_USER>
|
||||||
|
MAIL_PASS=<MAIL_PASS>
|
||||||
|
TG_TOKEN=<TG_TOKEN>
|
||||||
|
```
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"watch": ["src"],
|
||||||
|
"ext": ".ts,.js",
|
||||||
|
"ignore": [],
|
||||||
|
"exec": "ts-node ./src/index.ts"
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"name": "mango_alert_server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "build/index",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"postinstall": "tsc",
|
||||||
|
"deploy": "git add . && git commit -m Heroku && git push heroku main",
|
||||||
|
"start": "node --max_old_space_size=1024 --optimize_for_size build/index.js",
|
||||||
|
"start:dev": "ts-node src/index.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tsconfig/node10": "^1.0.7",
|
||||||
|
"@types/email-validator": "^1.0.6",
|
||||||
|
"@types/koa": "^2.13.1",
|
||||||
|
"@types/koa-bodyparser": "^4.3.0",
|
||||||
|
"@types/koa-mongo": "^1.9.0",
|
||||||
|
"@types/koa-router": "^7.4.1",
|
||||||
|
"@types/koa__cors": "^3.0.2",
|
||||||
|
"@types/mongodb": "^3.6.12",
|
||||||
|
"@types/node": "^14.14.37",
|
||||||
|
"@types/node-cron": "^2.0.3",
|
||||||
|
"@types/node-fetch": "^2.5.10",
|
||||||
|
"@types/node-telegram-bot-api": "^0.51.1",
|
||||||
|
"@types/nodemailer": "^6.4.1",
|
||||||
|
"@types/winston": "^2.4.4",
|
||||||
|
"nodemon": "^2.0.7",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@blockworks-foundation/mango-client": "^3.2.9",
|
||||||
|
"@koa/cors": "^3.1.0",
|
||||||
|
"@solana/web3.js": "^1.2.6",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"email-validator": "^2.0.4",
|
||||||
|
"koa": "^2.13.1",
|
||||||
|
"koa-bodyparser": "^4.3.0",
|
||||||
|
"koa-mongo": "^1.9.3",
|
||||||
|
"koa-router": "^10.0.0",
|
||||||
|
"mongodb": "^3.6.6",
|
||||||
|
"node-cron": "^3.0.0",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import * as dotenv from "dotenv"
|
||||||
|
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
export default {
|
||||||
|
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 || "",
|
||||||
|
|
||||||
|
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 || ''
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
export class UserError extends Error {
|
||||||
|
constructor(message = 'Error', ...params: any[]) {
|
||||||
|
// Pass remaining arguments (including vendor specific ones) to parent constructor
|
||||||
|
super(...params);
|
||||||
|
|
||||||
|
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
||||||
|
if (Error.captureStackTrace) {
|
||||||
|
Error.captureStackTrace(this, UserError);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.name = 'UserError';
|
||||||
|
// Custom debugging information
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +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 {
|
||||||
|
Cluster,
|
||||||
|
Config,
|
||||||
|
GroupConfig,
|
||||||
|
MangoClient,
|
||||||
|
MangoAccount,
|
||||||
|
IDS,
|
||||||
|
} from "@blockworks-foundation/mango-client"
|
||||||
|
import { Commitment, 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"
|
||||||
|
|
||||||
|
const MESSAGE = "Your health ratio is at or below @ratio@% \n"
|
||||||
|
|
||||||
|
const app = new Koa()
|
||||||
|
const router = new Router()
|
||||||
|
|
||||||
|
// const rpcUrl = "https://mango.rpcpool.com/946ef7337da3f5b8d3e4a34e7f88"
|
||||||
|
|
||||||
|
const clientConfig = new Config(IDS)
|
||||||
|
|
||||||
|
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`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mangoProgramId = groupIds.mangoProgramId
|
||||||
|
// const mangoGroupKey = groupIds.publicKey
|
||||||
|
|
||||||
|
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 validateMangoAccount(client, alert)
|
||||||
|
if (alert.alertProvider == "mail") {
|
||||||
|
validateEmail(alert.email)
|
||||||
|
ctx.body = { status: "success" }
|
||||||
|
} else {
|
||||||
|
throw new UserError("Invalid alert provider")
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
ctx.throw(400, errorMessage)
|
||||||
|
}
|
||||||
|
await next()
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/delete-alert", async (ctx, next) => {
|
||||||
|
try {
|
||||||
|
const id: any = new ObjectId(ctx.request.body.id)
|
||||||
|
if (id) {
|
||||||
|
ctx.body = { status: "success" }
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
ctx.throw(400, errorMessage)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.use(router.allowedMethods())
|
||||||
|
app.use(router.routes())
|
||||||
|
|
||||||
|
app.listen(config.port, () => {
|
||||||
|
const readyMessage = `> Server ready on http://localhost:${config.port}`
|
||||||
|
console.log(readyMessage)
|
||||||
|
// sendLogsToDiscord(readyMessage, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleAlert = async (alert: any, db: any) => {
|
||||||
|
try {
|
||||||
|
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() } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
// sendLogsToDiscord(null, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const runCron = async () => {
|
||||||
|
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()
|
||||||
|
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, db)
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// sendLogsToDiscord(null, e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
runCron()
|
|
@ -0,0 +1,28 @@
|
||||||
|
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"
|
||||||
|
// })
|
||||||
|
// ]
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -0,0 +1,158 @@
|
||||||
|
// 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 { PublicKey } from "@solana/web3.js"
|
||||||
|
|
||||||
|
import { UserError } from "./errors"
|
||||||
|
|
||||||
|
import config from "./environment"
|
||||||
|
|
||||||
|
const mailjetTransport = require("nodemailer-mailjet-transport")
|
||||||
|
|
||||||
|
// // 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 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()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
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 validateEmail = (email: string) => {
|
||||||
|
if (!EmailValidator.validate(email)) {
|
||||||
|
throw new UserError("The entered email is incorrect")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const 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 == "mail") {
|
||||||
|
const email = alert.email
|
||||||
|
sendEmail(email, message)
|
||||||
|
}
|
||||||
|
// 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 = {}
|
||||||
|
for (let mangoGroupPk of mangoGroupPks) {
|
||||||
|
const mangoGroup = await client.getMangoGroup(new PublicKey(mangoGroupPk))
|
||||||
|
const mangoAccounts = await client.getAllMangoAccounts(mangoGroup)
|
||||||
|
mangoGroups[mangoGroupPk] = {
|
||||||
|
mangoGroup,
|
||||||
|
mangoAccounts,
|
||||||
|
// 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');
|
||||||
|
// }
|
||||||
|
// 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
|
||||||
|
// }
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "@tsconfig/node10/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": ["es6"],
|
||||||
|
"allowJs": true,
|
||||||
|
"outDir": "build",
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue