Originally published on Dacian's blog as DeFi Liquidation Vulnerabilities on 23 January 2025.
Efficient liquidation is vital for decentralized finance (DeFi) solvency but challenging to implement securely, especially in trustless systems. High bug density can threaten protocol stability and user trust. Developers and auditors should assess these key vulnerability classes to mitigate risks.
Let’s start by exploring two frequently used terms with their definitions:
collateral_value * loan_to_value_ratio < borrow_value
, meaning enough collateral exists to cover the loan, preventing bad debt if liquidated in time.collateral_value < borrow_value
, meaning insufficient collateral remains, leading to bad debt even after liquidation.Liquidation should occur promptly to prevent liquidatable positions from becoming insolvent.
Decentralized protocols often rely on trustless liquidators rather than designated entities. To ensure timely liquidations, they offer incentives like bonuses or rewards. MEV bots, for example, liquidate positions if the reward exceeds gas costs, making it a consistent, low-risk profit opportunity.
Guideline: If the protocol depends on trustless liquidators, does it offer sufficient incentives?
Without minimum deposit and position size requirements, small debt positions may accumulate, remaining unliquidated due to a lack of financial incentive. This is particularly risky for stablecoin protocols, as bad debt can pile up, leading to under-collateralization.
Mitigation:
Guideline: Does the protocol enforce a minimum position size across all functions that modify positions, or only when creating a new one?
Additional cases: [1, 2, 3, 4, 5]
In trading protocols like perpetuals, a user’s open long/short position includes their current profit/loss (PNL) when calculating total collateral value. If users have a high positive PNL, they may withdraw most or all of their deposited collateral while still appearing solvent.
If their PNL later declines, the position becomes liquidatable. However, with no collateral left to seize, liquidators lack incentives, potentially leading to liquidation failure or a transaction revert, ultimately resulting in insolvency.
Mitigation:
Additionally, allowing users to borrow deposited collateral without restrictions can create similar risks and should be carefully managed.
Guideline: Can profitable users withdraw their deposited collateral? If so, what happens if market conditions turn against them?
Additional cases: [1]
If a liquidatable position isn’t addressed quickly, it can become insolvent, where the liquidation reward and seized collateral are worth less than the debt tokens needed to cover the bad debt.
In this case, trustless liquidators have no incentive to liquidate, allowing bad debt to accumulate. Some protocols may not handle this state properly, leading to liquidation transactions failing or reverting, making insolvent positions impossible to liquidate.
Mitigation:
Guideline: Does the protocol have a mechanism to handle bad debt? What happens when an insolvent position is liquidated?
Consider this liquidation code:
// additional processing when position closed by liquidation
if (!hasPosition) {
int256 remainingMargin = vault.margin;
// credit positive margin to vault recipient
if (remainingMargin > 0) {
if (vault.recipient != address(0)) {
vault.margin = 0;
sentMarginAmount = uint256(remainingMargin);
ERC20(pairStatus.quotePool.token).safeTransfer(
vault.recipient, sentMarginAmount);
}
}
// otherwise ensure liquidator covers bad debt
else if (remainingMargin < 0) {
vault.margin = 0;
// any losses that cannot be covered by the vault
// must be compensated by the liquidator
ERC20(pairStatus.quotePool.token).safeTransferFrom(
msg.sender, address(this), uint256(-remainingMargin));
}
}
If a position is fully liquidated, the code ensures the liquidator covers any associated bad debt. However, since this check only applies to full liquidations, a liquidator can avoid bad debt responsibility by only partially liquidating the position.
This loophole allows bad debt to accumulate unaccounted for within the protocol. A possible mitigation is requiring that partial liquidations of insolvent positions also account for a proportional share of the bad debt, either through an insurance fund or a bad debt socialization mechanism.
Guideline: Is bad debt accounted for during partial liquidation of an insolvent position?
In protocols where trustless liquidators provide debt tokens to cover a borrower’s bad debt, partial liquidation is essential to allow large positions to be liquidated in smaller portions. Without partial liquidation, large liquidatable positions created by whales may remain unresolved since individual liquidators might lack the required tokens to cover the entire debt.
Flash loans can help liquidate large positions, but only if the loan amount does not exceed available market liquidity, which is not always guaranteed.
Guideline: Does the protocol support partial liquidation? If not, how can a whale user be liquidated? Are there other safeguards, such as caps on maximum position size? If so, how effective are these safeguards in ensuring that the largest positions can be liquidated?
If an attacker can indefinitely block liquidations or make themselves immune to liquidation, it poses a severe risk to protocol solvency by allowing bad debt to accumulate unchecked. Audits of real-world protocols have uncovered several attack methods that exploit this vulnerability.
Consider this liquidation code, which loops through all of a user’s active positions:
function _removePosition(uint256 positionId) internal {
address trader = userPositions[positionId].owner;
positionIDs[trader].removeItem(positionId);
}
// @audit called by `_removePosition`
function removeItem(uint256[] storage items, uint256 item) internal {
uint256 index = getItemIndex(items, item);
removeItemByIndex(items, index);
}
// @audit called by `removeItem`
function getItemIndex(uint256[] memory items, uint256 item) internal pure returns (uint256) {
uint256 index = type(uint256).max;
// @audit OOG revert for large items.length
for (uint256 i = 0; i < items.length; i++) {
if (items[i] == item) {
index = i;
break;
}
}
return index;
}
A malicious user can exploit this for
loop by opening multiple small positions and ensuring the last one becomes liquidatable. When a liquidator tries to process that position, the transaction will fail due to running out of gas, making liquidation impossible.
Mitigation:
mapping
or data structure that avoids iterating through all positions.Guideline: Does the protocol iterate over an unbounded list that users can continuously add to? Is there a minimum position size enforced?
In some protocols, a user's health score is calculated based on all their open positions combined. If their overall health score falls below a threshold, all positions are liquidated in a single transaction.
Consider this code example:
// load open markets for account being liquidated
ctx.amountOfOpenPositions = tradingAccount.activeMarketsIds.length();
// iterate through open markets
for (uint256 j = 0; j < ctx.amountOfOpenPositions; j++) {
// load current active market id into working data
// @audit assumes constant ordering of active markets
ctx.marketId = tradingAccount.activeMarketsIds.at(j).toUint128();
// snip - a bunch of liquidation processing code //
// remove this active market from the account
// @audit this calls `EnumerableSet::remove` which changes the order of `activeMarketIds`
tradingAccount.updateActiveMarkets(ctx.marketId, ctx.oldPositionSizeX18, SD_ZERO);
Because EnumerableSet
does not guarantee element order and its remove
function uses a swap-and-pop method for efficiency, removing an active market that is not the last in the list can disrupt the order of a user’s active markets.
A malicious user can exploit this by opening multiple positions and triggering this corruption, causing liquidation attempts to fail with an array out-of-bounds error.
Mitigation: Iterate over a memory copy of activeMarketIds
using EnumerableSet::values
instead of accessing storage directly.
Guideline: Can a user with multiple open positions be liquidated? Does the test suite include a test for this scenario?
If a liquidatable user can modify key variables during the liquidation process, they can force the transaction to revert. By front-running liquidation attempts, they make themselves impossible to liquidate.
Examples of blocking liquidation:
Guideline: Is there a user-controlled variable that can cause liquidation to revert? Can a liquidatable user front-run liquidation to exploit this? What actions can a liquidatable user take, and should they be able to do so?
Additional cases: [1, 2, 3, 4, 5, 6]
Consider this liquidation check:
require(balance - (withdrawalPendingAmount + depositPendingAmount) > 0);
A malicious user can exploit this by initiating a withdrawal equal to their balance, causing all liquidation attempts to fail and making liquidation impossible.
Mitigation: Restrict liquidatable users from performing certain actions like deposits, withdrawals, or swaps. However, this approach may unintentionally affect legitimate users who had pending withdrawals before becoming liquidatable.
Additionally, an attacker might exploit protocol functions while in a liquidatable state to profit from an upcoming liquidation. Protocols should carefully assess which actions a liquidatable user should be allowed to perform.
Guideline: Are there any actions that require multiple transactions over several blocks to complete? If so, what occurs if a user is liquidated while these actions are still pending? What actions can a liquidatable user take, and should they be allowed to perform them?
onERC721Received
callback to block liquidationIf an NFT (ERC721) is "pushed" to an attacker-controlled address during liquidation, the attacker can set up their contract to revert in the onERC721Received
callback, preventing liquidation from being completed.
Mitigation: Use a "pull" mechanism, requiring NFT owners to manually retrieve their tokens in a separate transaction.
This attack can also occur with ERC20 tokens with transfer hooks, potentially disrupting liquidation settlements.
Guideline: If liquidation relies on a "push" mechanism for token transfers, can an attacker exploit callbacks to force the transaction to revert?
Some multi-collateral protocols allow users to deposit collateral into vaults or farms that generate yield, maximizing capital efficiency. These protocols must properly account for both deposited collateral and earned yield when:
If only the first is implemented, an attacker can exploit this by:
Mitigation: Smart contract auditors should verify that all instruments used as collateral are accounted for in liquidation and that any contracts holding collateral are properly notified when liquidation occurs.
Guideline: Does the protocol include features like yield generation for deposited collateral? If so, is the liquidation code fully integrated with these features? Can users obscure their deposited collateral in ways the liquidation system does not recognize?
Additional cases: [1]
In protocols where an insurance fund covers bad debt, liquidation transactions will fail if the debt surpasses the fund’s available balance—unless the protocol includes specific handling for this scenario. This can leave large insolvent positions stuck indefinitely, preventing liquidation until enough fees accumulate to replenish the insurance fund.
Guideline: What happens if the bad debt from an insolvent position exceeds the insurance fund’s balance?
Additional cases: [1]
Consider this code, which attempts to guarantee a fixed 10% liquidation bonus by providing extra seized collateral to the liquidator:
uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
// liquidator always receives 10% bonus
uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
_redeemCollateral(collateral, tokenAmountFromDebtCovered + bonusCollateral, user, msg.sender);
When a borrower’s collateral ratio falls below 110%, they become under-collateralized and subject to liquidation. However, if the fixed liquidation bonus requires more collateral than what remains, the transaction will fail, preventing liquidation.
Mitigation: Check whether the borrower has enough collateral to cover the bonus and, if not, limit the bonus to the maximum available amount.
Guideline: What happens if there isn’t enough collateral to fully cover the liquidation bonus?
Multi-collateral protocols support various assets, some of which do not follow the standard ERC20 18-decimal precision. To handle this, protocols typically:
While effective when consistently applied, large protocols with multiple developers can introduce inconsistencies. Auditors should verify that liquidation functions properly when either the collateral or debt token has a different decimal precision.
Guideline: Does liquidation work correctly when tokens have varying decimal precision?
nonReentrancy
modifiersIn complex protocols, liquidation logic often involves optional calls to multiple contracts. Auditors should ensure that no execution path triggers two functions with the nonReentrant
modifier within the same contract, as this would cause the transaction to fail.
Guideline: Are there any liquidation paths that invoke multiple nonReentrant
modifiers within the same contract?
Liquidation code typically involves calculating various token amounts, such as liquidator rewards and fees, followed by multiple token transfers. If the protocol does not check for zero-value transfers, liquidation may fail when dealing with tokens that revert on such transactions.
Guideline: Does the protocol perform zero-value checks before token transfers? If not, does it support tokens that revert on zero-value transfers?
Additional cases: [1]
Some tokens, like USDC, have deny lists that allow token admins to freeze certain addresses, causing all transfer attempts to those addresses to revert. Many liquidation mechanisms use a "push" model, where tokens are automatically sent to designated addresses. If a protocol supports deny-listed tokens and liquidation attempts to send funds to a blocked address, the transaction will fail, making liquidation impossible.
Mitigation: Switch to a "pull" model, where users must manually claim their tokens instead of having them automatically sent.
Guideline: Does the protocol use a "push" mechanism for liquidation and support tokens with deny lists? If so, what happens when liquidation attempts to send tokens to a blocked address?
Consider this liquidation logic:
// get number of borrowers
uint256 troveCount = troveManager.getTroveOwnersCount();
// only process liquidations when more than 1 borrower
while (trovesRemaining > 0 && troveCount > 1) {
This code prevents liquidation if there is only one borrower, which is a design flaw. A single borrower should still be subject to liquidation if their position becomes liquidatable.
Guideline: If only one borrower remains, can they still be liquidated?
Additional cases: [1]
Liquidation involves multiple calculations, including collateral valuation, bad debt assessment, and determining liquidator rewards and fees. Even minor miscalculations can have severe consequences.
Liquidation often involves both debt and collateral tokens, which may have different decimal precisions. Errors in handling these differences can lead to:
Consider this simplified code:
function executeLiquidate(State storage state, LiquidateParams calldata params)
external returns (uint256 liquidatorProfitCollateralToken) {
// @audit debtPosition = USDC using 6 decimals
DebtPosition storage debtPosition = state.getDebtPosition(params.debtPositionId);
// @audit assignedCollateral = WETH using 18 decimals
uint256 assignedCollateral = state.getDebtPositionAssignedCollateral(debtPosition);
// @audit debtPosition.futureValue = USDC using 6 decimals
// debtInCollateralToken = WETH using 18 decimals
uint256 debtInCollateralToken = state.debtTokenAmountToCollateralTokenAmount(debtPosition.futureValue);
if (assignedCollateral > debtInCollateralToken) {
uint256 liquidatorReward = Math.min(
assignedCollateral - debtInCollateralToken,
// @audit liquidatorReward calculated using debtPosition.futureValue using
// 6 decimals instead of debtInCollateralToken using 18 decimals, even though
// liquidation reward is paid in WETH collateral which uses 18 decimals
Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
// @audit should be:
// Math.mulDivUp(debtInCollateralToken, ...)
);
This liquidation function distributes rewards in collateral tokens (WETH with 18 decimals) but calculates the reward using the debt token (USDC with 6 decimals). As a result, liquidators receive a significantly lower payout than expected, reducing their incentive to participate.
The liquidation reward should scale proportionally—if a borrower takes the same loan amount from three lenders in one account, their liquidation reward should be comparable to borrowing from three lenders using separate accounts.
Errors in liquidation reward calculations can arise in many ways. Since there is no universal guideline, auditors must carefully review the specific implementation to identify potential miscalculations.
Additional cases: [1, 2, 3, 4, 5, 6, 7, 8, 9]
During liquidation, multiple fees may need to be distributed to different entities. If the available collateral (or insurance fund in cases of bad debt) is insufficient to cover all fees, the protocol should prioritize paying the liquidator’s reward. This ensures liquidators remain incentivized, especially in trustless systems where they play a crucial role in maintaining protocol solvency.
Guideline: What happens if there isn’t enough collateral to cover all liquidation fees? Is the liquidator reward given priority, particularly in protocols that rely on trustless liquidators?
Some protocols impose a "protocol fee" during liquidation, paid either by the liquidator or the liquidated user. If miscalculated and set too high, it can make liquidations unprofitable, discouraging liquidators and allowing bad debt to accumulate.
Consider this protocol liquidation fee calculation code:
function _transferAssetsToLiquidator(address position, AssetData[] calldata assetData) internal {
// transfer position assets to the liquidator and accrue protocol liquidation fees
uint256 assetDataLength = assetData.length;
for (uint256 i; i < assetDataLength; ++i) {
// ensure assetData[i] is in the position asset list
if (Position(payable(position)).hasAsset(assetData[i].asset) == false) {
revert PositionManager_SeizeInvalidAsset(position, assetData[i].asset);
}
// compute fee amt
// [ROUND] liquidation fee is rounded down, in favor of the liquidator
// @audit liquidator fee calculated from seized collateral amount
// makes many liquidations unprofitable
uint256 fee = liquidationFee.mulDiv(assetData[i].amt, 1e18);
// transfer fee amt to protocol
Position(payable(position)).transfer(owner(), assetData[i].asset, fee);
// transfer difference to the liquidator
Position(payable(position)).transfer(msg.sender, assetData[i].asset, assetData[i].amt - fee);
}
}
In this case, the protocol liquidation fee is set as a percentage of the total seized collateral. This approach can make many liquidations unprofitable—such as when the fee is excessively high (e.g., 30% of seized collateral), discouraging liquidators from acting and allowing bad debt to accumulate.
Mitigation:
Incorrect fee calculations can also work in reverse, allowing liquidators to pay less than necessary to complete a liquidation.
Guideline: Is the protocol liquidation fee based on the liquidator’s profit? If not, could the fee structure make liquidation unprofitable, discouraging liquidators?
Additional cases: [1, 2, 3, 4, 5]
When determining if a position is solvent or setting minimum collateral requirements, liquidation fees should be factored in. If they are excluded, a position that appears solvent may not have enough collateral to cover liquidation costs, causing the transaction to fail or creating bad debt.
However, some protocols do not include liquidation fees in collateral calculations, arguing it may be unfair to users.
Guideline: Are liquidation fees accounted for in minimum collateral requirements? If not, has the protocol explicitly documented its reasoning?
Some protocols allow deposited collateral to generate yield, increasing capital efficiency. However, if the earned yield is not included in the collateral valuation, a user may be unfairly liquidated despite having sufficient total value.
Guideline: Is earned yield considered when calculating a user's total collateral value? If not, can this lead to unfair liquidation? If it is included, what happens to the earned yield during liquidation—is it retained or lost?
In leveraged trading protocols, a trader’s open profit and loss (PNL) should be factored into their total collateral value:
If a protocol ignores positive PNL but deducts negative PNL, traders with large unrealized gains may be unfairly liquidated. If a protocol chooses not to account for positive PNL, it should explicitly communicate this to users.
Guideline: Is open PNL considered when determining liquidation? If not, can traders be unfairly liquidated despite having profitable positions? If it is included, what happens to the unrealized PNL—does it carry over, or is it lost?
Chainlink recommends a grace period after an L2 sequencer restarts, during which price data should not be fetched. If protocols prevent users from depositing additional collateral during this period, they may face immediate liquidation once fresh price data is available.
Mitigation: Protocols should consider allowing collateral deposits during the grace period, enabling users to protect their positions before new price data is applied.
Guideline: After an L2 sequencer comes back online, can users deposit collateral during the grace period before price data updates? Does the protocol provide a grace period to prevent immediate liquidation, or are users liquidated as soon as price data resumes?
If a protocol allows pausing but prevents users from repaying loans while paused, borrow interest should also stop accumulating. Otherwise, users may face instant liquidation upon unpausing due to the sudden interest buildup.
Guideline: Does borrow interest continue to accrue while the protocol is paused, even when users cannot make repayments?
A protocol should not allow a scenario where repayments are paused while liquidations remain enabled. This would unfairly liquidate borrowers who intended to repay but were blocked by the protocol itself.
Mitigation: Protocols should implement a grace period after unpausing liquidations, allowing users time to repay loans or add collateral before being liquidated.
Guideline: Can the protocol enter a state where users cannot repay but still face liquidation? After unpausing, is there a grace period for repayments and collateral deposits, or are users liquidated immediately?
Additional cases: [1, 2, 3, 4, 5, 6]
isLiquidatable
not refreshing interest or funding feesBefore determining if a user is liquidatable, the protocol must first update any accrued fees, such as loan interest or funding fees in leveraged trading. Failure to do so can result in delayed or incorrect liquidations.
Auditors should pay close attention to view
functions that check liquidation status but do not modify state, ensuring they properly calculate the latest owed fees. Additionally, all relevant fees must be updated before executing liquidation.
Guideline: Does the protocol refresh all interest, yield, funding fees, and PNL before determining whether a user is liquidatable?
An edge case in leveraged trading occurs when:
If this happens, the trader’s positive PNL, earned yield, and other rewards should be credited to their account before liquidation. Otherwise, these assets are lost, making liquidation unfair.
Guideline: Does the protocol ensure all unrealized profit, yield, and rewards are realized before liquidation? If not, are they lost after liquidation?
Some protocols impose swap fees when converting one asset to another. If these fees apply to regular swaps but are not charged when a liquidator exchanges debt tokens for seized collateral, the protocol, and its insurance fund may accumulate fewer tokens than expected.
Guideline: Does the protocol typically charge swap fees and execute swaps during liquidation? If so, does it apply a swap fee to liquidation swaps? If not, has the protocol explicitly documented why this exception exists?
An attacker can exploit a user-triggered oracle update to execute a profitable self-liquidation by following these steps:
This attack becomes profitable if the oracle price update causes the full collateral balance to be recovered while repaying fewer debt tokens than were borrowed.
Mitigation:
Self-liquidation can be a significant risk, especially if users can deliberately make themselves liquidatable to exploit the protocol.
Guideline: Can users deliberately become liquidatable and trigger self-liquidation? Can oracle price updates be manipulated to extract value from the protocol?
Liquidation, whether full or partial, should improve the borrower’s financial position by reducing their risk of future liquidation. However, in protocols that support multiple collateral types and partial liquidation, subtle bugs may leave borrowers in a worse condition post-liquidation, increasing the likelihood of further liquidations.
Consider this liquidate function:
function liquidatePartiallyFromTokens(
uint256 _nftId,
uint256 _nftIdLiquidator,
address _paybackToken,
address _receiveToken, //@audit liquidator can choose collateral
uint256 _shareAmountToPay
)
This liquidate function allows the liquidator to select which collateral to seize as compensation. This is risky because different types of collateral have varying:
A liquidator can exploit this by first seizing the borrower’s most stable, high-borrowing-factor collateral. This leaves the borrower with:
This can lead to cascading liquidations, where the first liquidation weakens the borrower’s position, triggering additional liquidations in quick succession. This leaves the trader with an unhealthier and riskier collateral basket.
Mitigation:
Common health score calculations:
collateral_value / borrow_value
(collateral_value * loan_to_value_ratio) / borrow_value
Guideline: Can liquidation leave a borrower in a worse financial state? Can liquidators selectively seize collateral, leaving borrowers with a more volatile and riskier portfolio?
Additional cases: [1, 2, 3, 4]
Protocols allowing various collateral types can lessen the aforementioned risk by establishing a prioritized liquidation order, targeting the more volatile, higher-risk collateral first. However, caution is crucial when designing functions that modify this order, as they could inadvertently corrupt it, leading to improper liquidation.
Guideline: Can the collateral liquidation priority be corrupted by the functions that change it?
Certain protocols offer an optional "replacement" liquidation method. This allows a liquidatable position to be used to fulfill an order from an order book, essentially substituting a financially unstable borrower with a stable one.
Other protocols permit users to "purchase" a liquidatable position, effectively assuming it, provided they have sufficient collateral to ensure its solvency. This achieves the same outcome: transferring the debt from the original, unhealthy borrower to a new, healthy one.
In both scenarios, the borrower's address is updated to the new borrower, but other data, like the position's id
and debt, typically remain unchanged. Consider the potential conflict when these two transactions occur simultaneously:
Transaction 1 (TX1): The original, liquidatable borrower attempts to repay their position, providing its id
as input.
Transaction 2 (TX2): A replacement liquidation transaction attempts to transfer the position to a healthier borrower.
If TX2 executes before TX1, the new borrower acquires the position before the original borrower's repayment. The original borrower effectively repays the debt of the new borrower! In protocols allowing users to "buy" positions, a malicious actor could exploit this by front-running repayment transactions. They could buy the liquidatable position and then have the original borrower repay the debt on the position they just acquired.
A possible solution is to require repayment transactions to include the borrower's address as input and to revert the transaction if the current borrower's address doesn't match.
Guideline: Is it possible to transfer a liquidatable position from an unstable user to a stable one? If so, what are the consequences if the unstable user attempts repayment concurrently with the transfer?
Additional cases: [1]
Many platforms utilize a higher loan-to-value (LTV) ratio for initiating a loan compared to the LTV ratio that triggers liquidation. This difference is implemented to protect borrowers from immediate liquidation after establishing a new position.
Eliminating this gap between borrowing and liquidation LTV ratios allows users to open positions that are dangerously close to liquidation. This increases the probability of liquidations, jeopardizing the platform's stability and negatively impacting user experience.
Guideline: Can a user face liquidation shortly after opening a new position? What about after adjusting an existing position?
Additional cases: [1, 2, 3, 4]
Certain protocols employ an "auction" system where a liquidatable position is auctioned off over a specific timeframe. In these instances, debt interest accrual should be suspended immediately upon auction initiation. Liquidating positions shouldn't accumulate further interest during the auction.
Guideline: Does a borrower continue to accrue interest while their debt is being auctioned?
Ideally, during liquidation, the liquidator should be able to define the minimum acceptable reward (tokens, shares, etc.). This is crucial for protocols using liquidation swaps, as these swaps are susceptible to MEV exploitation, potentially yielding lower-than-expected rewards for the liquidator.
Guideline: Can the liquidator set a slippage parameter? If swaps are part of liquidation, could this lead to the liquidator (or the protocol or the liquidated user) receiving fewer tokens than anticipated?