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,
});