@lifi/composer-sdk 0.2.0-staging.4 → 0.2.0-staging.5
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/authoring/handles.cjs.map +1 -1
- package/dist/authoring/handles.d.cts +13 -6
- package/dist/authoring/handles.d.ts +13 -6
- package/dist/authoring/handles.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/generated/config.generated.cjs.map +1 -1
- package/dist/generated/config.generated.d.cts +39 -1
- package/dist/generated/config.generated.d.ts +39 -1
- package/dist/generated/operations.generated.cjs +55 -1
- package/dist/generated/operations.generated.cjs.map +1 -1
- package/dist/generated/operations.generated.d.cts +204 -2
- package/dist/generated/operations.generated.d.ts +204 -2
- package/dist/generated/operations.generated.js +55 -1
- package/dist/generated/operations.generated.js.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/authoring/handles.ts +19 -10
- package/src/examples/aaveRepay.ts +55 -16
- package/src/examples/aaveRepayWithATokens.ts +41 -30
- package/src/examples/aaveRounding.ts +42 -0
- package/src/examples/aaveSetEMode.ts +0 -1
- package/src/examples/config.ts +1 -1
- package/src/examples/emitCustomEvent.ts +75 -0
- package/src/examples/invariantChecks.ts +96 -0
- package/src/examples/run.ts +20 -18
- package/src/examples/staged/aaveBorrow.ts +38 -14
- package/src/examples/staged/aaveToMorphoDebtMigration.ts +13 -3
- package/src/examples/staged/aaveToMorphoDebtMigrationWithSwap.ts +12 -2
- package/src/examples/staged/aaveToMorphoDebtMigrationWithSwapExactOut.ts +5 -0
- package/src/examples/staged/flashloanRepay.ts +4 -0
- package/src/examples/staged/morphoBlueBorrow.ts +4 -0
- package/src/examples/staged/morphoBlueRepay.ts +59 -18
- package/src/examples/staged/registry.ts +7 -5
- package/src/examples/untypedOpWithTypedRef.ts +26 -20
- package/src/generated/config.generated.ts +50 -0
- package/src/generated/operations.generated.ts +330 -0
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createComposeSdk,
|
|
5
|
+
guards,
|
|
6
|
+
materialisers,
|
|
7
|
+
resources,
|
|
8
|
+
} from '../../index.js';
|
|
4
9
|
import type { Address } from '../../types.js';
|
|
5
10
|
import { BASE_URL } from '../config.js';
|
|
6
11
|
|
|
7
12
|
// Aave v3 contracts on Ethereum mainnet.
|
|
8
13
|
const AAVE_V3_POOL = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2';
|
|
9
14
|
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
|
|
15
|
+
// Aave v3 aEthUSDC receipt token and variable-debt USDC token.
|
|
16
|
+
const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';
|
|
10
17
|
const VDEBT_USDC = '0x72E95b8931767C79bA4EeE721354d6E99a61D004';
|
|
11
18
|
|
|
12
19
|
// 1.05 WAD (1e18) — minimum acceptable Aave health factor after the borrow.
|
|
@@ -16,53 +23,67 @@ const MIN_HEALTH_FACTOR_WAD = '1050000000000000000';
|
|
|
16
23
|
export interface AaveBorrowInput {
|
|
17
24
|
readonly owner: Address;
|
|
18
25
|
readonly recipient: Address;
|
|
19
|
-
|
|
26
|
+
/** USDC supplied as collateral so the proxy can borrow (6 dp). */
|
|
27
|
+
readonly collateralAmount: `${bigint}`;
|
|
28
|
+
/** USDC borrowed against the collateral and sent to the recipient (6 dp). */
|
|
29
|
+
readonly borrowAmount: `${bigint}`;
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
/**
|
|
23
|
-
*
|
|
24
|
-
* with an on-chain health-factor guard that reverts
|
|
25
|
-
* is too thin.
|
|
33
|
+
* Supply USDC to Aave v3, borrow USDC against it, and transfer the borrowed
|
|
34
|
+
* funds to a recipient — with an on-chain health-factor guard that reverts
|
|
35
|
+
* if the post-borrow position is too thin.
|
|
26
36
|
*
|
|
27
|
-
* The
|
|
28
|
-
*
|
|
29
|
-
*
|
|
37
|
+
* The in-flow supply makes the example self-contained: the borrow is backed
|
|
38
|
+
* by collateral created in the same transaction, so it simulates cleanly
|
|
39
|
+
* for a fresh proxy. Keep `borrowAmount` comfortably below the collateral's
|
|
40
|
+
* borrowing power or the health-factor guard reverts the run.
|
|
30
41
|
*
|
|
31
42
|
* Demonstrates:
|
|
43
|
+
* - `lifi.zap` to supply USDC into Aave (USDC → aEthUSDC routing edge)
|
|
32
44
|
* - `aave.borrow` with no resource input — the borrowed asset materialises
|
|
33
45
|
* as the `borrowed` resource output.
|
|
34
46
|
* - Chaining the borrow output into a `core.transfer` to forward funds.
|
|
35
|
-
* - The `debtBalance` handle reports the post-borrow variable-debt balance
|
|
36
|
-
* for the proxy.
|
|
37
47
|
* - `aave.getHealthFactor` + `core.numericInvariant` guard asserts that
|
|
38
48
|
* `healthFactor >= MIN_HEALTH_FACTOR_WAD` after the borrow; the run reverts
|
|
39
49
|
* on-chain if the threshold is violated.
|
|
50
|
+
*
|
|
51
|
+
* The supplied aEthUSDC stays on the proxy: it backs the open debt, and
|
|
52
|
+
* Aave rejects aToken transfers that would break the position's health
|
|
53
|
+
* factor, so it cannot be swept while the borrow is outstanding.
|
|
40
54
|
*/
|
|
41
55
|
export const buildAaveBorrow = ({
|
|
42
56
|
owner,
|
|
43
57
|
recipient,
|
|
44
|
-
|
|
58
|
+
collateralAmount,
|
|
59
|
+
borrowAmount,
|
|
45
60
|
}: AaveBorrowInput): {
|
|
46
61
|
flow: Flow;
|
|
47
62
|
request: ComposeCompileRequest;
|
|
48
63
|
} => {
|
|
49
64
|
const sdk = createComposeSdk({ baseUrl: BASE_URL });
|
|
50
65
|
|
|
51
|
-
// The flow takes no resource inputs — Aave hands us the borrowed asset.
|
|
52
66
|
const builder = sdk.flow(1, {
|
|
53
67
|
name: 'aave-borrow-usdc',
|
|
54
68
|
inputs: {
|
|
69
|
+
collateralIn: resources.erc20(USDC, 1),
|
|
55
70
|
recipient: 'address',
|
|
56
71
|
},
|
|
57
72
|
});
|
|
58
73
|
|
|
74
|
+
// Supply USDC as collateral (USDC → aEthUSDC) so the proxy can borrow.
|
|
75
|
+
builder.lifi.zap('supply', {
|
|
76
|
+
bind: { amountIn: builder.inputs.collateralIn },
|
|
77
|
+
config: { resourceOut: resources.erc20(A_ETH_USDC, 1) },
|
|
78
|
+
});
|
|
79
|
+
|
|
59
80
|
const borrowOut = builder.aave.borrow('borrow', {
|
|
60
81
|
bind: {},
|
|
61
82
|
config: {
|
|
62
83
|
pool: AAVE_V3_POOL,
|
|
63
84
|
asset: USDC,
|
|
64
85
|
variableDebtToken: VDEBT_USDC,
|
|
65
|
-
amount,
|
|
86
|
+
amount: borrowAmount,
|
|
66
87
|
},
|
|
67
88
|
});
|
|
68
89
|
|
|
@@ -92,12 +113,15 @@ export const buildAaveBorrow = ({
|
|
|
92
113
|
|
|
93
114
|
const flow = builder.build();
|
|
94
115
|
|
|
116
|
+
// No sweepTo: the aEthUSDC collateral must stay on the proxy while the
|
|
117
|
+
// debt is open — Aave blocks aToken transfers that would leave the
|
|
118
|
+
// position undercollateralized.
|
|
95
119
|
const request = sdk.request(flow, {
|
|
96
120
|
signer: owner,
|
|
97
121
|
inputs: {
|
|
122
|
+
collateralIn: materialisers.directDeposit({ amount: collateralAmount }),
|
|
98
123
|
recipient,
|
|
99
124
|
},
|
|
100
|
-
sweepTo: builder.context.sender,
|
|
101
125
|
});
|
|
102
126
|
|
|
103
127
|
return { flow, request };
|
|
@@ -2,6 +2,10 @@ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
|
2
2
|
|
|
3
3
|
import { createComposeSdk, materialisers, resources } from '../../index.js';
|
|
4
4
|
import type { Address } from '../../types.js';
|
|
5
|
+
import {
|
|
6
|
+
padForAaveDebtRounding,
|
|
7
|
+
trimForAaveWithdrawalRounding,
|
|
8
|
+
} from '../aaveRounding.js';
|
|
5
9
|
import { BASE_URL } from '../config.js';
|
|
6
10
|
|
|
7
11
|
// Base mainnet token addresses.
|
|
@@ -80,10 +84,16 @@ export const buildAaveToMorphoDebtMigration = ({
|
|
|
80
84
|
} => {
|
|
81
85
|
const sdk = createComposeSdk({ baseUrl: BASE_URL });
|
|
82
86
|
|
|
87
|
+
// Both flashloan legs absorb Aave's 1-wei scaled-balance skew: the USDC
|
|
88
|
+
// leg funds a max-mode repay, the WETH leg is covered by a withdrawal.
|
|
89
|
+
const debtFlashloanAmount = padForAaveDebtRounding(debtAmount);
|
|
90
|
+
const collateralFlashloanAmount =
|
|
91
|
+
trimForAaveWithdrawalRounding(collateralAmount);
|
|
92
|
+
|
|
83
93
|
// Morpho borrow must equal principal + Aave-V3 flashloan fee so the
|
|
84
94
|
// `borrowed` resource exactly settles the USDC flashloan leg.
|
|
85
95
|
const morphoBorrowAmount = (
|
|
86
|
-
BigInt(
|
|
96
|
+
BigInt(debtFlashloanAmount) + BigInt(debtFlashloanFee)
|
|
87
97
|
).toString() as `${bigint}`;
|
|
88
98
|
|
|
89
99
|
const builder = sdk.flow(8453, {
|
|
@@ -174,11 +184,11 @@ export const buildAaveToMorphoDebtMigration = ({
|
|
|
174
184
|
}),
|
|
175
185
|
debtFlashloan: materialisers.flashloan({
|
|
176
186
|
providerKind: 'aave-v3',
|
|
177
|
-
amount:
|
|
187
|
+
amount: debtFlashloanAmount,
|
|
178
188
|
}),
|
|
179
189
|
collateralFlashloan: materialisers.flashloan({
|
|
180
190
|
providerKind: 'balancer-v2',
|
|
181
|
-
amount:
|
|
191
|
+
amount: collateralFlashloanAmount,
|
|
182
192
|
}),
|
|
183
193
|
},
|
|
184
194
|
// Sweep the Aave borrow proceeds (and any aave.repay residual) to the
|
|
@@ -2,6 +2,10 @@ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
|
2
2
|
|
|
3
3
|
import { createComposeSdk, materialisers, resources } from '../../index.js';
|
|
4
4
|
import type { Address } from '../../types.js';
|
|
5
|
+
import {
|
|
6
|
+
padForAaveDebtRounding,
|
|
7
|
+
trimForAaveWithdrawalRounding,
|
|
8
|
+
} from '../aaveRounding.js';
|
|
5
9
|
import { BASE_URL } from '../config.js';
|
|
6
10
|
|
|
7
11
|
// Base mainnet token addresses.
|
|
@@ -105,6 +109,12 @@ export const buildAaveToMorphoDebtMigrationWithSwap = ({
|
|
|
105
109
|
} => {
|
|
106
110
|
const sdk = createComposeSdk({ baseUrl: BASE_URL });
|
|
107
111
|
|
|
112
|
+
// Both flashloan legs absorb Aave's 1-wei scaled-balance skew: the USDC
|
|
113
|
+
// leg funds a max-mode repay, the WETH leg is covered by a withdrawal.
|
|
114
|
+
const debtFlashloanAmount = padForAaveDebtRounding(debtAmount);
|
|
115
|
+
const collateralFlashloanAmount =
|
|
116
|
+
trimForAaveWithdrawalRounding(collateralAmount);
|
|
117
|
+
|
|
108
118
|
const builder = sdk.flow(8453, {
|
|
109
119
|
name: 'aave-to-morpho-debt-migration-with-swap',
|
|
110
120
|
inputs: {
|
|
@@ -205,11 +215,11 @@ export const buildAaveToMorphoDebtMigrationWithSwap = ({
|
|
|
205
215
|
}),
|
|
206
216
|
debtFlashloan: materialisers.flashloan({
|
|
207
217
|
providerKind: 'aave-v3',
|
|
208
|
-
amount:
|
|
218
|
+
amount: debtFlashloanAmount,
|
|
209
219
|
}),
|
|
210
220
|
collateralFlashloan: materialisers.flashloan({
|
|
211
221
|
providerKind: 'balancer-v2',
|
|
212
|
-
amount:
|
|
222
|
+
amount: collateralFlashloanAmount,
|
|
213
223
|
}),
|
|
214
224
|
},
|
|
215
225
|
// Sweep Aave borrow proceeds, aave.repay's residual, and any EURC / USDC
|
|
@@ -273,6 +273,10 @@ export const buildAaveToMorphoDebtMigrationWithSwapExactOut = ({
|
|
|
273
273
|
|
|
274
274
|
const flow = builder.build();
|
|
275
275
|
|
|
276
|
+
const assumptions: Record<string, bigint> = {
|
|
277
|
+
'buy-usdc-exact.amountIn': BigInt(morphoBorrowAmount),
|
|
278
|
+
};
|
|
279
|
+
|
|
276
280
|
const request = sdk.request(flow, {
|
|
277
281
|
signer: owner,
|
|
278
282
|
inputs: {
|
|
@@ -296,6 +300,7 @@ export const buildAaveToMorphoDebtMigrationWithSwapExactOut = ({
|
|
|
296
300
|
// Sweep Aave borrow proceeds, aave.repay's residual, and any EURC over-repay
|
|
297
301
|
// residual from the capped Morpho repay back to the signer.
|
|
298
302
|
sweepTo: builder.context.sender,
|
|
303
|
+
assumptions,
|
|
299
304
|
});
|
|
300
305
|
|
|
301
306
|
return { flow, request };
|
|
@@ -69,6 +69,10 @@ export const buildTrivialFlashloanRepay = ({
|
|
|
69
69
|
}),
|
|
70
70
|
feeTopUp: materialisers.directDeposit({ amount: fee }),
|
|
71
71
|
},
|
|
72
|
+
// The smoke flow returns the full principal + fee to the adapter and
|
|
73
|
+
// produces no user output, so the guard sees the fee top-up as 100%
|
|
74
|
+
// loss. 0 skips the check; the user's real cost is only the provider fee.
|
|
75
|
+
maxPriceImpactBps: 0,
|
|
72
76
|
});
|
|
73
77
|
|
|
74
78
|
return { flow, request };
|
|
@@ -83,6 +83,10 @@ export const buildMorphoBlueBorrow = ({
|
|
|
83
83
|
},
|
|
84
84
|
// Sweep the borrowed USDC back to the signer.
|
|
85
85
|
sweepTo: builder.context.sender,
|
|
86
|
+
// The WETH collateral becomes unpriced Morpho position state (no receipt
|
|
87
|
+
// token), so the default 500 bps price-impact check reads any safe borrow
|
|
88
|
+
// (LLTV caps at 86%) as a loss. 0 skips the check.
|
|
89
|
+
maxPriceImpactBps: 0,
|
|
86
90
|
});
|
|
87
91
|
|
|
88
92
|
return { flow, request };
|
|
@@ -21,27 +21,41 @@ const WETH_USDC_MARKET = {
|
|
|
21
21
|
|
|
22
22
|
export interface MorphoBlueRepayInput {
|
|
23
23
|
readonly owner: Address;
|
|
24
|
-
|
|
24
|
+
/** WETH supplied as collateral for the in-flow borrow (18 dp). */
|
|
25
25
|
readonly collateralAmount: `${bigint}`;
|
|
26
|
+
/** USDC borrowed against the collateral, then repaid by this flow (6 dp). */
|
|
27
|
+
readonly borrowAmount: `${bigint}`;
|
|
28
|
+
/**
|
|
29
|
+
* USDC deposited to repay the debt (6 dp). Must exceed `borrowAmount`:
|
|
30
|
+
* Morpho's share rounding can leave the debt a wei above the borrowed
|
|
31
|
+
* amount, so the `max`-mode repay needs a little headroom. The leftover
|
|
32
|
+
* surfaces on the `residual` port.
|
|
33
|
+
*/
|
|
34
|
+
readonly repayAmount: `${bigint}`;
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
/**
|
|
29
|
-
*
|
|
38
|
+
* Open and close a Morpho Blue WETH/USDC position on Base in one flow —
|
|
39
|
+
* a self-contained supplyCollateral → borrow → repay → withdrawCollateral
|
|
40
|
+
* round trip that creates the debt it retires.
|
|
30
41
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
42
|
+
* Demonstrates:
|
|
43
|
+
* - `morphoBlue.supplyCollateral` to post WETH (collateral is internal
|
|
44
|
+
* position state — no receipt token).
|
|
45
|
+
* - `morphoBlue.borrow` to mint USDC debt against it.
|
|
46
|
+
* - `morphoBlue.repay` with `mode: 'max'`, which reads the proxy's current
|
|
47
|
+
* `borrowShares` on-chain and repays in shares mode to retire the debt to
|
|
48
|
+
* the wei. Unused USDC surfaces on the `residual` Resource port.
|
|
49
|
+
* - `morphoBlue.withdrawCollateral` to pull the freed WETH once the debt
|
|
50
|
+
* is cleared.
|
|
51
|
+
* - `sweepTo` to return the borrowed USDC, the repay residual, and the
|
|
52
|
+
* freed WETH to the signer.
|
|
40
53
|
*/
|
|
41
54
|
export const buildMorphoBlueRepay = ({
|
|
42
55
|
owner,
|
|
43
|
-
repayAmount,
|
|
44
56
|
collateralAmount,
|
|
57
|
+
borrowAmount,
|
|
58
|
+
repayAmount,
|
|
45
59
|
}: MorphoBlueRepayInput): {
|
|
46
60
|
flow: Flow;
|
|
47
61
|
request: ComposeCompileRequest;
|
|
@@ -51,13 +65,38 @@ export const buildMorphoBlueRepay = ({
|
|
|
51
65
|
const builder = sdk.flow(8453, {
|
|
52
66
|
name: 'morpho-blue-repay-usdc-withdraw-weth',
|
|
53
67
|
inputs: {
|
|
54
|
-
|
|
68
|
+
collateralIn: resources.erc20(BASE_WETH, 8453),
|
|
69
|
+
repayIn: resources.erc20(BASE_USDC, 8453),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Post WETH collateral so the proxy can open the debt it will repay.
|
|
74
|
+
builder.morphoBlue.supplyCollateral('supply-collateral', {
|
|
75
|
+
bind: {
|
|
76
|
+
assetIn: builder.inputs.collateralIn,
|
|
77
|
+
},
|
|
78
|
+
config: {
|
|
79
|
+
marketParams: WETH_USDC_MARKET,
|
|
80
|
+
mode: 'exact',
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Borrow USDC against the collateral; the borrowed USDC stays on the
|
|
85
|
+
// proxy as a terminal resource and is swept back to the signer.
|
|
86
|
+
builder.morphoBlue.borrow('borrow', {
|
|
87
|
+
bind: {},
|
|
88
|
+
config: {
|
|
89
|
+
marketParams: WETH_USDC_MARKET,
|
|
90
|
+
amount: borrowAmount,
|
|
55
91
|
},
|
|
56
92
|
});
|
|
57
93
|
|
|
94
|
+
// Retire the just-opened debt from the deposited USDC. mode 'max' reads
|
|
95
|
+
// the live borrowShares and repays in shares mode, clearing the debt to
|
|
96
|
+
// the wei; the unused USDC surfaces on the `residual` port.
|
|
58
97
|
builder.morphoBlue.repay('repay', {
|
|
59
98
|
bind: {
|
|
60
|
-
assetIn: builder.inputs.
|
|
99
|
+
assetIn: builder.inputs.repayIn,
|
|
61
100
|
onBehalfOf: builder.context.executionAddress,
|
|
62
101
|
},
|
|
63
102
|
config: {
|
|
@@ -66,8 +105,8 @@ export const buildMorphoBlueRepay = ({
|
|
|
66
105
|
},
|
|
67
106
|
});
|
|
68
107
|
|
|
69
|
-
// The
|
|
70
|
-
//
|
|
108
|
+
// The debt is cleared, so the full collateral can be withdrawn. The freed
|
|
109
|
+
// WETH lands on the proxy and is swept to the signer.
|
|
71
110
|
builder.morphoBlue.withdrawCollateral('withdraw-collateral', {
|
|
72
111
|
bind: {},
|
|
73
112
|
config: {
|
|
@@ -81,9 +120,11 @@ export const buildMorphoBlueRepay = ({
|
|
|
81
120
|
const request = sdk.request(flow, {
|
|
82
121
|
signer: owner,
|
|
83
122
|
inputs: {
|
|
84
|
-
|
|
123
|
+
collateralIn: materialisers.directDeposit({ amount: collateralAmount }),
|
|
124
|
+
repayIn: materialisers.directDeposit({ amount: repayAmount }),
|
|
85
125
|
},
|
|
86
|
-
// Sweep
|
|
126
|
+
// Sweep the borrowed USDC, the repay residual, and the freed WETH back
|
|
127
|
+
// to the signer.
|
|
87
128
|
sweepTo: builder.context.sender,
|
|
88
129
|
});
|
|
89
130
|
|
|
@@ -25,7 +25,8 @@ export const STAGED_EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
25
25
|
buildAaveBorrow({
|
|
26
26
|
owner: OWNER,
|
|
27
27
|
recipient: RECIPIENT,
|
|
28
|
-
|
|
28
|
+
collateralAmount: '1000000000',
|
|
29
|
+
borrowAmount: '500000000',
|
|
29
30
|
}).request,
|
|
30
31
|
'aave-hf-explode': () =>
|
|
31
32
|
buildAaveHealthFactorExplode({ signer: OWNER }).request,
|
|
@@ -33,13 +34,14 @@ export const STAGED_EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
33
34
|
buildMorphoBlueBorrow({
|
|
34
35
|
owner: OWNER,
|
|
35
36
|
collateralAmount: '1000000000000000000',
|
|
36
|
-
borrowAmount: '
|
|
37
|
+
borrowAmount: '1200000000',
|
|
37
38
|
}).request,
|
|
38
39
|
'morpho-repay': () =>
|
|
39
40
|
buildMorphoBlueRepay({
|
|
40
41
|
owner: OWNER,
|
|
41
|
-
repayAmount: '1505000000',
|
|
42
42
|
collateralAmount: '1000000000000000000',
|
|
43
|
+
borrowAmount: '500000000',
|
|
44
|
+
repayAmount: '501000000',
|
|
43
45
|
}).request,
|
|
44
46
|
'debt-rebalance': () =>
|
|
45
47
|
buildAaveDebtRebalanceExactOut({
|
|
@@ -52,8 +54,8 @@ export const STAGED_EXAMPLES: Record<string, () => ComposeCompileRequest> = {
|
|
|
52
54
|
buildAaveToMorphoDebtMigrationWithSwapExactOut({
|
|
53
55
|
owner: OWNER,
|
|
54
56
|
collateralAmount: '1000000000000000000',
|
|
55
|
-
debtAmount: '
|
|
56
|
-
morphoBorrowAmount: '
|
|
57
|
+
debtAmount: '1000000000',
|
|
58
|
+
morphoBorrowAmount: '975000000',
|
|
57
59
|
}).request,
|
|
58
60
|
'flashloan-repay': () =>
|
|
59
61
|
buildTrivialFlashloanRepay({
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
|
|
2
2
|
|
|
3
|
-
import { createComposeSdk,
|
|
3
|
+
import { createComposeSdk, raw } from '../index.js';
|
|
4
4
|
import type { Address } from '../types.js';
|
|
5
5
|
|
|
6
6
|
import { BASE_URL } from './config.js';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
const
|
|
8
|
+
// Real ERC-4626 vault (Steakhouse USDC on Ethereum mainnet) queried through
|
|
9
|
+
// the untyped escape hatch.
|
|
10
|
+
const VAULT = '0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB';
|
|
11
11
|
|
|
12
12
|
export interface UntypedOpWithTypedRefInput {
|
|
13
13
|
readonly owner: Address;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Insert an untyped operation node
|
|
18
|
-
*
|
|
17
|
+
* Insert an untyped operation node, then feed its output into typed builder
|
|
18
|
+
* methods using `raw.ref<T>()`.
|
|
19
|
+
*
|
|
20
|
+
* `untypedOp` is the escape hatch for ops the installed SDK's typed surface
|
|
21
|
+
* doesn't cover — typically backend ops newer than your SDK version. The op
|
|
22
|
+
* id is passed as a plain string and its bind/config shapes are not
|
|
23
|
+
* type-checked, so the backend validates them at compile time instead.
|
|
24
|
+
*
|
|
25
|
+
* This example routes a real op (`core.staticCall`) through the untyped path
|
|
26
|
+
* so the flow compiles end-to-end; the mechanism is identical for any op id.
|
|
19
27
|
*
|
|
20
28
|
* Demonstrates:
|
|
21
|
-
* - `builder.untypedOp()` to add a node the typed API doesn't cover
|
|
22
|
-
* (e.g. a custom vault query).
|
|
29
|
+
* - `builder.untypedOp()` to add a node the typed API doesn't cover.
|
|
23
30
|
* - `raw.ref<'uint256'>()` to reference the untyped node's output in a typed
|
|
24
31
|
* `Bindable<'uint256'>` slot — the explicit type parameter is required
|
|
25
32
|
* so the compiler verifies the ref is used in a compatible slot.
|
|
@@ -35,16 +42,17 @@ export const buildUntypedOpWithTypedRef = ({
|
|
|
35
42
|
|
|
36
43
|
const builder = sdk.flow(1, {
|
|
37
44
|
name: 'untyped-op-with-typed-ref',
|
|
38
|
-
inputs: {
|
|
39
|
-
amountIn: resources.erc20(USDC, 1),
|
|
40
|
-
},
|
|
45
|
+
inputs: {},
|
|
41
46
|
});
|
|
42
47
|
|
|
43
|
-
// Insert an untyped node
|
|
48
|
+
// Insert an untyped node querying the vault. untypedOp returns void —
|
|
44
49
|
// the typed builder has no knowledge of this node's outputs.
|
|
45
|
-
builder.untypedOp('vault-query', '
|
|
46
|
-
bind: {
|
|
47
|
-
config: {
|
|
50
|
+
builder.untypedOp('vault-query', 'core.staticCall', {
|
|
51
|
+
bind: {},
|
|
52
|
+
config: {
|
|
53
|
+
target: VAULT,
|
|
54
|
+
functionSignature: 'function totalAssets() view returns (uint256)',
|
|
55
|
+
},
|
|
48
56
|
});
|
|
49
57
|
|
|
50
58
|
// Use raw.ref to bridge the untyped node's output into a typed operation.
|
|
@@ -60,17 +68,15 @@ export const buildUntypedOpWithTypedRef = ({
|
|
|
60
68
|
|
|
61
69
|
// Continue with fully typed operations downstream.
|
|
62
70
|
builder.core.assertGte('check-min', {
|
|
63
|
-
bind: { a: scaled.result, b:
|
|
71
|
+
bind: { a: scaled.result, b: vaultResult },
|
|
64
72
|
});
|
|
65
73
|
|
|
66
74
|
const flow = builder.build();
|
|
67
75
|
|
|
76
|
+
// No sweepTo: the flow reads state and asserts — it produces no resources.
|
|
68
77
|
const request = sdk.request(flow, {
|
|
69
78
|
signer: owner,
|
|
70
|
-
inputs: {
|
|
71
|
-
amountIn: materialisers.directDeposit({ amount: '1000000' }),
|
|
72
|
-
},
|
|
73
|
-
sweepTo: builder.context.sender,
|
|
79
|
+
inputs: {},
|
|
74
80
|
});
|
|
75
81
|
|
|
76
82
|
return { flow, request };
|
|
@@ -55,6 +55,40 @@ export interface LifiSwapConfig {
|
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
export interface InvariantNumericConfig {
|
|
59
|
+
op: 'gte' | 'gt' | 'lte' | 'lt' | 'eq' | 'neq';
|
|
60
|
+
threshold: IntegerStringInput;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface InvariantNumericInRangeConfig {
|
|
64
|
+
min: IntegerStringInput;
|
|
65
|
+
max: IntegerStringInput;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface InvariantGteConfig {
|
|
69
|
+
threshold: IntegerStringInput;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface InvariantGtConfig {
|
|
73
|
+
threshold: IntegerStringInput;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface InvariantLteConfig {
|
|
77
|
+
threshold: IntegerStringInput;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface InvariantLtConfig {
|
|
81
|
+
threshold: IntegerStringInput;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface InvariantEqConfig {
|
|
85
|
+
threshold: IntegerStringInput;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface InvariantNeqConfig {
|
|
89
|
+
threshold: IntegerStringInput;
|
|
90
|
+
}
|
|
91
|
+
|
|
58
92
|
export interface CoreBpsDownConfig {
|
|
59
93
|
bps: number;
|
|
60
94
|
}
|
|
@@ -76,6 +110,22 @@ export interface CoreTransferConfig {
|
|
|
76
110
|
amount?: IntegerStringInput;
|
|
77
111
|
}
|
|
78
112
|
|
|
113
|
+
export interface CoreEmitEvent1Config {
|
|
114
|
+
signature: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface CoreEmitEvent2Config {
|
|
118
|
+
signature: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface CoreEmitEvent3Config {
|
|
122
|
+
signature: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface CoreEmitEvent4Config {
|
|
126
|
+
signature: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
79
129
|
export interface CoreCallConfig {
|
|
80
130
|
target: Address;
|
|
81
131
|
functionSignature: string;
|