User Position Conditions
Learn how user position conditions work in Aave v4.
User positions track two risk conditions: Dynamic Risk Configuration and User Risk Premium.
Dynamic Risk Configuration
Dynamic Risk Configuration, or Dynamic Config for short, snapshots the per-reserve collateral parameters—Collateral Factor, Max Liquidation Bonus, and Protocol Fee—active when the position first became risk-bearing, i.e. when the user initially borrowed against collateral.
It updates when the user performs risk-increasing actions: borrowing, withdrawing collateral, or disabling collateral (updates all reserves' snapshots), or enabling collateral (updates only that reserve's snapshot). It can also be updated manually, and always refreshes the User Risk Premium.
The Dynamic Config values used on first borrow or after an update—implicit or explicit—are exposed on the Reserve object under the settings field:
Live Dynamic Config
const reserve: Reserve = { __typename: "Reserve", id: "SGVsbG8h", settings: { __typename: "ReserveSettings", collateralFactor: { normalized: BigDecimal(80), // 90% // … }, maxLiquidationBonus: { normalized: BigDecimal(10), // 10% // … }, // protocol fee liquidationFee: { normalized: BigDecimal(1), // 1% // … }, // … latestDynamicConfigKey: "1234567890", }, // …};The snapshotted values are exposed under the Reserve's userState field: the Collateral Factor applies to reserves linked by UserSupplyItem when used as collateral, while the Max Liquidation Bonus and Protocol Fee apply to reserves linked by UserBorrowItem.
User Risk Premium reflects the current risk profile of the collateral assets. In practice, it acts as a multiplier—a percentage applied on top of each reserve's base borrow rate. Lower is better.
A high User Risk Premium signals riskier collateral, which in turn results in a higher borrowing rate. Conversely, a low User Risk Premium indicates higher-quality collateral and leads to reduced borrowing costs.
It updates when the user performs actions that affect collateralization (borrowing, withdrawing collateral, enabling or disabling collateral), when the Dynamic Risk Configuration changes, or when explicitly triggered.
You can keep track of the User Risk Premium for a position by checking the riskPremium.current field in the User Position response.
User Risk Premium
const userPosition: UserPosition = { __typename: "UserPosition", id: "aGVsbG8", user: "0x456…", riskPremium: { current: { normalized: BigDecimal(50), // 50% // … }, latest: { normalized: BigDecimal(50), // 50% - same as current // … }, breakdown: [ // … ], }, spoke: { id: "SGVsbG8h", address: "0x123…", chain: { chainId: 1, name: "Ethereum", // … }, // … }, // …};The example above shows a User Risk Premium of 50%. This means that on an asset with a base borrow rate of 5%, the user is paying 7.5% interest on their borrow positions (5% + 50% = 7.5%).
The riskPremium.breakdown field contains the User Risk Premium Breakdown for the user position collaterals.
The User Risk Premium Breakdown shows each collateral asset in a user position, including what percentage of total collateral it represents and its weight in the overall User Risk Premium.
User Risk Premium Breakdown
const breakdown: UserRiskPremiumBreakdownItem[] = [ { __typename: "UserRiskPremiumBreakdownItem", token: { __typename: "Erc20Token", id: "aGVsbG8", address: "0x456…", name: "USDC", symbol: "USDC", decimals: 6, }, currentRiskPremiumWeight: { __typename: "PercentNumber", normalized: BigDecimal(50), // 50% // … }, latestRiskPremiumWeight: { __typename: "PercentNumber", normalized: BigDecimal(45), // 45% // … }, collateral: { __typename: "PercentNumber", normalized: BigDecimal(30), // 30% // … }, }, // …];Where:
currentRiskPremiumWeight represents the current contribution of this collateral asset to the overall User Risk Premium.
latestRiskPremiumWeight represents the contribution if the User Risk Premium were to be updated.
collateral represents this asset’s share of the position’s total collateral value.
As mentioned above, the breakdown is available in the riskPremium.breakdown field of user positions, or you can use the standalone query explained below.
- React
- TypeScript
- GraphQL
Use the useUserRiskPremiumBreakdown hook to fetch the breakdown for a specific user position.
You can query by user position ID or by user spoke:
Update Conditions
As protocol configurations evolve through governance votes, a user position’s conditions may improve.
Updating user position conditions can be broken down into the following steps:
Identify eligible positions
Preview the impact of the update (optional)
Update the position conditions
Identify Eligible Positions
You can identify positions that qualify for updates by checking if the riskPremium.latest is lower than riskPremium.current (indicating a better risk premium is available) or the canUpdateDynamicConfig field (true when dynamic config can be updated) in the user's positions.
Eligible User Position
const userPosition: UserPosition = { __typename: "UserPosition", id: "aGVsbG8", user: "0x456…", riskPremium: { current: { normalized: BigDecimal(50), // 50% // … }, latest: { normalized: BigDecimal(25), // 25% - lower is better // … }, breakdown: [ // … ], }, spoke: { id: "SGVsbG8h", address: "0x123…", chain: { chainId: 1, name: "Ethereum", // … }, // … }, canUpdateDynamicConfig: true, // …};Preview the Impact
Preview the impact of updating the user position conditions before committing to it.
- React
- TypeScript
- GraphQL
Use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of updating the user position conditions.
See below for examples of UpdateUserPositionConditionsRequest objects.
Remember that updating Dynamic Config will also update the User Risk Premium.
The PreviewUserPosition shows the impact of the update user position conditions operation by comparing current and after states, with the table below outlining key fields and how to interpret them.
| Field | Impact | |
|---|---|---|
| healthFactor.[current → after]: BigDecimal|null | Higher is better (null if not applicable) | |
| riskPremium.[current → after]: PercentNumber | Lower is better | |
| netApy.[current → after]: PercentNumber | Higher is better | |
| projectedEarning.[current → after]: ExchangeAmount | Projected earnings | |
| borrowingPower.[current → after]: ExchangeAmount | Borrowing power | |
| otherConditions: UserPositionConditionVariation[] | Dynamic config changes |
The otherConditions field is an array of objects describing dynamic configuration changes per reserve the user has a position in.
CollateralFactorVariation – Collateral factor change
LiquidationFeeVariation – Liquidation fee change
MaxLiquidationBonusVariation – Maximum liquidation bonus change
Step-by-Step
Now that we know how to identify the user positions that qualify for an update, and we know how to preview the impact of updating the user position conditions, let's see how to update the user position conditions.
- React
- TypeScript
- GraphQL
- Solidity
To update user position conditions with AaveKit React, follow these steps.
First, instantiate the useSendTransaction hook for the wallet library of your choice.
Viem
import { useWalletClient } from "wagmi";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();const [sendTransaction] = useSendTransaction(wallet);Then, use the useUpdateUserPositionConditions hook to prepare the transaction request.
Then, execute the transaction.
Remember that updating Dynamic Config will also update the User Risk Premium.
Finally, handle the result.
Example
const execute = async () => { const result = await updateConditions(/* … */);
if (result.isErr()) { switch (result.error.name) { case "CancelError": // The user cancelled the operation return;
case "SigningError": console.error( `Failed to sign the transaction: ${result.error.message}` ); break;
case "TimeoutError": console.error(`Transaction timed out: ${result.error.message}`); break;
case "TransactionError": console.error(`Transaction failed: ${result.error.message}`); break;
case "UnexpectedError": console.error(result.error.message); break; } return; }
console.log( "Position conditions updated successfully with hash:", result.value );};Advanced Usage
Network Fee
This experimental AaveKit React hook currently works only with Viem or Wagmi integrations. Support for additional wallet libraries may be added later.
Estimate the network cost of any action using the same PreviewAction you pass to the usePreview hook.
Let's consider the following example:
PreviewAction
import { type PreviewAction, UserPositionConditionsUpdate } from "@aave/react";
const action: PreviewAction = { updateUserPositionConditions: { userPositionId: userPosition.id, // from UserPosition update: UserPositionConditionsUpdate.AllDynamicConfig, },};Use the useNetworkFee hook to estimate both the network fee for the provided action and its fiat equivalent.
Viem
import { type PreviewAction, Currency } from "@aave/react";import { useNetworkFee } from "@aave/react/viem";
function NetworkFee({ action }: { action: PreviewAction }) { const { data: fee, loading, error, } = useNetworkFee({ query: { estimate: action }, currency: Currency.Eur, });
if (loading) return <p>Loading fee…</p>; if (error) return <p>Error: {error.message}</p>;
return ( <p> Network Fee: {fee.amount.value.toDisplayString(2)} {fee.token.info.symbol} <span> ≈{fee.exchange.symbol} {fee.exchange.value.toDisplayString(2)} </span> </p> );}