Introducing Liquidation Protection Template for PowerAgent

Mr FOS
PowerPool
Published in
6 min readApr 16, 2024

Introduction

Lending markets are one of Defi’s most actively used products and are a basic building block in various yield-generation strategies.

Borrowing funds on lending markets exposes borrowers to liquidation risk if the collateral/debt ratio decreases below a certain value. The liquidation is associated with a liquidation penalty, a direct loss for the borrower.

However, borrowers can be protected from liquidation if there is an automatically executed strategy for adjusting the collateral/debt ratio based on returning a share of the debt in case of collateral price decline.

The liquidation protection use case

For example, the user deposited 10 ETH as collateral at the price of $3,500 and borrowed $25,000 USDC. The initial collateral ratio was F = 35,000/25,000 = 1.4 or 140% collateralization. However, the ETH price has recently declined and is now $3,050, so F = 30,050/25,000 = 1.22 (we don’t consider the interest rate on the debt in this simple example).

If liquidation is performed at F<1.20 (ETH<$3000), the user will lose a 10% liquidation penalty or ~$3000. To avoid this, the debt share should be repaid, and the collateral ratio should be returned to at least 1.25 or above.

The debt repayment must be done strictly when the condition is fulfilled. The cost of failure is too high.

For such cases, decentralized networks of Keeper bots like PowerAgent are perfect: if the designated Keeper didn’t execute the liquidation protection strategy, other Keepers would do it.

This article presents the overview of the architecture for the AAVE liquidation protection Template Job.

Liquidation Protection Contract

In the prototype implementation, the contract acts as an intermediary between the person and the lending protocol. Our lending protocol of choice is AAVE, however, any lending protocol can be utilized by making the appropriate changes to the code and utilizing the correct interfaces. This potentially merits the development of a generalized lending protocol interface to abstract such interactions outside of the contract; however, in the current prototype implementation, we are quite content to work just with AAVE.

The contract’s main purpose is to monitor the health factor of the user’s position and balance it accordingly by either repaying debt (to increase the health factor) or increasing debt (to decrease the health factor). The health factor is kept between the lower and upper bounds.

Find the Liquidation Protection Template prototype code on PowerPool’s GitHub: https://github.com/powerpool-finance/powerpool-research/tree/main/liquidation-protection-prototype

Let’s dive deeper into the contract operation.

Main components

Initialization

When deployed, the contract is initialized with the following parameters:

  • collateralAsset — the address of the asset used as a collateral
  • debtAsset — the address of the asset that will be drawn as debt
  • aaveOracle — address of the AAVE oracle. It is used to convert the asset amounts to the AAVE base asset according to the price.
  • aavePool — address of the AAVE pool where the position will be opened.
  • agentAddress — address of the PowerAgent contract. Necessary for onlyOnwerOrAgent modifiers which prevent execution of the contract methods by anyone other than the Agent of the contract owner.

The used AAVE addresses may be found in the official deployment list: Deployed Contracts | v3 | Developers (aave.com)

Immediately after deployment, the user invokes the setHfParams function, which sets the lower and upper bounds for the acceptable position health factor. It is impossible to set the lower bound (lb) higher than the upper bound (ub). This automatically sets the targetHF parameter, which equals 1/2*(lb+ub). Therefore, it is obvious that the desired health factor must be chosen by also choosing the width of the admissibility interval.

If the width of the admissibility interval is w, and the target health factor is thf, then the lower and upper bounds are respectively lb = thf-w/2, ub = thf+w/2. Each time the position is balanced, the position’s health factor will be brought to this target value. The balancing criteria are (in the interest of minimizing the number of transactions and therefore also the amount of gas expended) that either hf>ub or hf<lb.

Supplying collateral

To open the position, the user must call depositCollateral(uint256 amount) function of the contract to deposit collateral into the AAVE pool on behalf of the contract. This action needs manual approval from the user to the contract for the deposited collateral amount. The contract will then siphon the specified collateral asset and deposit it into the AAVE pool, opening the position.

Taking debt

The debt can be taken by invoking the increaseDebt() function. This function takes no arguments, as the position is fully defined by the lower and upper health factor bounds. Thus, calling this function will lead to issuing the amount of debt that will bring the health factor of the position to the target value. Should the user want to change the amount, they would need to change the lower and upper bounds of the health factor.

Repaying debt

Debt can be repaid by invoking the repayDebt() function. This function also accepts no arguments, just like increaseDebt(), and brings the health factor of the position to the target. Repayment is done by siphoning the debt token from the owner’s address to the contract and then invoking the repay() function of the AAVE pool.

Balancing health factor

This is the most important function of the contract. The function balanceHF():

  1. Checks the current health factor of the position.
  2. Calculates whether the health factor is within the defined bounds.
  3. If the health factor is not within the bounds, the function to repay repayDebt() or increase increaseDebt() debt is called to increase or decrease the health factor to the target value accordingly.

This function is specifically designed to be called during the automated execution by the PowerAgent network.

Resolver

The resolver function is necessary for the PowerAgent automation operation. This function is called every block by the automation agents (Keepers) and checks the current health factor of the position. When the health factor is out of range, the resolver function returns true, calldata, where calldata is the selector of the balanceHF() function. After that, the balanceHF() function is called by the automation agent.

Emergency exit

In such a case that the user suffered his funds getting stuck on the contract (having sent Ethereum there, for instance), he may invoke the emergencyExit(address[] assetsToWithdraw, bool assertWithdraw) function to withdraw these funds.

The first parameter is the list of the addresses of the assets to withdraw (address(0) for the native token of the chain) and the second parameter toggles assertion of the success of the transfer of stuck tokens to the user. All tokens present on the contract’s balance are withdrawn for each of the elements of the assetsToWithdraw list.

Liquidation Protection Job

The contract is designed around the automated execution provided by the PowerAgent network.

Its main purpose is to keep the health factor of the debt position in the predefined range and balance it automatically by either repaying or increasing debt. In the present form, this contract serves as a prototype for a more generalized health-factor-keeping component for strategies of various complexity.

An example of such a strategy is PowerPool’s ETHIndia project — the “ETH believer” Starter Pack for Arbitrum:

  1. Gradual accumulation of $WETH using DCA and its exchange for $wstETH.
  2. Borrowing $USDC using the purchased $wstETH as collateral and depositing it in a farming pool.
  3. Swapping yields for $wstETH and compounding to increase future gains.
  4. Protecting the CDP by monitoring the health factor and repaying or borrowing more $USDC when necessary.

Deployed and used right now, this Template will allow the user to hold the position within the predefined health factor range, automatically sending or siphoning funds from the user’s address to keep the position healthy. This mechanism will unleash its full potential if coupled with sophisticated staking/re-staking strategies.

In the strategy described above, WETH is used to collateralize USDC debt, which later is staked in a pool to earn rewards. Whenever the position health factor decreases below the lower threshold, the USDC gets automatically un-staked and is used to repay part of the debt to keep the position healthy. And vice versa, if the WETH price goes up and the position becomes overcollateralized, additional USDC debt is issued to be staked and earn more rewards.

Conclusion

The importance of reliable liquidation protection when leveraging borrowed funds cannot be overstated. By introducing this Template Job, a new solution will be available to all users, regardless of technical background.

With PowerAgent, lending market borrowers will now be able to effortlessly maintain the balance of their CDP “health”, easily prevent potential losses, and ensure the stability of their DeFi strategies.

--

--

Mr FOS
PowerPool

DePIN layer powering AI Agents and DeFi automation in multichain universe. https://powerpool.finance