@lifi/composer-sdk 0.7.0 → 0.8.1

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.
Files changed (41) hide show
  1. package/README.md +6 -0
  2. package/dist/authoring/FlowBuilderCore.cjs +1 -1
  3. package/dist/authoring/FlowBuilderCore.cjs.map +1 -1
  4. package/dist/authoring/FlowBuilderCore.js +1 -1
  5. package/dist/authoring/FlowBuilderCore.js.map +1 -1
  6. package/dist/client.cjs +1 -1
  7. package/dist/client.js +1 -1
  8. package/dist/generated/config.generated.cjs.map +1 -1
  9. package/dist/generated/config.generated.d.cts +77 -35
  10. package/dist/generated/config.generated.d.ts +77 -35
  11. package/dist/generated/guards.generated.cjs +6 -0
  12. package/dist/generated/guards.generated.cjs.map +1 -1
  13. package/dist/generated/guards.generated.d.cts +1 -1
  14. package/dist/generated/guards.generated.d.ts +1 -1
  15. package/dist/generated/guards.generated.js +5 -0
  16. package/dist/generated/guards.generated.js.map +1 -1
  17. package/dist/generated/operations.generated.cjs +56 -1
  18. package/dist/generated/operations.generated.cjs.map +1 -1
  19. package/dist/generated/operations.generated.d.cts +155 -2
  20. package/dist/generated/operations.generated.d.ts +155 -2
  21. package/dist/generated/operations.generated.js +56 -1
  22. package/dist/generated/operations.generated.js.map +1 -1
  23. package/dist/{guards.generated-M3VAIevI.d.cts → guards.generated-CDCgYGZo.d.cts} +8 -3
  24. package/dist/{guards.generated-BPLFwe7y.d.ts → guards.generated-CdYcs4h0.d.ts} +8 -3
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +3 -3
  27. package/dist/index.d.ts +3 -3
  28. package/dist/index.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/authoring/FlowBuilderCore.ts +4 -1
  31. package/src/examples/aaveBorrow.ts +129 -0
  32. package/src/examples/aaveHealthFactorExplode.ts +63 -0
  33. package/src/examples/morphoBlueBorrow.ts +94 -0
  34. package/src/examples/morphoBlueRepay.ts +133 -0
  35. package/src/examples/run.ts +43 -0
  36. package/src/examples/uniswapV2AddLiquidity.ts +106 -0
  37. package/src/examples/uniswapV3Mint.ts +95 -0
  38. package/src/generated/config.generated.ts +82 -38
  39. package/src/generated/guards.generated.ts +9 -0
  40. package/src/generated/operations.generated.ts +292 -0
  41. package/src/index.ts +0 -3
@@ -0,0 +1,129 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import {
4
+ createComposeSdk,
5
+ guards,
6
+ materialisers,
7
+ resources,
8
+ } from '../index.js';
9
+ import type { Address } from '../types.js';
10
+
11
+ import { API_KEY, BASE_URL } from './config.js';
12
+
13
+ // Aave v3 contracts on Ethereum mainnet.
14
+ const AAVE_V3_POOL = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2';
15
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
16
+ // Aave v3 aEthUSDC receipt token and variable-debt USDC token.
17
+ const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';
18
+ const VDEBT_USDC = '0x72E95b8931767C79bA4EeE721354d6E99a61D004';
19
+
20
+ // 1.05 WAD (1e18) — minimum acceptable Aave health factor after the borrow.
21
+ // The on-chain VM reverts the run if the post-borrow HF drops below this.
22
+ const MIN_HEALTH_FACTOR_WAD = '1050000000000000000';
23
+
24
+ export interface AaveBorrowInput {
25
+ readonly owner: Address;
26
+ readonly recipient: Address;
27
+ /** USDC supplied as collateral so the proxy can borrow (6 dp). */
28
+ readonly collateralAmount: `${bigint}`;
29
+ /** USDC borrowed against the collateral and sent to the recipient (6 dp). */
30
+ readonly borrowAmount: `${bigint}`;
31
+ }
32
+
33
+ /**
34
+ * Supply USDC to Aave v3, borrow USDC against it, and transfer the borrowed
35
+ * funds to a recipient — with an on-chain health-factor guard that reverts
36
+ * if the post-borrow position is too thin.
37
+ *
38
+ * The in-flow supply makes the example self-contained: the borrow is backed
39
+ * by collateral created in the same transaction, so it simulates cleanly
40
+ * for a fresh proxy. Keep `borrowAmount` comfortably below the collateral's
41
+ * borrowing power or the health-factor guard reverts the run.
42
+ *
43
+ * Demonstrates:
44
+ * - `lifi.zap` to supply USDC into Aave (USDC → aEthUSDC routing edge)
45
+ * - `aave.borrow` with no resource input — the borrowed asset materialises
46
+ * as the `borrowed` resource output.
47
+ * - Chaining the borrow output into a `core.transfer` to forward funds.
48
+ * - `aave.getHealthFactor` + `core.numericInvariant` guard asserts that
49
+ * `healthFactor >= MIN_HEALTH_FACTOR_WAD` after the borrow; the run reverts
50
+ * on-chain if the threshold is violated.
51
+ *
52
+ * The supplied aEthUSDC stays on the proxy: it backs the open debt, and
53
+ * Aave rejects aToken transfers that would break the position's health
54
+ * factor, so it cannot be swept while the borrow is outstanding.
55
+ */
56
+ export const buildAaveBorrow = ({
57
+ owner,
58
+ recipient,
59
+ collateralAmount,
60
+ borrowAmount,
61
+ }: AaveBorrowInput): {
62
+ flow: Flow;
63
+ request: ComposeCompileRequest;
64
+ } => {
65
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
66
+
67
+ const builder = sdk.flow(1, {
68
+ name: 'aave-borrow-usdc',
69
+ inputs: {
70
+ collateralIn: resources.erc20(USDC, 1),
71
+ recipient: 'address',
72
+ },
73
+ });
74
+
75
+ // Supply USDC as collateral (USDC → aEthUSDC) so the proxy can borrow.
76
+ builder.lifi.zap('supply', {
77
+ bind: { amountIn: builder.inputs.collateralIn },
78
+ config: { resourceOut: resources.erc20(A_ETH_USDC, 1) },
79
+ });
80
+
81
+ const borrowOut = builder.aave.borrow('borrow', {
82
+ bind: {},
83
+ config: {
84
+ pool: AAVE_V3_POOL,
85
+ asset: USDC,
86
+ variableDebtToken: VDEBT_USDC,
87
+ amount: borrowAmount,
88
+ },
89
+ });
90
+
91
+ // Read the post-borrow Aave health factor and assert it stays above the
92
+ // minimum threshold. The numericInvariant guard lowers to an on-chain
93
+ // `AssertRawInvariant` IR1 instruction; the run reverts if HF < threshold.
94
+ builder.aave.getHealthFactor('hf', {
95
+ bind: {},
96
+ config: { pool: AAVE_V3_POOL },
97
+ guards: [
98
+ guards.coreNumericInvariant({
99
+ port: 'healthFactor',
100
+ op: 'gte',
101
+ threshold: MIN_HEALTH_FACTOR_WAD,
102
+ }),
103
+ ],
104
+ });
105
+
106
+ // Forward the freshly borrowed USDC to the recipient.
107
+ builder.core.transfer('send-borrowed', {
108
+ bind: {
109
+ amount: borrowOut.borrowed,
110
+ recipient: builder.inputs.recipient,
111
+ },
112
+ config: {},
113
+ });
114
+
115
+ const flow = builder.build();
116
+
117
+ // No sweepTo: the aEthUSDC collateral must stay on the proxy while the
118
+ // debt is open — Aave blocks aToken transfers that would leave the
119
+ // position undercollateralized.
120
+ const request = sdk.request(flow, {
121
+ signer: owner,
122
+ inputs: {
123
+ collateralIn: materialisers.directDeposit({ amount: collateralAmount }),
124
+ recipient,
125
+ },
126
+ });
127
+
128
+ return { flow, request };
129
+ };
@@ -0,0 +1,63 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import { createComposeSdk, guards } from '../index.js';
4
+ import type { Address } from '../types.js';
5
+
6
+ import { API_KEY, BASE_URL } from './config.js';
7
+
8
+ // Base mainnet Aave v3 Pool.
9
+ const AAVE_V3_POOL = '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5';
10
+
11
+ // 1.0 WAD (1e18) — minimum acceptable health factor.
12
+ const MIN_HEALTH_FACTOR_WAD = '1000000000000000000';
13
+
14
+ export interface AaveHealthFactorExplodeInput {
15
+ readonly signer: Address;
16
+ }
17
+
18
+ /**
19
+ * EXPLODE / DecomposeValue showcase.
20
+ *
21
+ * Builds a minimal compose flow that:
22
+ * - StaticCalls `IPool.getUserAccountData(user)` on Aave v3 (Base)
23
+ * - Decomposes the returned 6-tuple via the EXPLODE opcode
24
+ * - Asserts `healthFactor >= 1.0 WAD` via `core.numericInvariant`
25
+ *
26
+ * The signer must hold an Aave v3 position on the target chain so HF > 0.
27
+ * Uses `allow-revert` so the compiled calldata is returned even if the
28
+ * assertion would fail — handy for tracing on a fork.
29
+ */
30
+ export const buildAaveHealthFactorExplode = ({
31
+ signer,
32
+ }: AaveHealthFactorExplodeInput): {
33
+ flow: Flow;
34
+ request: ComposeCompileRequest;
35
+ } => {
36
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
37
+
38
+ const builder = sdk.flow(8453 /* Base */, {
39
+ name: 'aave-hf-explode-showcase',
40
+ inputs: {},
41
+ });
42
+
43
+ builder.aave.getHealthFactor('checkHf', {
44
+ bind: {},
45
+ config: { pool: AAVE_V3_POOL, user: signer },
46
+ guards: [
47
+ guards.coreNumericInvariant({
48
+ port: 'healthFactor',
49
+ op: 'gte',
50
+ threshold: MIN_HEALTH_FACTOR_WAD,
51
+ }),
52
+ ],
53
+ });
54
+
55
+ const flow = builder.build();
56
+ const request = sdk.request(flow, {
57
+ signer,
58
+ inputs: {},
59
+ simulationPolicy: 'allow-revert',
60
+ });
61
+
62
+ return { flow, request };
63
+ };
@@ -0,0 +1,94 @@
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
+
6
+ import { API_KEY, BASE_URL } from './config.js';
7
+
8
+ // Morpho Blue WETH/USDC market on Base (chainId 8453).
9
+ // The Morpho singleton address (0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb)
10
+ // is the default `morpho` config field and is read from compose-builtins.
11
+ const ADAPTIVE_CURVE_IRM_BASE = '0x46415998764C29aB2a25CbeA6254146D50D22687';
12
+ const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
13
+ const BASE_WETH = '0x4200000000000000000000000000000000000006';
14
+ const WETH_USDC_ORACLE = '0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4';
15
+ const WETH_USDC_LLTV = '860000000000000000'; // 0.86e18
16
+
17
+ const WETH_USDC_MARKET = {
18
+ loanToken: BASE_USDC,
19
+ collateralToken: BASE_WETH,
20
+ oracle: WETH_USDC_ORACLE,
21
+ irm: ADAPTIVE_CURVE_IRM_BASE,
22
+ lltv: WETH_USDC_LLTV,
23
+ };
24
+
25
+ export interface MorphoBlueBorrowInput {
26
+ readonly owner: Address;
27
+ readonly collateralAmount: `${bigint}`;
28
+ readonly borrowAmount: `${bigint}`;
29
+ }
30
+
31
+ /**
32
+ * Open a leveraged-borrow position on the Base Morpho Blue WETH/USDC market.
33
+ *
34
+ * - `morphoBlue.supplyCollateral` debits the proxy's WETH and credits
35
+ * `Morpho.position(WETH_USDC_MARKET_ID, proxy).collateral`. There is no
36
+ * receipt token — collateral is non-transferable accounting state.
37
+ * - `morphoBlue.borrow` mints debt shares against that collateral and
38
+ * transfers USDC to the proxy. The borrowed asset is exposed as the
39
+ * `borrowed` Resource port for downstream nodes.
40
+ * - The flow sweeps the borrowed USDC back to the signer's wallet via
41
+ * `sweepTo` on the request.
42
+ */
43
+ export const buildMorphoBlueBorrow = ({
44
+ owner,
45
+ collateralAmount,
46
+ borrowAmount,
47
+ }: MorphoBlueBorrowInput): {
48
+ flow: Flow;
49
+ request: ComposeCompileRequest;
50
+ } => {
51
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
52
+
53
+ const builder = sdk.flow(8453, {
54
+ name: 'morpho-blue-borrow-weth-usdc',
55
+ inputs: {
56
+ assetIn: resources.erc20(BASE_WETH, 8453),
57
+ },
58
+ });
59
+
60
+ builder.morphoBlue.supplyCollateral('supply-collateral', {
61
+ bind: {
62
+ assetIn: builder.inputs.assetIn,
63
+ },
64
+ config: {
65
+ marketParams: WETH_USDC_MARKET,
66
+ mode: 'exact',
67
+ },
68
+ });
69
+
70
+ builder.morphoBlue.borrow('borrow', {
71
+ bind: {},
72
+ config: {
73
+ marketParams: WETH_USDC_MARKET,
74
+ amount: borrowAmount,
75
+ },
76
+ });
77
+
78
+ const flow = builder.build();
79
+
80
+ const request = sdk.request(flow, {
81
+ signer: owner,
82
+ inputs: {
83
+ assetIn: materialisers.directDeposit({ amount: collateralAmount }),
84
+ },
85
+ // Sweep the borrowed USDC back to the signer.
86
+ sweepTo: builder.context.sender,
87
+ // The WETH collateral becomes unpriced Morpho position state (no receipt
88
+ // token), so the default 500 bps price-impact check reads any safe borrow
89
+ // (LLTV caps at 86%) as a loss. 0 skips the check.
90
+ maxPriceImpactBps: 0,
91
+ });
92
+
93
+ return { flow, request };
94
+ };
@@ -0,0 +1,133 @@
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
+
6
+ import { API_KEY, BASE_URL } from './config.js';
7
+
8
+ // Morpho Blue WETH/USDC market on Base (chainId 8453).
9
+ const ADAPTIVE_CURVE_IRM_BASE = '0x46415998764C29aB2a25CbeA6254146D50D22687';
10
+ const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
11
+ const BASE_WETH = '0x4200000000000000000000000000000000000006';
12
+ const WETH_USDC_ORACLE = '0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4';
13
+ const WETH_USDC_LLTV = '860000000000000000';
14
+
15
+ const WETH_USDC_MARKET = {
16
+ loanToken: BASE_USDC,
17
+ collateralToken: BASE_WETH,
18
+ oracle: WETH_USDC_ORACLE,
19
+ irm: ADAPTIVE_CURVE_IRM_BASE,
20
+ lltv: WETH_USDC_LLTV,
21
+ };
22
+
23
+ export interface MorphoBlueRepayInput {
24
+ readonly owner: Address;
25
+ /** WETH supplied as collateral for the in-flow borrow (18 dp). */
26
+ readonly collateralAmount: `${bigint}`;
27
+ /** USDC borrowed against the collateral, then repaid by this flow (6 dp). */
28
+ readonly borrowAmount: `${bigint}`;
29
+ /**
30
+ * USDC deposited to repay the debt (6 dp). Must exceed `borrowAmount`:
31
+ * Morpho's share rounding can leave the debt a wei above the borrowed
32
+ * amount, so the `max`-mode repay needs a little headroom. The leftover
33
+ * surfaces on the `residual` port.
34
+ */
35
+ readonly repayAmount: `${bigint}`;
36
+ }
37
+
38
+ /**
39
+ * Open and close a Morpho Blue WETH/USDC position on Base in one flow —
40
+ * a self-contained supplyCollateral → borrow → repay → withdrawCollateral
41
+ * round trip that creates the debt it retires.
42
+ *
43
+ * Demonstrates:
44
+ * - `morphoBlue.supplyCollateral` to post WETH (collateral is internal
45
+ * position state — no receipt token).
46
+ * - `morphoBlue.borrow` to mint USDC debt against it.
47
+ * - `morphoBlue.repay` with `mode: 'max'`, which reads the proxy's current
48
+ * `borrowShares` on-chain and repays in shares mode to retire the debt to
49
+ * the wei. Unused USDC surfaces on the `residual` Resource port.
50
+ * - `morphoBlue.withdrawCollateral` to pull the freed WETH once the debt
51
+ * is cleared.
52
+ * - `sweepTo` to return the borrowed USDC, the repay residual, and the
53
+ * freed WETH to the signer.
54
+ */
55
+ export const buildMorphoBlueRepay = ({
56
+ owner,
57
+ collateralAmount,
58
+ borrowAmount,
59
+ repayAmount,
60
+ }: MorphoBlueRepayInput): {
61
+ flow: Flow;
62
+ request: ComposeCompileRequest;
63
+ } => {
64
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
65
+
66
+ const builder = sdk.flow(8453, {
67
+ name: 'morpho-blue-repay-usdc-withdraw-weth',
68
+ inputs: {
69
+ collateralIn: resources.erc20(BASE_WETH, 8453),
70
+ repayIn: resources.erc20(BASE_USDC, 8453),
71
+ },
72
+ });
73
+
74
+ // Post WETH collateral so the proxy can open the debt it will repay.
75
+ builder.morphoBlue.supplyCollateral('supply-collateral', {
76
+ bind: {
77
+ assetIn: builder.inputs.collateralIn,
78
+ },
79
+ config: {
80
+ marketParams: WETH_USDC_MARKET,
81
+ mode: 'exact',
82
+ },
83
+ });
84
+
85
+ // Borrow USDC against the collateral; the borrowed USDC stays on the
86
+ // proxy as a terminal resource and is swept back to the signer.
87
+ builder.morphoBlue.borrow('borrow', {
88
+ bind: {},
89
+ config: {
90
+ marketParams: WETH_USDC_MARKET,
91
+ amount: borrowAmount,
92
+ },
93
+ });
94
+
95
+ // Retire the just-opened debt from the deposited USDC. mode 'max' reads
96
+ // the live borrowShares and repays in shares mode, clearing the debt to
97
+ // the wei; the unused USDC surfaces on the `residual` port.
98
+ builder.morphoBlue.repay('repay', {
99
+ bind: {
100
+ assetIn: builder.inputs.repayIn,
101
+ onBehalfOf: builder.context.executionAddress,
102
+ },
103
+ config: {
104
+ marketParams: WETH_USDC_MARKET,
105
+ mode: 'max',
106
+ },
107
+ });
108
+
109
+ // The debt is cleared, so the full collateral can be withdrawn. The freed
110
+ // WETH lands on the proxy and is swept to the signer.
111
+ builder.morphoBlue.withdrawCollateral('withdraw-collateral', {
112
+ bind: {},
113
+ config: {
114
+ marketParams: WETH_USDC_MARKET,
115
+ amount: collateralAmount,
116
+ },
117
+ });
118
+
119
+ const flow = builder.build();
120
+
121
+ const request = sdk.request(flow, {
122
+ signer: owner,
123
+ inputs: {
124
+ collateralIn: materialisers.directDeposit({ amount: collateralAmount }),
125
+ repayIn: materialisers.directDeposit({ amount: repayAmount }),
126
+ },
127
+ // Sweep the borrowed USDC, the repay residual, and the freed WETH back
128
+ // to the signer.
129
+ sweepTo: builder.context.sender,
130
+ });
131
+
132
+ return { flow, request };
133
+ };
@@ -8,6 +8,8 @@
8
8
  * LIFI_API_KEY=your-key COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>
9
9
  *
10
10
  * Available examples:
11
+ * aave-borrow — supply USDC to Aave v3, borrow against it with a health-factor guard
12
+ * aave-hf-explode — read the Aave v3 health factor and assert it stays >= 1.0
11
13
  * aave-repay — repay an Aave v3 WETH debt by supplying WETH
12
14
  * aave-repay-atoken — repay an Aave v3 USDC debt by burning proxy aTokens
13
15
  * aave-emode — switch the proxy's Aave v3 eMode category
@@ -21,6 +23,8 @@
21
23
  * split-arithmetic — split USDC 70/30 with arithmetic assertions
22
24
  * zap — zap USDC into Aave lending position
23
25
  * zap-async — zap USDC into an async Aave position (future output)
26
+ * morpho-borrow — supply WETH collateral to Morpho Blue and borrow USDC
27
+ * morpho-repay — open, repay and close a Morpho Blue WETH/USDC position
24
28
  * fly-swap — exit a Pendle PT position and swap ALL proceeds to WETH
25
29
  * swap-zap — swap WETH to USDC then zap into Aave
26
30
  * swap-check — swap WETH to USDC with balance check
@@ -34,6 +38,8 @@
34
38
  * transfer — transfer full token balance to a recipient
35
39
  * partial-transfer — transfer a specific amount, keeping the remainder
36
40
  * untyped-ref — mix untypedOp with typed handles via raw.ref
41
+ * uniswap-v2-add — split USDC, swap half to WETH, add both to the Uniswap V2 pair
42
+ * uniswap-v3-mint — open a full-range Uniswap V3 USDC/WETH position
37
43
  * route-exact — wrap 0.1 native ETH into WETH via /compose/route
38
44
  * route-all — unwrap the whole WETH balance to ETH via /compose/route
39
45
  * supported-chains — list the chains this deployment supports, and guard on them
@@ -46,6 +52,8 @@ import type {
46
52
  import { bigintReplacer } from '../client.js';
47
53
  import { type ComposeSdk, createComposeSdk } from '../sdk.js';
48
54
 
55
+ import { buildAaveBorrow } from './aaveBorrow.js';
56
+ import { buildAaveHealthFactorExplode } from './aaveHealthFactorExplode.js';
49
57
  import { buildAaveRepay } from './aaveRepay.js';
50
58
  import { buildAaveRepayWithATokens } from './aaveRepayWithATokens.js';
51
59
  import { buildAaveSetEMode } from './aaveSetEMode.js';
@@ -60,6 +68,8 @@ import { buildFlySwapExample } from './flySwap.js';
60
68
  import { buildLifiSwapExample } from './lifiSwap.js';
61
69
  import { buildLifiZapExample } from './lifiZap.js';
62
70
  import { buildLifiZapAsyncExample } from './lifiZapAsync.js';
71
+ import { buildMorphoBlueBorrow } from './morphoBlueBorrow.js';
72
+ import { buildMorphoBlueRepay } from './morphoBlueRepay.js';
63
73
  import { buildRawCallWithArithmetic } from './rawCallWithArithmetic.js';
64
74
  import { buildReadContractState } from './readContractState.js';
65
75
  import {
@@ -75,12 +85,23 @@ import { buildSwapWithAllowRevertExample } from './swapWithAllowRevert.js';
75
85
  import { buildSwapWithBalanceCheck } from './swapWithBalanceCheck.js';
76
86
  import { buildSwapWithOutputValidation } from './swapWithOutputValidation.js';
77
87
  import { buildPartialTransfer, buildTransferTokens } from './transferTokens.js';
88
+ import { buildUniswapV2AddLiquidity } from './uniswapV2AddLiquidity.js';
89
+ import { buildUniswapV3Mint } from './uniswapV3Mint.js';
78
90
  import { buildUntypedOpWithTypedRef } from './untypedOpWithTypedRef.js';
79
91
 
80
92
  const stringifyJson = (value: unknown) =>
81
93
  JSON.stringify(value, bigintReplacer, 2);
82
94
 
83
95
  const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
96
+ 'aave-borrow': () =>
97
+ buildAaveBorrow({
98
+ owner: OWNER,
99
+ recipient: RECIPIENT,
100
+ collateralAmount: '1000000000',
101
+ borrowAmount: '500000000',
102
+ }).request,
103
+ 'aave-hf-explode': () =>
104
+ buildAaveHealthFactorExplode({ signer: OWNER }).request,
84
105
  'aave-repay': () =>
85
106
  buildAaveRepay({
86
107
  owner: OWNER,
@@ -128,6 +149,19 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
128
149
  'zap-async': () =>
129
150
  buildLifiZapAsyncExample({ owner: OWNER, recipient: RECIPIENT }).request,
130
151
  'fly-swap': () => buildFlySwapExample().request,
152
+ 'morpho-borrow': () =>
153
+ buildMorphoBlueBorrow({
154
+ owner: OWNER,
155
+ collateralAmount: '1000000000000000000',
156
+ borrowAmount: '1200000000',
157
+ }).request,
158
+ 'morpho-repay': () =>
159
+ buildMorphoBlueRepay({
160
+ owner: OWNER,
161
+ collateralAmount: '1000000000000000000',
162
+ borrowAmount: '500000000',
163
+ repayAmount: '501000000',
164
+ }).request,
131
165
  'swap-zap': () => buildSwapAndZapExample().request,
132
166
  'swap-check': () =>
133
167
  buildSwapWithBalanceCheck({ owner: OWNER, amount: '1000000000000000000' })
@@ -166,6 +200,15 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
166
200
  amount: '1000000000',
167
201
  }).request,
168
202
  'untyped-ref': () => buildUntypedOpWithTypedRef({ owner: OWNER }).request,
203
+ 'uniswap-v2-add': () =>
204
+ buildUniswapV2AddLiquidity({ owner: OWNER, usdcAmount: '1000000000' })
205
+ .request,
206
+ 'uniswap-v3-mint': () =>
207
+ buildUniswapV3Mint({
208
+ owner: OWNER,
209
+ usdcAmount: '1000000000',
210
+ wethAmount: '400000000000000000',
211
+ }).request,
169
212
  };
170
213
 
171
214
  // `/compose/route` examples build a `ComposeRouteRequest` and go to
@@ -0,0 +1,106 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import {
4
+ createComposeSdk,
5
+ guards,
6
+ materialisers,
7
+ resources,
8
+ } from '../index.js';
9
+ import type { Address } from '../types.js';
10
+
11
+ import { API_KEY, BASE_URL } from './config.js';
12
+
13
+ // Ethereum mainnet (chainId 1).
14
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
15
+ const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
16
+ const UNISWAP_V2_ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';
17
+ const UNISWAP_V2_FACTORY = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f';
18
+ const USDC_WETH_PAIR = '0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc';
19
+
20
+ // Tolerance of the swap leg: the aggregator's `toAmountMin` lets the swap
21
+ // deliver up to 3% less WETH than quoted.
22
+ const SWAP_SLIPPAGE = 0.03;
23
+
24
+ export interface UniswapV2AddLiquidityInput {
25
+ readonly owner: Address;
26
+ readonly usdcAmount: `${bigint}`;
27
+ }
28
+
29
+ /**
30
+ * Deposit USDC alone into the Uniswap V2 USDC/WETH pair.
31
+ *
32
+ * - `core.split` halves the USDC input.
33
+ * - `lifi.swap` turns one half into WETH.
34
+ * - `uniswapV2.addLiquidity` deposits the other USDC half and the swapped
35
+ * WETH, minting the UNI-V2 LP token. Unused input comes back as residuals.
36
+ * - The request sweeps the LP token and the residuals to the signer.
37
+ */
38
+ export const buildUniswapV2AddLiquidity = ({
39
+ owner,
40
+ usdcAmount,
41
+ }: UniswapV2AddLiquidityInput): {
42
+ flow: Flow;
43
+ request: ComposeCompileRequest;
44
+ } => {
45
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
46
+
47
+ const builder = sdk.flow(1, {
48
+ name: 'uniswap-v2-add-liquidity-usdc-weth',
49
+ inputs: {
50
+ usdcIn: resources.erc20(USDC, 1),
51
+ },
52
+ });
53
+
54
+ const { a: usdcHalf, b: usdcToSwap } = builder.core.split('split', {
55
+ bind: { source: builder.inputs.usdcIn },
56
+ config: { bps: 5000 },
57
+ });
58
+
59
+ const swap = builder.lifi.swap('swap', {
60
+ bind: { amountIn: usdcToSwap },
61
+ config: {
62
+ resourceOut: resources.erc20(WETH, 1),
63
+ slippage: SWAP_SLIPPAGE,
64
+ },
65
+ });
66
+
67
+ builder.uniswapV2.addLiquidity('add-liquidity', {
68
+ bind: {
69
+ tokenA: usdcHalf,
70
+ tokenB: swap.amountOut,
71
+ },
72
+ config: {
73
+ router: UNISWAP_V2_ROUTER,
74
+ factory: UNISWAP_V2_FACTORY,
75
+ pair: USDC_WETH_PAIR,
76
+ },
77
+ guards: [
78
+ // The router is called with zero minimums, so this band is the sandwich
79
+ // protection: it reverts unless the pool price read before the deposit
80
+ // stays within ±50 bps of the simulated price. It does not depend on the
81
+ // swap leg.
82
+ guards.band({ port: 'poolPrice', bps: 50 }),
83
+ // A swap that fills at its 3% minimum delivers less WETH, so the add
84
+ // mints less LP. The floor must cover that tolerance (300 bps) plus the
85
+ // 50 bps band, or a valid swap fill reverts the transaction.
86
+ guards.slippage({ port: 'liquidity', bps: 350 }),
87
+ ],
88
+ });
89
+
90
+ const flow = builder.build();
91
+
92
+ const request = sdk.request(flow, {
93
+ signer: owner,
94
+ inputs: {
95
+ usdcIn: materialisers.directDeposit({ amount: usdcAmount }),
96
+ },
97
+ // Sweep the LP token and the unused USDC/WETH back to the signer.
98
+ sweepTo: builder.context.sender,
99
+ // The UNI-V2 LP token is unpriced, so the default 500 bps price-impact
100
+ // check reads the deposit as a 100% loss. 0 skips the check; the `band`
101
+ // and `slippage` guards above are the protection.
102
+ maxPriceImpactBps: 0,
103
+ });
104
+
105
+ return { flow, request };
106
+ };