Skip to content

Commit

Permalink
Implemented range bound health factor ,borrow and supply apy notifica…
Browse files Browse the repository at this point in the history
…tions
  • Loading branch information
Shubham committed Feb 1, 2024
1 parent e304909 commit dcab188
Show file tree
Hide file tree
Showing 8 changed files with 683 additions and 87 deletions.
308 changes: 234 additions & 74 deletions src/sample_showrunners/aave/aaveChannel.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,169 @@
// @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) {

public async checkHealthFactor(aave, userAddress, sdk: any, simulate) {
this.logInfo(`Checking Health Factor`);
// 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.
this.checkHealthFactor(subscriberObj.subscriber, 0, 3, simulate)
}
// 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;

} 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 +180,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 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 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 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 +257,63 @@ export default class AaveChannel extends EPNSChannel {
image: null,
simulate: simulate,
});
} else {
// 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),
);

return {
success: true,
data: tx,
};
//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;
}

public async testLogic(healthFactor) {

if (Number(healthFactor) >= 0 && Number(healthFactor) <= 3) {
const precision = CUSTOMIZABLE_SETTINGS.precision;
const newHealthFactor = parseFloat(healthFactor).toFixed(precision);
return true;
} else {
this.logInfo(`[Wallet: ${userAddress} is SAFE with Health Factor:: ${healthFactor}`);
return {
success: false,
data: userAddress + ' is not about to get liquidated',
};
return false;
}
}

}
Loading

0 comments on commit dcab188

Please sign in to comment.