Skip to main content

Repay (simulate)

POST 

/v1/actions/lending/repay

Build calldata for repaying a loan and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (balanceData, aprData, positions) to receive projected post-trade metrics in the simulation field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include positions for accurate health-factor and borrow-capacity projections.

Plain-text reference — POST /v1/actions/lending/repay

Parameters

ParameterInTypeRequiredDescription
marketUidquerystringyesMarket identifier (lender:chainId:address). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).
amountquerystringyesAmount in wei
modequeryproxy, directnoExecution mode. proxy = 1delta composer, direct = raw protocol
operatorquerystringnoWallet address of the user executing the action
receiverquerystringnoRecipient of the lender position (deposit) or underlying tokens (borrow/withdraw).
Defaults to operator when omitted.

Custom-receiver support is per-lender. The API auto-selects the execution path:

Direct path supported

  • Aave V2/V3 — supply / withdraw honor to.
  • Aave V4 — deposit via GiverPM supplyOnBehalfOf. Requires the GiverPM to be curated in aave-v4-peripherals.json with a name containing "giver".
  • Compound V3 — supplyTo / withdrawTo.
  • Morpho Blue & Lista DAO ERC-20 markets — Morpho onBehalf.
  • Euler V2 ERC-20 vaults — ERC-4626 deposit(receiver). Collateral auto-enable is dropped for non-sub-account receivers.
  • Silo V2/V3 ERC-20 — deposit(_, receiver, _).
  • Gearbox V3 passive-pool deposits — ERC-4626 deposit(_, receiver).
  • Fluid borrow & withdraw — operate(..., to_) outflow slot.
  • Fluid deposit to an existing NFT when accountId is supplied — pure-deposit operate() calls bypass Fluid's owner auth gate, and the API folds a pre-flight VaultFactory.ownerOf(nftId) == receiver check into the merged multicall (rejects with 400 INVALID_PARAM on mismatch, VALIDATION_FAILED if the RPC can't confirm ownership).

Routes to composer (proxy) path

  • Compound V2 family — direct mint is msg.sender-only.
  • Fluid fresh-open deposits — no accountId or accountId=0. The composer mints the new position NFT to itself, then transfers it to receiver via the encoder's nftReceiver slot.
  • Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards msg.value to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as payAsset.

Direct-only branches that throw

  • Gearbox V3 credit-side addCollateral — CA bound to operator.
  • Aave V4 native-gateway path — supplyAsCollateralNative has no recipient slot.

Unsupported in any single tx

  • Init Capital — position NFT swept to operator.
  • Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.
  • Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).

When the lender cannot honor a custom receiver on the direct path, getTarget falls back to proxy automatically. Forcing mode=direct on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | isAll | query | boolean | no | Withdraw/repay full balance.

When on-chain position data is available, the API compares amount against the actual balance to decide the effective mode:

  • If amount covers the full position the action is treated as "withdraw/repay all" regardless of this flag.
  • If isAll is true but amount is less than the position, the API falls back to a partial action with the provided amount to avoid on-chain reverts.

Without on-chain data, the flag is trusted as-is. | | lendingMode | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) | | loanId | query | string | no | Lista DAO fixed-term (brokered) markets only. Identifies which loan to repay.

Pass the loanId of the target loan from the user's positions (each per-loan position in the user-positions response carries loanId and a term object). To repay the flexible / dynamic position instead, pass the sentinel 340282366920938463463374607431768211455 (type(uint128).max).

The broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed loans) and refunds any excess to the caller, so to fully close a loan fund outstanding + accruedInterest + earlyRepayPenalty (all on the per-loan term).

Required on brokered repays; ignored for non-brokered lenders. | | payAsset | query | string | no | Asset to pay with.

Use the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 cETH markets).

Proxy mode: defaults to market asset. Native is forwarded as msg.value only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | isShares | query | boolean | no | Amount is in shares (direct mode) | | accountId | query | string | no | Per-position identifier. Lender-specific:

  • Init Capital — account ID, required for borrow/withdraw/repay.
  • Euler V2 — sub-account index (0..255), defaults to 0.
  • Gearbox V3 — credit-account address (alias: creditAccount).
  • Fluid — position NFT id. Omit or pass 0 to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom receiver (deposit lands on the receiver-owned NFT after pre-flight ownerOf validation). | | slippage | query | number | no | Slippage tolerance in basis points (50 = 0.5%, 100 = 1%).

Required whenever the action has to price something:

  • Aggregator swap — when payAsset / receiveAsset differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap.
  • Order-book take (Morpho Midnight) — bounds the worst execution price accepted while filling offers.

Ignored when neither applies (same-asset action on a pool lender). | | simulate | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the simulation field. Default: false. |

Request body

FieldTypeRequiredDescription
balanceDataobjectyesAggregated balance data for a sub-account.
balanceData.depositsnumbernoTotal deposits in USD
balanceData.debtnumbernoTotal debt in USD
balanceData.adjustedDebtnumbernoDebt adjusted for borrow factors
balanceData.collateralnumbernoCollateral value in USD
balanceData.collateralAllActivenumbernoCollateral if all assets were enabled
balanceData.borrowDiscountedCollateralnumbernoCollateral discounted by borrow factors
balanceData.borrowDiscountedCollateralAllActivenumbernoDiscounted collateral if all enabled
balanceData.navnumbernoNet asset value (deposits - debt)
balanceData.deposits24hnumbernoDeposits 24h ago (for change calculation)
balanceData.debt24hnumbernoDebt 24h ago
balanceData.nav24hnumbernoNAV 24h ago
balanceData.rewardsobject[]noPending reward token claims. Each entry represents a single reward program.
balanceData.rewards[].assetstringnoReward token contract address
balanceData.rewards[].totalRewardsnumbernoTotal accumulated rewards (token units)
balanceData.rewards[].claimableRewardsnumbernoImmediately claimable rewards (token units)
aprDataobjectyesAPR breakdown for a sub-account.
aprData.aprnumbernoNet APR (deposit - borrow)
aprData.depositAprnumbernoWeighted deposit APR
aprData.borrowAprnumbernoWeighted borrow APR
aprData.rewardAprnumbernoTotal reward APR
aprData.rewardDepositAprnumbernoReward APR on deposits
aprData.rewardBorrowAprnumbernoReward APR on borrows
aprData.intrinsicAprnumbernoIntrinsic yield APR (e.g., stETH staking)
aprData.intrinsicDepositAprnumbernoIntrinsic yield APR portion from deposits
aprData.intrinsicBorrowAprnumbernoIntrinsic yield APR portion from borrows
aprData.rewardsobjectnoPer-reward-token APR breakdown. Keys are reward token addresses.
modeIdstringnoMode/config key from userConfig.selectedMode (defaults to "0")
positionsobject[]noCurrent lending positions from the matching sub-account's positions array. The full LendingPosition objects returned by user-positions are accepted — only the fields in SimulationPosition are used. Always include this for accurate health-factor and borrow-capacity projections.
positions[].marketUidstringyesUnique market identifier (format: {lender}:{chainId}:{address})
positions[].depositsUSDnumberyesDeposit amount in USD
positions[].debtUSDnumberyesVariable debt in USD
positions[].debtStableUSDnumberyesStable debt in USD
positions[].collateralEnabledbooleanyesWhether this asset is enabled as collateral

Response 200

FieldTypeDescription
successTrue
dataobjectSimulation results including projected health factor and borrow capacity
data.transactionobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.transaction.tostringTarget contract address
data.transaction.datastringEncoded calldata
data.transaction.valuestringETH value to send with the transaction
data.transaction.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.permissionTxnsobject[]Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level actions.permissions instead.
data.permissionTxns[].tostringTarget contract address
data.permissionTxns[].datastringEncoded calldata
data.permissionTxns[].valuestringETH value
data.permissionTxns[].descriptionstringHuman-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20")
data.permissionTxns[].spenderstringERC-20 approve spender (x-chain permissions). Match it against the selected quote's approvalTarget — several bridges can share one spender, so do not match by description.
data.rateImpactobject[]Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable.
data.rateImpact[].marketUidstringMarket identifier (format: lender:chainId:address)
data.rateImpact[].utilizationobjectA current/projected pair for a single rate metric.
data.rateImpact[].utilization.currentnumberCurrent value
data.rateImpact[].utilization.projectednumberProjected value after the action
data.rateImpact[].borrowRateobjectA current/projected pair for a single rate metric.
data.rateImpact[].borrowRate.currentnumberCurrent value
data.rateImpact[].borrowRate.projectednumberProjected value after the action
data.rateImpact[].depositRateobjectA current/projected pair for a single rate metric.
data.rateImpact[].depositRate.currentnumberCurrent value
data.rateImpact[].depositRate.projectednumberProjected value after the action
data.simulationobjectProjected post-trade metrics, or null if simulation failed
data.simulation.preobjectPortfolio state before the trade.
data.simulation.pre.healthFactornumberHealth factor before the trade (null-safe: capped at 1e18 when no debt)
data.simulation.pre.borrowCapacitynumberBorrow capacity (USD) before the trade
data.simulation.postobjectProjected portfolio state after the trade.
data.simulation.post.healthFactornumberProjected health factor after the trade
data.simulation.post.borrowCapacitynumberProjected borrow capacity (USD) after the trade
data.simulation.post.balanceDataobjectAggregated balance data for a sub-account.
data.simulation.post.aprDataobjectAPR breakdown for a sub-account.
data.simulationErrorstringError message if simulation failed
data.transactionobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.transaction.tostringTarget contract address
data.transaction.datastringEncoded calldata
data.transaction.valuestringETH value to send with the transaction
data.transaction.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.permissionTxnsobject[]Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level actions.permissions instead.

Example response

{
"success": true,
"data": {
"transaction": {
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
},
"permissionTxns": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
],
"rateImpact": [
{
"marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
"utilization": {
"current": 1.0,
"projected": 1.0
},
"borrowRate": {
"current": 1.0,
"projected": 1.0
},
"depositRate": {
"current": 1.0,
"projected": 1.0
}
}
],
"simulation": {
"pre": {
"healthFactor": 1.85,
"borrowCapacity": 3000
},
"post": {
"healthFactor": 2.1,
"borrowCapacity": 3500,
"balanceData": {
"deposits": 10000.5,
"debt": 5000.25,
"adjustedDebt": 5500,
"collateral": 9000,
"collateralAllActive": 10000.5,
"borrowDiscountedCollateral": 8000,
"borrowDiscountedCollateralAllActive": 9000,
"nav": 5000.25,
"deposits24h": 9800,
"debt24h": 4900,
"nav24h": 4900,
"rewards": [
{
"asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
"totalRewards": 12.5,
"claimableRewards": 12.5
}
]
},
"aprData": {
"apr": 2.5,
"depositApr": 3.5,
"borrowApr": 5.2,
"rewardApr": 1.2,
"rewardDepositApr": 0.8,
"rewardBorrowApr": 0.4,
"intrinsicApr": 0,
"intrinsicDepositApr": 0,
"intrinsicBorrowApr": 0,
"rewards": {}
}
}
},
"simulationError": "string"
},
"actions": {
"transactions": [
{
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"alternatives": [
{
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"permissions": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
]
}
}

Request

Responses

Transaction calldata with post-trade simulation