Skip to main content

Channel Settings using Showrunners

Inside Aave's Channel Settings.

  • The Aave Channel supports both versions of Aave i.e Aave v2 and v3.
  • Need of the channel : To alert the user of his health factor before Liquidation of his assets starts.
  • You can select a range of Health Factor and if your health factor falls in that range then a notification about your health factor will be sent.
  • Eg : Only send me notification if my health factor is in range of 1.2 to 1.5. -Every 3 hours , Aave channel will check for your health factor on both versions and then send/not send notification.

Pre-requisites

  • In this tutorial, we will only understand the logic part of Aave i.e how Notifications are being triggered in Aave.
  • For step-by-step tutorial of Channel Settings,please refer BTC Tracker Tutorial.
  • Subscribe to this channel Address Aave Channel

Perform following steps to get started with Channel Settings.

Step 1 : Create a Position on Aave V3/V2 Mainnet by Supplying and borrowing against some asset. Step 2: You should be able to see some health Factor like 1.5 or 1.8. Step 3:

  • Create a function called getUserSetings() which will have main logic part.
  • This function will do following things :
    • Fetch Notification setting set by the user.
    • If Channel Settings exist and is enabled by the user then get the lower and upper range values set by the user and pass the values to the checkHealthFactor function with susbcriber's address.
    • If Channel Settings exists but are turned off i.e disabled by the user then pass dummy values of lower and upper values to the checkHealthFactor function. (Fun Fact : If you have just supplied assets on Aave and have not borrowed against it then you would have a crazy Health Factor > 3 due to which no notifications will be sent.).
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) {
status = false;
// 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 -->
//Borrow APY code goes here -->
});
}
})}else{
i=1;
break;
}
}
  • If Channel Settings dosen't exist then we would just send a normal notification if there Health Factor is in range of 0 to 3.
  • Here if you are wondering why i have set the range as 0 to 3 then the reason is that if you don't borrow against your asset then your asset is completely safe and you need not to worry about anything but if you have borrowed against youe assets then you need to worry about liquidation og your assets.
  • Generally if you borrow then your health decreases and comes in range of 1 to 3 and if your health factor reaches 1 then your assets can get liquidated.
  • In this step we will fetch the Channel Settings of our channel's subscribers.

Step 4:

  • In this step we check the health factor of Channel subscribers and then trigger notification on the basis of their upper and lower values set by the user.
  public async checkHealthFactor(userAddress, lowerLimit, upperLimit, simulate) {
try {
const logicOverride =
typeof simulate == 'object'
? simulate.hasOwnProperty('logicOverride') && simulate.logicOverride.mode
? simulate.logicOverride.mode
: false
: false;
const simulateApplyToAddr =
logicOverride && simulate.logicOverride.hasOwnProperty('applyToAddr')
? simulate.logicOverride.applyToAddr
: false;
const simulateAaveNetwork =
logicOverride && simulate.logicOverride.hasOwnProperty('aaveNetwork')
? simulate.logicOverride.aaveNetwork
: false;

if (!userAddress) {
if (simulateApplyToAddr) {
userAddress = simulateApplyToAddr;
} else {
// 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 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(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 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,
title: title,
message: message,
payloadTitle: payloadTitle,
payloadMsg: payloadMsg,
notificationType: notificationType,
cta: 'https://app.aave.com/#/dashboard',
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")
}
}

Step 5 : Our second goal is to give notification about APYs for assets that can be borrowed or supplied to on aave.

  • So first we will start by getting all the addresses of assets available on Aave.

  • In the below code,we are quering the addresses of the assets using getAllReservesTokens method, it returns a array in which each element is a array itself with two values i.e [assetName,assetAdderss].

  • Up next,we have a for loop in which we are quering the data of APR about each asset using getReserveData method. (APR : It is the rate of interest you get on your asset on yearly basis. APY : It is the compounded rate of interest you get on your assets on yearly basis. )

let status:boolean = false;
status = await this.getData();

public async getData(){
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

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) + "]");

}

return true;
}
  • Aave uses RAY for storing it's numbers and for more precision,as eth uses wei to store decimal and normal values with 18 digits precision,RAY has 27 digit precision due to which we will first convert it into normal format and then perform operations on it.

  • Next,we are finding the APYs of each assets and pushing it into different arrays which we will use in later stages(Tokens,supplyApy,borrowApy).

Step 6 : Filtering APYs on the basis of channel settings and send notification.

  • Let's go back in Step 1 where we were querying Channel Settings and add our logic for getting the Channel setting for Supply APY selected by the user.
  • The Channel setting for Supply Apy will be a number like 1.5 or 2 .
  • further We will compare APY of an asset with the number opted by the user and if the APY is greater than the user's number then we will add that asset with it's APY in the payload for notification.
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,
});
}
  • We are using a similar logic for Borrow APY too which can be decoded easily.

  • I hope you enjoyed this tutotial,reach out to Push Discord if you stuck somehwere or have any doubts.