Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented new features for Aave #35

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
298 changes: 223 additions & 75 deletions src/sample_showrunners/aave/aaveChannel.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,168 @@
// @name: Aave Channel
// @version: 1.0
// @version: 1.3.0
// @changes : Implemented Slider type notifications for Supply and borrow APY in Aave(v3)

import { Service, Inject } from 'typedi';
import config, { defaultSdkSettings, settings } from '../../config';
import config from '../../config';
import { ethers } from 'ethers';
import keys from "./aaveKeys.json";
import aaveSettings from './aaveSettings.json';
import { PushAPI, CONSTANTS } from '@pushprotocol/restapi';
import aaveLendingPoolDeployedContractABI from './aave_LendingPool.json';
import { EPNSChannel } from '../../helpers/epnschannel';
import { Logger } from 'winston';
import aavePoolDataProviderAbi from "./aavePoolDataProvidrAbi.json";

const NETWORK_TO_MONITOR = config.web3MainnetNetwork;
const HEALTH_FACTOR_THRESHOLD = 1.6;
const NETWORK_TO_MONITOR = aaveSettings.MainnetProvider;
const provider = new ethers.providers.JsonRpcProvider(config.web3MainnetProvider || aaveSettings.MainnetProvider);
const signer = new ethers.Wallet(keys.PRIVATE_KEY_NEW_STANDARD.PK, provider);
const CUSTOMIZABLE_SETTINGS = {
precision: 3,
};

@Service()
export default class AaveChannel extends EPNSChannel {
constructor(@Inject('logger') public logger: Logger) {
constructor(@Inject('logger') public logger: Logger, @Inject("cached") public cached) {
super(logger, {
sdkSettings: {
epnsCoreSettings: defaultSdkSettings.epnsCoreSettings,
epnsCommunicatorSettings: defaultSdkSettings.epnsCommunicatorSettings,
networkSettings: defaultSdkSettings.networkSettings,
},
networkToMonitor: NETWORK_TO_MONITOR,
dirname: __dirname,
name: 'Aave',
url: 'https://aave.com/',
useOffChain: true,
address:'0xAA940b3501176af328423d975C350d0d1BaAae50'
});
}

tokens: string[] = [];
supplyApy: string[] = [];
borrowApy: string[] = [];
// To form and write to smart contract
public async sendMessageToContract(simulate) {
const sdk = await this.getSdk();
this.logInfo('sendMessageToContract');

public async getUserSettings(simulate) {
const userAlice = await PushAPI.initialize(signer, { env: CONSTANTS.ENV.STAGING });
//simulate object settings START
const logicOverride =
typeof simulate == 'object'
? simulate.hasOwnProperty('logicOverride') && simulate.logicOverride.mode
? simulate.logicOverride.mode
: false
: false;
const simulateAaveNetwork =
logicOverride && simulate.logicOverride.hasOwnProperty('aaveNetwork')
? simulate.logicOverride.aaveNetwork
: false;
let aave: any;
if (simulateAaveNetwork) {
this.logInfo('Using Simulated Aave Network');
aave = sdk.advanced.getInteractableContracts(
simulateAaveNetwork,
settings,
this.walletKey,
aaveSettings.aaveLendingPoolDeployedContractMainnet,
aaveLendingPoolDeployedContractABI,
);
} else {
this.logInfo('Getting Aave Contract');
aave = await sdk.getContract(
aaveSettings.aaveLendingPoolDeployedContractMainnet,
JSON.stringify(aaveLendingPoolDeployedContractABI),
);
this.log(`Got Contract`);
}

this.logInfo(`Getting subscribed users`);

const users = await sdk.getSubscribedUsers();
for (const user of users) {
let res = await this.checkHealthFactor(aave, user, sdk, simulate);
}
let status: boolean = false;
status = await this.getData();
if (status) {
let i = 1;

return true;
}
while (true) {
const userData: any = await userAlice.channel.subscribers({
page: i,
limit: 30,
setting: true,
});
if (userData.itemcount != 0) {
i++;
userData.subscribers.map((subscriberObj) => {
const userSettings = JSON.parse(subscriberObj.settings);
if (userSettings !== null) {

// this.logInfo("User Info" + JSON.stringify(userSettings[0]));
userSettings.map(async (settings) => {
if (settings.index == 1 && settings.enabled == true) {
// Aave user settings Enabled.
let temp = userSettings[0];
let lowerLimit = JSON.stringify(temp.user.lower);
let upperLimit = JSON.stringify(temp.user.upper);
this.checkHealthFactor(subscriberObj.subscriber, Number(lowerLimit), Number(upperLimit), simulate);
}
else if (settings.index == 1 && settings.enabled == false) {
//If User settings Exist but is disabled by the user => send normal notification.
// Don't send any notifications.
}
// Supply APY code goes here -->
if (settings.index == 2 && settings.enabled == true) {
let k = 0;
let loopCounter = 0;
let title = 'Aave v3 supply APYs are here!';
let message = 'Here is a List of Assets that you can supply to on Aave v3';
let payloadTitle = 'Aave V3 Supply APY Alert!';
let payloadMsg = ``;
let notificationType = 3;
this.supplyApy.map(async (apy) => {
// console.log(apy);
if (Number(apy) >= Number(JSON.stringify(settings.user))) {
if (loopCounter % 2 == 0 && loopCounter != 1) {
let sentence = `${this.tokens[k]}'s APY :[d:${apy}]%\t\t`;
payloadMsg += sentence;

public async checkHealthFactor(aave, userAddress, sdk: any, simulate) {
this.logInfo(`Checking Health Factor`);
} else {
let sentence = `${this.tokens[k]}'s APY :[d:${apy}]%\n`;
payloadMsg += sentence;
}
loopCounter++;
}
k++;
})
// console.log("Payload " + payloadMsg)
const tx = await this.sendNotification({
recipient: subscriberObj.subscriber,
title: title,
message: message,
payloadTitle: payloadTitle,
payloadMsg: payloadMsg,
notificationType: notificationType,
cta: 'https://app.aave.com/#/dashboard',
image: null,
simulate: simulate,
});
}
// Borrow APY code goes here -->
if (settings.index == 3 && settings.enabled == true) {
let k = 0;
let loopCounter = 0;
let title = `Aave v3's Borrow APYs are here!`;
let message = 'Here is a List of Assets that you can Borrow on Aave v3';
let payloadTitle = 'Aave V3 Borrow APY Alert!';
let payloadMsg = ``;
let notificationType = 3;
this.borrowApy.map(async (apy) => {
if (Number(apy) >= Number(JSON.stringify(settings.user))) {
if (loopCounter % 2 == 0 && loopCounter != 1) {
let sentence = `${this.tokens[k]}'s APY :[d:${apy}]%\t\t`;
payloadMsg += sentence;
} else {
let sentence = `${this.tokens[k]}'s APY :[d:${apy}]%\n`;
payloadMsg += sentence;
}
loopCounter++;
}
k++;
})
const tx = await this.sendNotification({
recipient: subscriberObj.subscriber,
title: title,
message: message,
payloadTitle: payloadTitle,
payloadMsg: payloadMsg,
notificationType: notificationType,
cta: 'https://app.aave.com/#/dashboard',
image: null,
simulate: simulate,
});
}
})
}
else {
// For Users who have not opted into notification setting
this.checkHealthFactor(subscriberObj.subscriber, 0, 3, simulate)
}
})
} else {
break;
}
}
this.logInfo("-------------[ JOB Finished ]------------------");
return true;
}
}
public async checkHealthFactor(userAddress, lowerLimit, upperLimit, simulate) {
try {
const logicOverride =
typeof simulate == 'object'
Expand All @@ -96,41 +179,71 @@ export default class AaveChannel extends EPNSChannel {
? simulate.logicOverride.aaveNetwork
: false;

if (!aave) {
aave = await sdk.getContract(
aaveSettings.aaveLendingPoolDeployedContractMainnet,
JSON.stringify(aaveLendingPoolDeployedContractABI),
);
}
if (!userAddress) {
if (simulateApplyToAddr) {
userAddress = simulateApplyToAddr;
} else {
this.logDebug('userAddress is not defined');
// this.logDebug('userAddress is not defined');
}
}
} catch (err) {
this.logError('An error occured while checking health factor');
this.logError(err);
}
try{
let aaveV2 = await this.getContract(
aaveSettings.aaveLendingPoolDeployedContractMainnet,
JSON.stringify(aaveLendingPoolDeployedContractABI),
);
let aaveV3 = await this.getContract(
aaveSettings.aaveV3PoolContractMainnet,
JSON.stringify(aaveLendingPoolDeployedContractABI),
);
// console.log("User Address"+userAddress);
//simulate object settings END

const userData = await aave.contract.getUserAccountData(userAddress);
let healthFactor = ethers.utils.formatEther(userData.healthFactor);
this.logInfo('For wallet: %s, Health Factor: %o', userAddress, healthFactor);
if (Number(healthFactor) <= HEALTH_FACTOR_THRESHOLD) {
const aaveV2UserData = await aaveV2?.contract.getUserAccountData(userAddress);
const aaveV3UserData = await aaveV3?.contract.getUserAccountData(userAddress);
let healthFactorV2 = ethers.utils.formatEther(aaveV2UserData.healthFactor);
let healthFactorV3 = ethers.utils.formatEther(aaveV3UserData.healthFactor);
// console.log(`HF of ${userAddress} is ${healthFactorV3}`)
// this.logInfo('For wallet: %s, Health Factor: %o', userAddress, healthFactor);
if (Number(healthFactorV2).toFixed(2) >= lowerLimit && Number(healthFactorV2).toFixed(2) <= upperLimit) {
// this.logInfo("Aave v2 Notification sending to " + userAddress);
const precision = CUSTOMIZABLE_SETTINGS.precision;
const newHealthFactor = parseFloat(healthFactor).toFixed(precision);
const title = 'Aave Liquidity Alert!';
const newHealthFactor = parseFloat(healthFactorV2).toFixed(precision);
const title = 'Aave V2 Liquidation Alert!';
const message =
userAddress +
' your account has healthFactor ' +
newHealthFactor +
'. Maintain it above 1 to avoid liquidation.';
const payloadTitle = 'Aave Liquidity Alert!';
const payloadMsg = `Your account has healthFactor [b:${newHealthFactor}] . Maintain it above 1 to avoid liquidation.[timestamp: ${Math.floor(
Date.now() / 1000,
)}]`;
const payloadTitle = 'Aave V2 Liquidity Alert!';
const payloadMsg = `Your account on Aave V2 has healthFactor [d:${newHealthFactor}] . Maintain it above 1 to avoid liquidation.`;
const notificationType = 3;
const tx = await this.sendNotification({
recipient: userAddress,
title: title,
message: message,
payloadTitle: payloadTitle,
payloadMsg: payloadMsg,
notificationType: notificationType,
cta: 'https://app.aave.com/#/dashboard',
image: null,
simulate: simulate,
});
}
if (Number(healthFactorV3).toFixed(2) >= lowerLimit && Number(healthFactorV3).toFixed(2) <= upperLimit) {
this.logInfo("Aave v3 Notification sending to " + userAddress);
const precision = CUSTOMIZABLE_SETTINGS.precision;
const newHealthFactor = parseFloat(healthFactorV3).toFixed(precision);
const title = 'Aave V3 Liquidation Alert!';
const message =
userAddress +
' your account has healthFactor ' +
newHealthFactor +
'. Maintain it above 1 to avoid liquidation.';
const payloadTitle = 'Aave V3 Liquidity Alert!';
const payloadMsg = `Your account on Aave V3 has healthFactor [d:${newHealthFactor}] . Maintain it above 1 to avoid liquidation.`;
const notificationType = 3;
const tx = await this.sendNotification({
recipient: userAddress,
Expand All @@ -143,17 +256,52 @@ export default class AaveChannel extends EPNSChannel {
image: null,
simulate: simulate,
});

return {
success: true,
data: tx,
};
} else {
this.logInfo(`[Wallet: ${userAddress} is SAFE with Health Factor:: ${healthFactor}`);
return {
success: false,
data: userAddress + ' is not about to get liquidated',
};
// this.logInfo(`[Wallet: ${userAddress} is SAFE with Health Factor:: ${healthFactor}`);
}
return true;
}catch(e){
this.logInfo("Error occured in Aave Liquidity Alert")
}
}


public async getData():Promise<boolean> {
try{
let aaveV3 = await this.getContract(
aaveSettings.aaveV3PoolDataProvider,
JSON.stringify(aavePoolDataProviderAbi),
);

//Re-settings Arrays
this.tokens.length = 0;
this.supplyApy.length = 0;
this.borrowApy.length = 0;

let aaveV3Tokens = await aaveV3?.contract.getAllReservesTokens();
let RAY = 10 ** 27 // 10 to the power 27
let SECONDS_PER_YEAR = 31536000
// console.log("Tokens"+aaveV3Tokens[1]);
for (let i = 0; i < aaveV3Tokens.length; i++) {

let aaveV2APR = await aaveV3?.contract.getReserveData(aaveV3Tokens[i][1]);
let depositAPR = (aaveV2APR[5] / RAY)
let variableBorrowAPR = (aaveV2APR[6] / RAY)

let depositAPY = (((1 + (depositAPR / SECONDS_PER_YEAR)) ** SECONDS_PER_YEAR) - 1) * 100
let variableBorrowAPY = (((1 + (variableBorrowAPR / SECONDS_PER_YEAR)) ** SECONDS_PER_YEAR) - 1) * 100
this.tokens.push(aaveV3Tokens[i][0]);
this.supplyApy.push((depositAPY).toFixed(2));
this.borrowApy.push(variableBorrowAPY.toFixed(2));

// console.log(aaveV3Tokens[i][0] + "[" + depositAPY.toFixed(2) + "," + variableBorrowAPY.toFixed(2) + "]");

}

}catch(e){
this.logInfo("Error occured in Supply Borrow APY in aave")
}
return true;
}

}
15 changes: 7 additions & 8 deletions src/sample_showrunners/aave/aaveJobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,19 @@ import AaveChannel from './aaveChannel';
export default () => {
const startTime = new Date(new Date().setHours(0, 0, 0, 0));

const dailyRule = new schedule.RecurrenceRule();
dailyRule.hour = 0;
dailyRule.minute = 0;
dailyRule.second = 0;
dailyRule.dayOfWeek = new schedule.Range(0, 6);
const threeHourRule = new schedule.RecurrenceRule();
threeHourRule.hour = new schedule.Range(0, 23, 3);
threeHourRule.minute = 0;
threeHourRule.second = 0;

// AAVE CHANNEL RUNS EVERY 24 Hours
logger.info(` 🛵 Scheduling Showrunner - Aave Channel [on 6 Hours] [${new Date(Date.now())}]`);
schedule.scheduleJob({ start: startTime, rule: dailyRule }, async function () {
logger.info(` 🛵 Scheduling Showrunner - Aave Channel [on 3 Hours] [${new Date(Date.now())}]`);
schedule.scheduleJob({ start: startTime, rule: threeHourRule }, async function () {
const aaveChannel = Container.get(AaveChannel);
const taskName = 'Aave users address checks and sendMessageToContract()';

try {
await aaveChannel.sendMessageToContract(false);
await aaveChannel.getUserSettings(false);
logger.info(`[${new Date(Date.now())}] 🐣 Cron Task Completed -- ${taskName}`);
}
catch (err) {
Expand Down
Loading
Loading