> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Debt Migration

> 使用两笔并发闪电贷，将 Aave V3 借款仓位原子性地迁移到 Morpho Blue。

<Warning>
  **尚未公开。** 请联系我们以获取抢先体验。
</Warning>

## 场景

一位用户在 **Aave V3**（Base）上持有一笔以 WETH 为抵押的 USDC 借款，并想把同样的仓位改到 **Morpho Blue** 上 —— 比方说为了获取更好的利率。手动完成这件事意味着要在提取抵押品之前先找到资金来偿还 Aave，而这正是闪电贷所解决的先有鸡还是先有蛋的难题。

该 flow 并发借入两笔闪电贷，并在同一笔交易内解绑两者：

* \*\*闪电贷 #1（Aave V3，USDC）\*\*在 Morpho 借款存在之前偿还 Aave 债务。
* \*\*闪电贷 #2（Balancer V2，WETH）\*\*在 Aave 抵押品被释放之前供应 Morpho 抵押品。

Morpho 借款的额度恰好为 `principal + Aave fee`，因此它以零残余结清闪电贷 #1；从 Aave 释放出的 WETH 结清闪电贷 #2（Balancer V2 不收费）。

## 本配方演示了什么

* [`flashloan`](/composer/composer-api/materialisers/flashloan) materialiser 从两个不同的提供方为两个 flow 输入提供来源。
* 用 `lifi.flashloanRepay` 结清每一条 leg，通过 `leg` 键关联到它所偿还的输入。
* 跨协议穿引收据句柄：`aave.repay` → `lifi.zap` 提取 → `morphoBlue.supplyCollateral` / `morphoBlue.borrow`。
* 一个安全的 `sweepTo`：Aave aToken 抵押品被**完全解绑**（提取为 WETH），因此代理上不会留下任何不可转移的东西。（与保留 aToken 仓位的 flow 形成对比 —— 参见 [`sweepTo` 注意事项](/composer/composer-api/concepts/sweeping-and-amounts#non-transferable-terminal-resources)。）

## 完整示例

改编自 `composer-sdk-examples` 仓库中的 [`aaveToMorphoDebtMigration.ts`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/staged/aaveToMorphoDebtMigration.ts)。另有两个将目标债务通过一次交换进行路由的变体 —— [`...WithSwap`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/staged/aaveToMorphoDebtMigrationWithSwap.ts) 和 [`...WithSwapExactOut`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/staged/aaveToMorphoDebtMigrationWithSwapExactOut.ts) —— 都建立在相同的形态之上。

```ts theme={"system"}
import { createComposeSdk, materialisers, resources } from '@lifi/composer-sdk';

// Base mainnet (chain 8453)
const BASE_WETH = '0x4200000000000000000000000000000000000006';
const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';

// Aave V3 on Base (pool + aWETH receipt + variable-debt USDC)
const AAVE_V3_POOL_BASE = '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5';
const A_BAS_WETH = '0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7';
const VDEBT_BAS_USDC = '0x59dca05b6c26dbd64b5381374aAaC5CD05644C28';

// Morpho Blue WETH/USDC market on Base
const MORPHO_WETH_USDC_MARKET = {
  loanToken: BASE_USDC,
  collateralToken: BASE_WETH,
  oracle: '0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4',
  irm: '0x46415998764C29aB2a25CbeA6254146D50D22687',
  lltv: '860000000000000000',
};

const collateralAmount = '1000000000000000000'; // 1 WETH
const debtAmount = '1000000000'; // 1,000 USDC
const debtFlashloanFee = '500000'; // 5 bps of principal (Aave V3 flashloan fee)

// Morpho borrow must equal principal + Aave flashloan fee so `borrowed`
// settles the USDC flashloan leg exactly.
const morphoBorrowAmount = (
  BigInt(debtAmount) + BigInt(debtFlashloanFee)
).toString();

const sdk = createComposeSdk({ baseUrl: 'https://composer.li.quest' });

const builder = sdk.flow(8453, {
  name: 'aave-to-morpho-debt-migration',
  inputs: {
    initialCollateral: resources.erc20(BASE_WETH, 8453),
    debtFlashloan: resources.erc20(BASE_USDC, 8453),
    collateralFlashloan: resources.erc20(BASE_WETH, 8453),
  },
});

// --- Phase 1: provision the Aave V3 borrow position ---

// WETH → aBasWETH (Aave V3 supply via routing edge).
const supplyToAave = builder.lifi.zap('supply-to-aave', {
  bind: { amountIn: builder.inputs.initialCollateral },
  config: { resourceOut: resources.erc20(A_BAS_WETH, 8453) },
});

// Borrow USDC against the supplied collateral; proceeds are swept to the signer.
builder.aave.borrow('borrow-from-aave', {
  bind: {},
  config: {
    pool: AAVE_V3_POOL_BASE,
    asset: BASE_USDC,
    variableDebtToken: VDEBT_BAS_USDC,
    amount: debtAmount,
  },
});

// --- Phase 2: migrate to Morpho with two concurrent flash loans ---

// Repay the Aave USDC debt with flash loan #1 (mode: 'max' clamps to the debt).
builder.aave.repay('repay-aave', {
  bind: {
    assetIn: builder.inputs.debtFlashloan,
    onBehalfOf: builder.context.executionAddress,
  },
  config: { pool: AAVE_V3_POOL_BASE, mode: 'max' },
});

// Withdraw the freed WETH from Aave (aBasWETH → WETH).
const withdrawFromAave = builder.lifi.zap('withdraw-from-aave', {
  bind: { amountIn: supplyToAave.amountOut },
  config: { resourceOut: resources.erc20(BASE_WETH, 8453) },
});

// Open the Morpho position with flash loan #2's WETH.
builder.morphoBlue.supplyCollateral('supply-to-morpho', {
  bind: { assetIn: builder.inputs.collateralFlashloan },
  config: { marketParams: MORPHO_WETH_USDC_MARKET, mode: 'exact' },
});

// Borrow exactly principal + fee from Morpho to settle the USDC leg.
const morphoBorrow = builder.morphoBlue.borrow('borrow-from-morpho', {
  bind: {},
  config: { marketParams: MORPHO_WETH_USDC_MARKET, amount: morphoBorrowAmount },
});

// Settle the USDC flash loan with the Morpho borrow.
builder.lifi.flashloanRepay('repay-debt-flashloan', {
  bind: { funds: morphoBorrow.borrowed },
  config: { leg: 'debtFlashloan' },
});

// Settle the WETH flash loan with the Aave withdrawal (Balancer V2: no fee).
builder.lifi.flashloanRepay('repay-collateral-flashloan', {
  bind: { funds: withdrawFromAave.amountOut },
  config: { leg: 'collateralFlashloan' },
});

const request = sdk.request(builder.build(), {
  signer: '0xYourSignerAddress',
  inputs: {
    initialCollateral: materialisers.directDeposit({ amount: collateralAmount }),
    debtFlashloan: materialisers.flashloan({
      providerKind: 'aave-v3',
      amount: debtAmount,
    }),
    collateralFlashloan: materialisers.flashloan({
      providerKind: 'balancer-v2',
      amount: collateralAmount,
    }),
  },
  sweepTo: builder.context.sender,
});
```

## 需要留意什么

* **Inputs。** 三个资源输入：用户的抵押品（`directDeposit`）加上两个来自不同提供方的 `flashloan` 来源输入。
* **为什么用两个提供方。** Aave V3 供应用于偿还的 USDC；Balancer V2 供应 WETH 抵押品（且不收费，因此它这条 leg 仅由提取出的本金结清）。
* **给 Morpho 借款定额度。** `principal + debtFlashloanFee`，这样 `borrowed` 资源就以零剩余结清 USDC leg。
* **偿还是强制性的。** 两笔闪电贷都必须在 flow 内通过 `lifi.flashloanRepay` 偿还，否则模拟会回滚。
* **这里的 `sweepTo` 是安全的**，因为 Aave aToken 被完全提取为 WETH —— 代理上不残留任何被绑定的抵押品收据。当一个 flow *保留* aToken 仓位时，请省略笼统的 `sweepTo`，只转移零散代币（参见[注意事项](/composer/composer-api/concepts/sweeping-and-amounts#non-transferable-terminal-resources)）。
