@lifi/composer-sdk 0.2.0-staging.3 → 0.2.0-staging.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/package.json +3 -4
- package/src/examples/staged/aaveBorrow.ts +104 -0
- package/src/examples/staged/aaveDebtRebalanceExactOut.ts +301 -0
- package/src/examples/staged/aaveHealthFactorExplode.ts +70 -0
- package/src/examples/staged/aaveToMorphoDebtMigration.ts +190 -0
- package/src/examples/staged/aaveToMorphoDebtMigrationWithSwap.ts +221 -0
- package/src/examples/staged/aaveToMorphoDebtMigrationWithSwapExactOut.ts +302 -0
- package/src/examples/staged/flashloanRepay.ts +138 -0
- package/src/examples/staged/morphoBlueBorrow.ts +89 -0
- package/src/examples/staged/morphoBlueRepay.ts +91 -0
- package/src/examples/staged/registry.ts +78 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
import { createComposeSdk, materialisers, resources } from '../../index.js';
|
|
4
|
+
import type { Address } from '../../types.js';
|
|
5
|
+
import { BASE_URL } from '../config.js';
|
|
6
|
+
|
|
7
|
+
// Base mainnet token addresses.
|
|
8
|
+
const BASE_WETH = '0x4200000000000000000000000000000000000006';
|
|
9
|
+
const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
|
|
10
|
+
|
|
11
|
+
// Aave V3 on Base (pool + aWETH receipt + variable-debt USDC).
|
|
12
|
+
const AAVE_V3_POOL_BASE = '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5';
|
|
13
|
+
const A_BAS_WETH = '0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7';
|
|
14
|
+
const VDEBT_BAS_USDC = '0x59dca05b6c26dbd64b5381374aAaC5CD05644C28';
|
|
15
|
+
|
|
16
|
+
// Morpho Blue WETH/USDC market on Base (same parameters as the
|
|
17
|
+
// `morphoBlueBorrow` / `morphoBlueRepay` examples).
|
|
18
|
+
const ADAPTIVE_CURVE_IRM_BASE = '0x46415998764C29aB2a25CbeA6254146D50D22687';
|
|
19
|
+
const WETH_USDC_ORACLE = '0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4';
|
|
20
|
+
const WETH_USDC_LLTV = '860000000000000000';
|
|
21
|
+
|
|
22
|
+
const MORPHO_WETH_USDC_MARKET = {
|
|
23
|
+
loanToken: BASE_USDC,
|
|
24
|
+
collateralToken: BASE_WETH,
|
|
25
|
+
oracle: WETH_USDC_ORACLE,
|
|
26
|
+
irm: ADAPTIVE_CURVE_IRM_BASE,
|
|
27
|
+
lltv: WETH_USDC_LLTV,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export interface AaveToMorphoDebtMigrationInput {
|
|
31
|
+
readonly owner: Address;
|
|
32
|
+
/** WETH collateral the user posts (in smallest units). */
|
|
33
|
+
readonly collateralAmount: `${bigint}`;
|
|
34
|
+
/** USDC principal borrowed from Aave (in smallest units). */
|
|
35
|
+
readonly debtAmount: `${bigint}`;
|
|
36
|
+
/**
|
|
37
|
+
* Aave-V3 flashloan fee on `debtAmount` — equals
|
|
38
|
+
* `computeDefaultFee('aave-v3', debtAmount)` (5 bps of the principal).
|
|
39
|
+
*/
|
|
40
|
+
readonly debtFlashloanFee: `${bigint}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Atomically provision an Aave V3 borrow position on Base and migrate it to
|
|
45
|
+
* a Morpho Blue WETH/USDC market — all in a single compose flow driven by
|
|
46
|
+
* two concurrent flashloans.
|
|
47
|
+
*
|
|
48
|
+
* Phase 1 — provision the source position on Aave V3:
|
|
49
|
+
* - User direct-deposits WETH.
|
|
50
|
+
* - `lifi.zap` supplies the WETH to Aave (WETH → aBasWETH routing edge).
|
|
51
|
+
* - `aave.borrow` mints USDC debt; the borrowed USDC stays on the proxy
|
|
52
|
+
* and is swept back to the signer as the user's loan proceeds.
|
|
53
|
+
*
|
|
54
|
+
* Phase 2 — migrate the position to Morpho using two concurrent flashloans:
|
|
55
|
+
* - Flashloan #1 (Aave V3, USDC) bridges the Aave debt payoff before the
|
|
56
|
+
* Morpho borrow exists.
|
|
57
|
+
* - Flashloan #2 (Balancer V2, WETH) bridges the Morpho collateral supply
|
|
58
|
+
* before the Aave collateral is freed.
|
|
59
|
+
* - `aave.repay` clears the Aave USDC debt with flashloan #1.
|
|
60
|
+
* - `lifi.zap` withdraws the freed WETH from Aave (aBasWETH → WETH).
|
|
61
|
+
* - `morphoBlue.supplyCollateral` deposits flashloan #2's WETH into Morpho.
|
|
62
|
+
* - `morphoBlue.borrow` mints exactly `debtAmount + debtFlashloanFee` USDC
|
|
63
|
+
* so the `borrowed` resource settles flashloan #1 with zero residual.
|
|
64
|
+
* - Two `lifi.flashloanRepay` ops settle each leg: the USDC leg from the
|
|
65
|
+
* Morpho borrow, the WETH leg from the Aave withdrawal (Balancer V2
|
|
66
|
+
* charges no fee, so the principal alone covers it).
|
|
67
|
+
*
|
|
68
|
+
* After execution the signer holds `debtAmount` USDC and an open Morpho
|
|
69
|
+
* Blue position (`collateralAmount` WETH collateral, `debtAmount +
|
|
70
|
+
* debtFlashloanFee` USDC debt). The Aave position is closed.
|
|
71
|
+
*/
|
|
72
|
+
export const buildAaveToMorphoDebtMigration = ({
|
|
73
|
+
owner,
|
|
74
|
+
collateralAmount,
|
|
75
|
+
debtAmount,
|
|
76
|
+
debtFlashloanFee,
|
|
77
|
+
}: AaveToMorphoDebtMigrationInput): {
|
|
78
|
+
flow: Flow;
|
|
79
|
+
request: ComposeCompileRequest;
|
|
80
|
+
} => {
|
|
81
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL });
|
|
82
|
+
|
|
83
|
+
// Morpho borrow must equal principal + Aave-V3 flashloan fee so the
|
|
84
|
+
// `borrowed` resource exactly settles the USDC flashloan leg.
|
|
85
|
+
const morphoBorrowAmount = (
|
|
86
|
+
BigInt(debtAmount) + BigInt(debtFlashloanFee)
|
|
87
|
+
).toString() as `${bigint}`;
|
|
88
|
+
|
|
89
|
+
const builder = sdk.flow(8453, {
|
|
90
|
+
name: 'aave-to-morpho-debt-migration',
|
|
91
|
+
inputs: {
|
|
92
|
+
initialCollateral: resources.erc20(BASE_WETH, 8453),
|
|
93
|
+
debtFlashloan: resources.erc20(BASE_USDC, 8453),
|
|
94
|
+
collateralFlashloan: resources.erc20(BASE_WETH, 8453),
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// --- Phase 1: provision the Aave V3 borrow position ----------------------
|
|
99
|
+
|
|
100
|
+
// WETH → aBasWETH via the aave routing edge family (Aave V3 supply).
|
|
101
|
+
const supplyToAave = builder.lifi.zap('supply-to-aave', {
|
|
102
|
+
bind: { amountIn: builder.inputs.initialCollateral },
|
|
103
|
+
config: { resourceOut: resources.erc20(A_BAS_WETH, 8453) },
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Borrow USDC against the freshly supplied collateral. The `borrowed`
|
|
107
|
+
// resource is left unbound; request-level `sweepTo` forwards it to the
|
|
108
|
+
// signer as the user's loan proceeds.
|
|
109
|
+
builder.aave.borrow('borrow-from-aave', {
|
|
110
|
+
bind: {},
|
|
111
|
+
config: {
|
|
112
|
+
pool: AAVE_V3_POOL_BASE,
|
|
113
|
+
asset: BASE_USDC,
|
|
114
|
+
variableDebtToken: VDEBT_BAS_USDC,
|
|
115
|
+
amount: debtAmount,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// --- Phase 2: migrate to Morpho with two concurrent flashloans -----------
|
|
120
|
+
|
|
121
|
+
// Settle the Aave USDC debt with flashloan #1. mode: 'max' makes Aave's
|
|
122
|
+
// Pool clamp paybackAmount to userVariableDebt exactly, so any unspent
|
|
123
|
+
// flashloan principal flows through the op's residual port (swept by the
|
|
124
|
+
// request-level sweepTo).
|
|
125
|
+
builder.aave.repay('repay-aave', {
|
|
126
|
+
bind: {
|
|
127
|
+
assetIn: builder.inputs.debtFlashloan,
|
|
128
|
+
onBehalfOf: builder.context.executionAddress,
|
|
129
|
+
},
|
|
130
|
+
config: { pool: AAVE_V3_POOL_BASE, mode: 'max' },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Withdraw the freed WETH from Aave (aBasWETH → WETH) via routing.
|
|
134
|
+
const withdrawFromAave = builder.lifi.zap('withdraw-from-aave', {
|
|
135
|
+
bind: { amountIn: supplyToAave.amountOut },
|
|
136
|
+
config: { resourceOut: resources.erc20(BASE_WETH, 8453) },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Open the Morpho Blue position with flashloan #2's WETH.
|
|
140
|
+
builder.morphoBlue.supplyCollateral('supply-to-morpho', {
|
|
141
|
+
bind: { assetIn: builder.inputs.collateralFlashloan },
|
|
142
|
+
config: { marketParams: MORPHO_WETH_USDC_MARKET, mode: 'exact' },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Borrow exactly principal + fee from Morpho to settle the USDC leg.
|
|
146
|
+
const morphoBorrow = builder.morphoBlue.borrow('borrow-from-morpho', {
|
|
147
|
+
bind: {},
|
|
148
|
+
config: {
|
|
149
|
+
marketParams: MORPHO_WETH_USDC_MARKET,
|
|
150
|
+
amount: morphoBorrowAmount,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Settle the USDC flashloan leg with the Morpho borrow.
|
|
155
|
+
builder.lifi.flashloanRepay('repay-debt-flashloan', {
|
|
156
|
+
bind: { funds: morphoBorrow.borrowed },
|
|
157
|
+
config: { leg: 'debtFlashloan' },
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Settle the WETH flashloan leg with the Aave withdrawal. Balancer V2
|
|
161
|
+
// charges no fee, so the withdrawn principal alone covers the leg.
|
|
162
|
+
builder.lifi.flashloanRepay('repay-collateral-flashloan', {
|
|
163
|
+
bind: { funds: withdrawFromAave.amountOut },
|
|
164
|
+
config: { leg: 'collateralFlashloan' },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const flow = builder.build();
|
|
168
|
+
|
|
169
|
+
const request = sdk.request(flow, {
|
|
170
|
+
signer: owner,
|
|
171
|
+
inputs: {
|
|
172
|
+
initialCollateral: materialisers.directDeposit({
|
|
173
|
+
amount: collateralAmount,
|
|
174
|
+
}),
|
|
175
|
+
debtFlashloan: materialisers.flashloan({
|
|
176
|
+
providerKind: 'aave-v3',
|
|
177
|
+
amount: debtAmount,
|
|
178
|
+
}),
|
|
179
|
+
collateralFlashloan: materialisers.flashloan({
|
|
180
|
+
providerKind: 'balancer-v2',
|
|
181
|
+
amount: collateralAmount,
|
|
182
|
+
}),
|
|
183
|
+
},
|
|
184
|
+
// Sweep the Aave borrow proceeds (and any aave.repay residual) to the
|
|
185
|
+
// signer.
|
|
186
|
+
sweepTo: builder.context.sender,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return { flow, request };
|
|
190
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
|
+
|
|
3
|
+
import { createComposeSdk, materialisers, resources } from '../../index.js';
|
|
4
|
+
import type { Address } from '../../types.js';
|
|
5
|
+
import { BASE_URL } from '../config.js';
|
|
6
|
+
|
|
7
|
+
// Base mainnet token addresses.
|
|
8
|
+
const BASE_WETH = '0x4200000000000000000000000000000000000006';
|
|
9
|
+
const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
|
|
10
|
+
// Circle EURC on Base (6 decimals).
|
|
11
|
+
const BASE_EURC = '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42';
|
|
12
|
+
|
|
13
|
+
// Aave V3 on Base (pool + aWETH receipt + variable-debt USDC).
|
|
14
|
+
const AAVE_V3_POOL_BASE = '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5';
|
|
15
|
+
const A_BAS_WETH = '0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7';
|
|
16
|
+
const VDEBT_BAS_USDC = '0x59dca05b6c26dbd64b5381374aAaC5CD05644C28';
|
|
17
|
+
|
|
18
|
+
// Morpho Blue WETH/EURC market on Base. Real listed market — borrow APY
|
|
19
|
+
// ~1.02% at the time of writing vs ~5.30% on the WETH/USDC market, which is
|
|
20
|
+
// what makes this migration economically interesting. Market ID:
|
|
21
|
+
// 0xa9b5142fa687a24c275faf731f13b52faa9873252bb4e1cb6077aa1f412edb0b
|
|
22
|
+
// (= keccak256(MarketParams) of the values below).
|
|
23
|
+
const ADAPTIVE_CURVE_IRM_BASE = '0x46415998764C29aB2a25CbeA6254146D50D22687';
|
|
24
|
+
const WETH_EURC_ORACLE = '0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37';
|
|
25
|
+
const WETH_EURC_LLTV = '860000000000000000';
|
|
26
|
+
|
|
27
|
+
const MORPHO_WETH_EURC_MARKET = {
|
|
28
|
+
loanToken: BASE_EURC,
|
|
29
|
+
collateralToken: BASE_WETH,
|
|
30
|
+
oracle: WETH_EURC_ORACLE,
|
|
31
|
+
irm: ADAPTIVE_CURVE_IRM_BASE,
|
|
32
|
+
lltv: WETH_EURC_LLTV,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Slippage budget on the EURC → USDC swap. The caller must size
|
|
36
|
+
// `morphoBorrowAmount` such that the swap's slippage-adjusted minimum covers
|
|
37
|
+
// `debtAmount + computeDefaultFee('aave-v3', debtAmount)`.
|
|
38
|
+
const SWAP_SLIPPAGE = 0.03;
|
|
39
|
+
|
|
40
|
+
export interface AaveToMorphoDebtMigrationWithSwapInput {
|
|
41
|
+
readonly owner: Address;
|
|
42
|
+
/** WETH collateral the user posts (in smallest units, 18 decimals). */
|
|
43
|
+
readonly collateralAmount: `${bigint}`;
|
|
44
|
+
/** USDC principal borrowed from Aave (6 decimals). */
|
|
45
|
+
readonly debtAmount: `${bigint}`;
|
|
46
|
+
/**
|
|
47
|
+
* EURC to borrow from Morpho (6 decimals). Must be large enough that, after
|
|
48
|
+
* the EURC → USDC swap at `SWAP_SLIPPAGE`, the swap's minimum output covers
|
|
49
|
+
* `debtAmount + computeDefaultFee('aave-v3', debtAmount)`. Caller sizes this
|
|
50
|
+
* off-chain from a live LI.FI quote, e.g.
|
|
51
|
+
* morphoBorrowAmount =
|
|
52
|
+
* ceil((debtAmount + aaveV3Fee) * eurcPerUsdc / (1 - slippage))
|
|
53
|
+
* Note: EUR/USD is not 1:1 — the example fixture assumes ~1.075 USD/EUR.
|
|
54
|
+
*/
|
|
55
|
+
readonly morphoBorrowAmount: `${bigint}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Atomically migrate an Aave V3 USDC borrow on Base into the Morpho Blue
|
|
60
|
+
* WETH/EURC market — same WETH collateral, different stablecoin debt. At the
|
|
61
|
+
* time of writing Morpho's WETH/EURC borrow APY is ~1.02% vs ~5.30% on
|
|
62
|
+
* USDC-denominated WETH-collateral markets, so a long-running borrow position
|
|
63
|
+
* can be made materially cheaper by migrating the debt asset.
|
|
64
|
+
*
|
|
65
|
+
* Topology mirrors `aaveToMorphoDebtMigration`, with one extra step: after
|
|
66
|
+
* Morpho mints EURC debt, the borrow proceeds are swapped to USDC via
|
|
67
|
+
* `lifi.swap`, and the swap's `amountOut` (which carries the slippage-adjusted
|
|
68
|
+
* minimum) settles the USDC flashloan leg.
|
|
69
|
+
*
|
|
70
|
+
* Phase 1 — provision the source position on Aave V3:
|
|
71
|
+
* - User direct-deposits WETH.
|
|
72
|
+
* - `lifi.zap` supplies the WETH to Aave (WETH → aBasWETH routing edge).
|
|
73
|
+
* - `aave.borrow` mints USDC debt; the borrowed USDC is swept back to the
|
|
74
|
+
* signer as the user's loan proceeds.
|
|
75
|
+
*
|
|
76
|
+
* Phase 2 — migrate to Morpho using two concurrent flashloans:
|
|
77
|
+
* - Flashloan #1 (Aave V3, USDC) bridges the Aave debt payoff before the
|
|
78
|
+
* Morpho borrow + swap exists.
|
|
79
|
+
* - Flashloan #2 (Balancer V2, WETH) bridges the Morpho collateral supply
|
|
80
|
+
* before the Aave collateral is freed.
|
|
81
|
+
* - `aave.repay` clears the Aave USDC debt with flashloan #1.
|
|
82
|
+
* - `lifi.zap` withdraws the freed WETH from Aave (aBasWETH → WETH).
|
|
83
|
+
* - `morphoBlue.supplyCollateral` deposits flashloan #2's WETH into Morpho.
|
|
84
|
+
* - `morphoBlue.borrow` mints `morphoBorrowAmount` EURC.
|
|
85
|
+
* - `lifi.swap` converts the borrowed EURC into USDC. `amountOut` is the
|
|
86
|
+
* slippage-adjusted minimum that settles the USDC flashloan leg.
|
|
87
|
+
* - Two `lifi.flashloanRepay` ops settle each leg: the USDC leg from the swap
|
|
88
|
+
* output, the WETH leg from the Aave withdrawal (Balancer V2 charges no
|
|
89
|
+
* fee, so the withdrawn principal alone covers it).
|
|
90
|
+
*
|
|
91
|
+
* After execution the signer holds a Morpho Blue position with
|
|
92
|
+
* `collateralAmount` WETH collateral and `morphoBorrowAmount` EURC debt; the
|
|
93
|
+
* Aave position is closed. Any EURC dust (Morpho residual above what the swap
|
|
94
|
+
* consumed) and USDC residual from `aave.repay`'s `mode: 'max'` clamp flow
|
|
95
|
+
* back to the signer via `sweepTo`.
|
|
96
|
+
*/
|
|
97
|
+
export const buildAaveToMorphoDebtMigrationWithSwap = ({
|
|
98
|
+
owner,
|
|
99
|
+
collateralAmount,
|
|
100
|
+
debtAmount,
|
|
101
|
+
morphoBorrowAmount,
|
|
102
|
+
}: AaveToMorphoDebtMigrationWithSwapInput): {
|
|
103
|
+
flow: Flow;
|
|
104
|
+
request: ComposeCompileRequest;
|
|
105
|
+
} => {
|
|
106
|
+
const sdk = createComposeSdk({ baseUrl: BASE_URL });
|
|
107
|
+
|
|
108
|
+
const builder = sdk.flow(8453, {
|
|
109
|
+
name: 'aave-to-morpho-debt-migration-with-swap',
|
|
110
|
+
inputs: {
|
|
111
|
+
initialCollateral: resources.erc20(BASE_WETH, 8453),
|
|
112
|
+
debtFlashloan: resources.erc20(BASE_USDC, 8453),
|
|
113
|
+
collateralFlashloan: resources.erc20(BASE_WETH, 8453),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// --- Phase 1: provision the Aave V3 borrow position ----------------------
|
|
118
|
+
|
|
119
|
+
// WETH → aBasWETH via the aave routing edge family (Aave V3 supply).
|
|
120
|
+
const supplyToAave = builder.lifi.zap('supply-to-aave', {
|
|
121
|
+
bind: { amountIn: builder.inputs.initialCollateral },
|
|
122
|
+
config: { resourceOut: resources.erc20(A_BAS_WETH, 8453) },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Borrow USDC against the freshly supplied collateral. The `borrowed`
|
|
126
|
+
// resource is left unbound; request-level `sweepTo` forwards it to the
|
|
127
|
+
// signer as the user's loan proceeds.
|
|
128
|
+
builder.aave.borrow('borrow-from-aave', {
|
|
129
|
+
bind: {},
|
|
130
|
+
config: {
|
|
131
|
+
pool: AAVE_V3_POOL_BASE,
|
|
132
|
+
asset: BASE_USDC,
|
|
133
|
+
variableDebtToken: VDEBT_BAS_USDC,
|
|
134
|
+
amount: debtAmount,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// --- Phase 2: migrate to Morpho with two concurrent flashloans -----------
|
|
139
|
+
|
|
140
|
+
// Settle the Aave USDC debt with flashloan #1. mode: 'max' makes Aave's
|
|
141
|
+
// Pool clamp paybackAmount to userVariableDebt exactly, so any unspent
|
|
142
|
+
// flashloan principal flows through the op's residual port (swept by
|
|
143
|
+
// request-level sweepTo).
|
|
144
|
+
builder.aave.repay('repay-aave', {
|
|
145
|
+
bind: {
|
|
146
|
+
assetIn: builder.inputs.debtFlashloan,
|
|
147
|
+
onBehalfOf: builder.context.executionAddress,
|
|
148
|
+
},
|
|
149
|
+
config: { pool: AAVE_V3_POOL_BASE, mode: 'max' },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Withdraw the freed WETH from Aave (aBasWETH → WETH) via routing.
|
|
153
|
+
const withdrawFromAave = builder.lifi.zap('withdraw-from-aave', {
|
|
154
|
+
bind: { amountIn: supplyToAave.amountOut },
|
|
155
|
+
config: { resourceOut: resources.erc20(BASE_WETH, 8453) },
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Open the Morpho Blue position with flashloan #2's WETH.
|
|
159
|
+
builder.morphoBlue.supplyCollateral('supply-to-morpho', {
|
|
160
|
+
bind: { assetIn: builder.inputs.collateralFlashloan },
|
|
161
|
+
config: { marketParams: MORPHO_WETH_EURC_MARKET, mode: 'exact' },
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Borrow EURC at the destination's (cheaper) APR.
|
|
165
|
+
const morphoBorrow = builder.morphoBlue.borrow('borrow-from-morpho', {
|
|
166
|
+
bind: {},
|
|
167
|
+
config: {
|
|
168
|
+
marketParams: MORPHO_WETH_EURC_MARKET,
|
|
169
|
+
amount: morphoBorrowAmount,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Swap EURC → USDC so the borrow proceeds can settle the USDC flashloan
|
|
174
|
+
// leg. `amountOut` carries `providesMinimum: true`; the caller is
|
|
175
|
+
// responsible for sizing `morphoBorrowAmount` so the slippage-adjusted
|
|
176
|
+
// minimum covers `debtAmount + aaveV3Fee(debtAmount)`.
|
|
177
|
+
const swapDebt = builder.lifi.swap('swap-borrow-to-usdc', {
|
|
178
|
+
bind: { amountIn: morphoBorrow.borrowed },
|
|
179
|
+
config: {
|
|
180
|
+
resourceOut: resources.erc20(BASE_USDC, 8453),
|
|
181
|
+
slippage: SWAP_SLIPPAGE,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Settle the USDC flashloan leg with the swap output.
|
|
186
|
+
builder.lifi.flashloanRepay('repay-debt-flashloan', {
|
|
187
|
+
bind: { funds: swapDebt.amountOut },
|
|
188
|
+
config: { leg: 'debtFlashloan' },
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Settle the WETH flashloan leg with the Aave withdrawal. Balancer V2
|
|
192
|
+
// charges no fee, so the withdrawn principal alone covers the leg.
|
|
193
|
+
builder.lifi.flashloanRepay('repay-collateral-flashloan', {
|
|
194
|
+
bind: { funds: withdrawFromAave.amountOut },
|
|
195
|
+
config: { leg: 'collateralFlashloan' },
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const flow = builder.build();
|
|
199
|
+
|
|
200
|
+
const request = sdk.request(flow, {
|
|
201
|
+
signer: owner,
|
|
202
|
+
inputs: {
|
|
203
|
+
initialCollateral: materialisers.directDeposit({
|
|
204
|
+
amount: collateralAmount,
|
|
205
|
+
}),
|
|
206
|
+
debtFlashloan: materialisers.flashloan({
|
|
207
|
+
providerKind: 'aave-v3',
|
|
208
|
+
amount: debtAmount,
|
|
209
|
+
}),
|
|
210
|
+
collateralFlashloan: materialisers.flashloan({
|
|
211
|
+
providerKind: 'balancer-v2',
|
|
212
|
+
amount: collateralAmount,
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
// Sweep Aave borrow proceeds, aave.repay's residual, and any EURC / USDC
|
|
216
|
+
// dust left after the swap back to the signer.
|
|
217
|
+
sweepTo: builder.context.sender,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return { flow, request };
|
|
221
|
+
};
|