Mango Notifi Integration (#2)

* Add notifiAlertId

* Put back mango account checks

* Conditionally validating alert based on alertProvider

* Import notifi-node

* Hook up to notifi-node SDK

* Update Notifi SDK

The new SDK has a different parameter name: healthValue rather than
value.

We should no longer delete the alert from server side.

* Bump up to latest SDK

* Comment out debugging logging

Co-authored-by: juni-notifi <hyungjoon.kim@notifi.network>
This commit is contained in:
joshgolden-dev 2022-03-23 19:09:01 -04:00 committed by GitHub
parent b96df3bada
commit fd182e1ae1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 6 deletions

View File

@ -32,6 +32,7 @@
"dependencies": {
"@blockworks-foundation/mango-client": "^3.2.9",
"@koa/cors": "^3.1.0",
"@notifi-network/notifi-node": "^0.8.0",
"@solana/web3.js": "^1.2.6",
"dotenv": "^8.2.0",
"email-validator": "^2.0.4",

View File

@ -14,4 +14,6 @@ export default {
mailJetKey: process.env.MAILJET_KEY || "",
mailJetSecret: process.env.MAILJET_SECRET || "",
updatePassword: process.env.UPDATE_PASSWORD,
notifiSid: process.env.NOTIFI_SID || "",
notifiSecret: process.env.NOTIFI_SECRET || ""
}

View File

@ -20,6 +20,7 @@ import {
validateEmail,
sendAlert,
validateUpdatePassword,
validateNotifiAlertId,
} from "./utils"
import config from "./environment"
@ -63,7 +64,13 @@ router.post("/alerts", async (ctx, next) => {
try {
const alert: any = ctx.request.body
await validateMangoAccount(client, alert)
validateEmail(alert.email)
if (alert.alertProvider === 'mail') {
validateEmail(alert.email)
} else if (alert.alertProvider === 'notifi') {
validateNotifiAlertId(alert.notifiAlertId)
} else {
throw new UserError("Invalid alertProvider")
}
ctx.body = { status: "success" }
alert.open = true
alert.timestamp = Date.now()
@ -115,6 +122,7 @@ router.get("/alerts/:mangoAccountPk", async (ctx, next) => {
open: 1,
timestamp: 1,
triggeredTimestamp: 1,
notifiAlertId: 1,
},
}
)
@ -245,6 +253,7 @@ const handleAlert = async (alert: any, db: any) => {
mangoAccountPk,
mangoGroup.dexProgramId
)
const walletPublicKey = mangoAccount.owner.toBase58();
const health = await mangoAccount.getHealthRatio(
mangoGroup,
mangoCache,
@ -255,7 +264,7 @@ const handleAlert = async (alert: any, db: any) => {
message +=
"Deposit more collateral or reduce your liabilities to improve your account health. \n"
message += `View your account: https://trade.mango.markets/account?pubkey=${alert.mangoAccountPk}`
const alertSent = await sendAlert(alert, message)
const alertSent = await sendAlert(alert, message, Number(health), walletPublicKey)
if (alertSent) {
db.collection("alerts").deleteOne({ _id: alert._id })
}

View File

@ -3,13 +3,25 @@ import * as EmailValidator from "email-validator"
import { MangoClient } from "@blockworks-foundation/mango-client"
import { PublicKey } from "@solana/web3.js"
import {
NotifiClient,
NotifiEnvironment,
createAxiosInstance,
} from '@notifi-network/notifi-node';
import axios from 'axios';
import { UserError } from "./errors"
import config from "./environment"
import { randomUUID } from "crypto"
const mailjetTransport = require("nodemailer-mailjet-transport")
// Initialize Notifi client
const env: NotifiEnvironment = 'Development';
const axiosInstance = createAxiosInstance(axios, env);
const notifiClient = new NotifiClient(axiosInstance);
export const validateMangoAccount = (client: MangoClient, alert: any) => {
return new Promise<void>(async (resolve, reject) => {
try {
@ -52,6 +64,13 @@ export const validateEmail = (email: string) => {
return
}
export const validateNotifiAlertId = (notifiAlertId: string) => {
if (!notifiAlertId) {
throw new UserError("Invalid notifiAlertId")
}
return
}
const sendEmail = async (email: string, message: string) => {
const transport = nodemailer.createTransport(
mailjetTransport({
@ -70,16 +89,59 @@ const sendEmail = async (email: string, message: string) => {
try {
await transport.sendMail(mailOptions)
return true
} catch (err) {
console.error(err)
}
transport.sendMail(mailOptions)
return false
}
export const sendAlert = async (alert: any, message: string) => {
const sendNotifiAlert = async (alertId: string, health: number, walletPublicKey: string ) => {
const sid = config.notifiSid
const secret = config.notifiSecret
if (!sid || !secret) {
throw new UserError("Missing sid/secret pair")
}
try {
// login with sid/secret to get jwt
const { token: jwt, expiry } = await notifiClient.logIn({ sid, secret })
// console.log(`login successfully, received jwt expire at ${expiry}`)
if (jwt) {
// trigger notifi to send notification
const key = randomUUID()
await notifiClient.sendSimpleHealthThreshold(jwt, {
key,
walletPublicKey,
walletBlockchain: "SOLANA",
healthValue: health,
})
// console.log(`sending alert with key: ${key}, walletPublicKey: ${walletPublicKey}, value: ${health}`);
return true
} else {
throw new UserError("Invalid jwt, please login")
}
} catch (err) {
console.error(err)
throw err
}
}
export const sendAlert = async (alert: any, message: string, health: number, walletPublicKey: string) => {
if (alert.alertProvider == "mail") {
const email = alert.email
sendEmail(email, message)
const emailSent = await sendEmail(email, message)
return emailSent
} else if (alert.alertProvider == "notifi") {
try {
const alertSent = await sendNotifiAlert(alert.notifiAlertId, health, walletPublicKey)
return alertSent;
} catch (err) {
console.error(err)
return false
}
}
return true
return false
}

View File

@ -65,6 +65,18 @@
dependencies:
vary "^1.1.2"
"@notifi-network/notifi-axios-utils@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@notifi-network/notifi-axios-utils/-/notifi-axios-utils-0.8.0.tgz#83ac4a649ee9facbd32a8d121748bb5c827f9c4f"
integrity sha512-q+RDUZ2gRkLl0gfKy6pVQrZHe9fGwLa+zH1Fy+dm3U6SCyAZX8cjqiLpFLYVJE89nguMMc28tnp3T5K39+wBlQ==
"@notifi-network/notifi-node@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@notifi-network/notifi-node/-/notifi-node-0.8.0.tgz#0c91b5f3ac27c41e4b54ddd5eed8a9118e54a2e6"
integrity sha512-bgleeL1M6RMm0GQFKhXETH6fbtDOJ7poqBX/VPg2ZTG7hThhYcxlFnYhQ33/qnG2FsMmYq1YjOlCV5Ens6o1XA==
dependencies:
"@notifi-network/notifi-axios-utils" "^0.8.0"
"@project-serum/anchor@^0.11.1":
version "0.11.1"
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.11.1.tgz#155bff2c70652eafdcfd5559c81a83bb19cec9ff"