@lifi/composer-sdk 0.0.1-alpha

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 (160) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +220 -0
  3. package/dist/authoring/FlowBuilderCore.cjs +115 -0
  4. package/dist/authoring/FlowBuilderCore.cjs.map +1 -0
  5. package/dist/authoring/FlowBuilderCore.d.cts +114 -0
  6. package/dist/authoring/FlowBuilderCore.d.ts +114 -0
  7. package/dist/authoring/FlowBuilderCore.js +91 -0
  8. package/dist/authoring/FlowBuilderCore.js.map +1 -0
  9. package/dist/authoring/handles.cjs +43 -0
  10. package/dist/authoring/handles.cjs.map +1 -0
  11. package/dist/authoring/handles.d.cts +61 -0
  12. package/dist/authoring/handles.d.ts +61 -0
  13. package/dist/authoring/handles.js +17 -0
  14. package/dist/authoring/handles.js.map +1 -0
  15. package/dist/authoring/raw.cjs +41 -0
  16. package/dist/authoring/raw.cjs.map +1 -0
  17. package/dist/authoring/raw.d.cts +47 -0
  18. package/dist/authoring/raw.d.ts +47 -0
  19. package/dist/authoring/raw.js +16 -0
  20. package/dist/authoring/raw.js.map +1 -0
  21. package/dist/authoring/signatureArgs.cjs +114 -0
  22. package/dist/authoring/signatureArgs.cjs.map +1 -0
  23. package/dist/authoring/signatureArgs.d.cts +146 -0
  24. package/dist/authoring/signatureArgs.d.ts +146 -0
  25. package/dist/authoring/signatureArgs.js +87 -0
  26. package/dist/authoring/signatureArgs.js.map +1 -0
  27. package/dist/client.cjs +140 -0
  28. package/dist/client.cjs.map +1 -0
  29. package/dist/client.d.cts +67 -0
  30. package/dist/client.d.ts +67 -0
  31. package/dist/client.js +116 -0
  32. package/dist/client.js.map +1 -0
  33. package/dist/discovery.cjs +17 -0
  34. package/dist/discovery.cjs.map +1 -0
  35. package/dist/discovery.d.cts +56 -0
  36. package/dist/discovery.d.ts +56 -0
  37. package/dist/discovery.js +1 -0
  38. package/dist/discovery.js.map +1 -0
  39. package/dist/errors.cjs +91 -0
  40. package/dist/errors.cjs.map +1 -0
  41. package/dist/errors.d.cts +77 -0
  42. package/dist/errors.d.ts +77 -0
  43. package/dist/errors.js +65 -0
  44. package/dist/errors.js.map +1 -0
  45. package/dist/generated/config.generated.cjs +17 -0
  46. package/dist/generated/config.generated.cjs.map +1 -0
  47. package/dist/generated/config.generated.d.cts +144 -0
  48. package/dist/generated/config.generated.d.ts +144 -0
  49. package/dist/generated/config.generated.js +1 -0
  50. package/dist/generated/config.generated.js.map +1 -0
  51. package/dist/generated/guards.generated.cjs +32 -0
  52. package/dist/generated/guards.generated.cjs.map +1 -0
  53. package/dist/generated/guards.generated.d.cts +4 -0
  54. package/dist/generated/guards.generated.d.ts +4 -0
  55. package/dist/generated/guards.generated.js +8 -0
  56. package/dist/generated/guards.generated.js.map +1 -0
  57. package/dist/generated/materialisers.generated.cjs +44 -0
  58. package/dist/generated/materialisers.generated.cjs.map +1 -0
  59. package/dist/generated/materialisers.generated.d.cts +4 -0
  60. package/dist/generated/materialisers.generated.d.ts +4 -0
  61. package/dist/generated/materialisers.generated.js +18 -0
  62. package/dist/generated/materialisers.generated.js.map +1 -0
  63. package/dist/generated/operations.generated.cjs +110 -0
  64. package/dist/generated/operations.generated.cjs.map +1 -0
  65. package/dist/generated/operations.generated.d.cts +337 -0
  66. package/dist/generated/operations.generated.d.ts +337 -0
  67. package/dist/generated/operations.generated.js +89 -0
  68. package/dist/generated/operations.generated.js.map +1 -0
  69. package/dist/generated/preconditions.generated.cjs +44 -0
  70. package/dist/generated/preconditions.generated.cjs.map +1 -0
  71. package/dist/generated/preconditions.generated.d.cts +4 -0
  72. package/dist/generated/preconditions.generated.d.ts +4 -0
  73. package/dist/generated/preconditions.generated.js +18 -0
  74. package/dist/generated/preconditions.generated.js.map +1 -0
  75. package/dist/guards.generated-DKKDKREA.d.ts +14 -0
  76. package/dist/guards.generated-hrQ1KPNv.d.cts +14 -0
  77. package/dist/index.cjs +76 -0
  78. package/dist/index.cjs.map +1 -0
  79. package/dist/index.d.cts +99 -0
  80. package/dist/index.d.ts +99 -0
  81. package/dist/index.js +30 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/materialisers.generated-BsA1uDW8.d.ts +24 -0
  84. package/dist/materialisers.generated-nMxTAaVi.d.cts +24 -0
  85. package/dist/preconditions.generated-DblS13Wq.d.cts +24 -0
  86. package/dist/preconditions.generated-U7YpVh30.d.ts +24 -0
  87. package/dist/raw-Dj_2rBSQ.d.cts +19 -0
  88. package/dist/raw-IxCF_bSS.d.ts +19 -0
  89. package/dist/raw.cjs +34 -0
  90. package/dist/raw.cjs.map +1 -0
  91. package/dist/raw.d.cts +4 -0
  92. package/dist/raw.d.ts +4 -0
  93. package/dist/raw.js +8 -0
  94. package/dist/raw.js.map +1 -0
  95. package/dist/resources-BKlFxjo8.d.cts +56 -0
  96. package/dist/resources-CYis1_DS.d.ts +56 -0
  97. package/dist/resources.cjs +39 -0
  98. package/dist/resources.cjs.map +1 -0
  99. package/dist/resources.d.cts +3 -0
  100. package/dist/resources.d.ts +3 -0
  101. package/dist/resources.js +14 -0
  102. package/dist/resources.js.map +1 -0
  103. package/dist/run/inputs.cjs +51 -0
  104. package/dist/run/inputs.cjs.map +1 -0
  105. package/dist/run/inputs.d.cts +91 -0
  106. package/dist/run/inputs.d.ts +91 -0
  107. package/dist/run/inputs.js +26 -0
  108. package/dist/run/inputs.js.map +1 -0
  109. package/dist/sdk.cjs +60 -0
  110. package/dist/sdk.cjs.map +1 -0
  111. package/dist/sdk.d.cts +112 -0
  112. package/dist/sdk.d.ts +112 -0
  113. package/dist/sdk.js +40 -0
  114. package/dist/sdk.js.map +1 -0
  115. package/dist/types.cjs +17 -0
  116. package/dist/types.cjs.map +1 -0
  117. package/dist/types.d.cts +74 -0
  118. package/dist/types.d.ts +74 -0
  119. package/dist/types.js +1 -0
  120. package/dist/types.js.map +1 -0
  121. package/package.json +81 -0
  122. package/src/authoring/FlowBuilderCore.ts +270 -0
  123. package/src/authoring/handles.ts +81 -0
  124. package/src/authoring/raw.ts +60 -0
  125. package/src/authoring/signatureArgs.ts +249 -0
  126. package/src/client.ts +230 -0
  127. package/src/discovery.ts +51 -0
  128. package/src/errors.ts +150 -0
  129. package/src/examples/approveAndDeposit.ts +84 -0
  130. package/src/examples/callContract.ts +199 -0
  131. package/src/examples/config.ts +9 -0
  132. package/src/examples/consolidateToEth.ts +94 -0
  133. package/src/examples/consolidateToUsdc.ts +95 -0
  134. package/src/examples/depositFromProxy.ts +87 -0
  135. package/src/examples/dustSweep.ts +66 -0
  136. package/src/examples/lifiSwap.ts +56 -0
  137. package/src/examples/lifiZap.ts +60 -0
  138. package/src/examples/rawCallWithArithmetic.ts +78 -0
  139. package/src/examples/readContractState.ts +77 -0
  140. package/src/examples/run.ts +168 -0
  141. package/src/examples/splitAndZap.ts +73 -0
  142. package/src/examples/splitWithArithmetic.ts +93 -0
  143. package/src/examples/swapAndZap.ts +72 -0
  144. package/src/examples/swapToRecipient.ts +109 -0
  145. package/src/examples/swapWithAllowRevert.ts +119 -0
  146. package/src/examples/swapWithBalanceCheck.ts +73 -0
  147. package/src/examples/swapWithOutputValidation.ts +125 -0
  148. package/src/examples/transferTokens.ts +123 -0
  149. package/src/examples/untypedOpWithTypedRef.ts +77 -0
  150. package/src/generated/config.generated.ts +174 -0
  151. package/src/generated/guards.generated.ts +14 -0
  152. package/src/generated/materialisers.generated.ts +44 -0
  153. package/src/generated/operations.generated.ts +568 -0
  154. package/src/generated/preconditions.generated.ts +43 -0
  155. package/src/index.ts +149 -0
  156. package/src/raw.ts +10 -0
  157. package/src/resources.ts +61 -0
  158. package/src/run/inputs.ts +117 -0
  159. package/src/sdk.ts +173 -0
  160. package/src/types.ts +101 -0
@@ -0,0 +1,78 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import { createComposeSdk } from '../index.js';
4
+ import type { Address } from '../types.js';
5
+
6
+ import { BASE_URL } from './config.js';
7
+
8
+ // Example contract address for a non-standard oracle
9
+ const ORACLE = '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419';
10
+
11
+ export interface RawCallWithArithmeticInput {
12
+ readonly owner: Address;
13
+ }
14
+
15
+ /**
16
+ * Query a non-standard contract with pre-encoded calldata, then derive
17
+ * values from the result using multiply, divideDown, and divideUp.
18
+ *
19
+ * Demonstrates:
20
+ * - core.rawCall to invoke a contract with pre-encoded calldata
21
+ * - core.multiply to scale a raw value
22
+ * - core.divideDown / core.divideUp for rounding-aware division
23
+ */
24
+ export const buildRawCallWithArithmetic = ({
25
+ owner,
26
+ }: RawCallWithArithmeticInput): {
27
+ flow: Flow;
28
+ request: ComposeCompileRequest;
29
+ } => {
30
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
31
+
32
+ const builder = sdk.flow(1, {
33
+ name: 'raw-call-with-arithmetic',
34
+ inputs: {},
35
+ });
36
+
37
+ // Call an oracle contract with pre-encoded calldata for latestAnswer().
38
+ // selector: 0x50d25bcd = keccak256("latestAnswer()")[:4]
39
+ const oracleResult = builder.core.rawCall('read-oracle', {
40
+ bind: {},
41
+ config: {
42
+ target: ORACLE,
43
+ calldata: '0x50d25bcd',
44
+ callType: 'StaticCall',
45
+ resultType: 'uint256',
46
+ },
47
+ });
48
+
49
+ // Scale the oracle result by multiplying with itself.
50
+ // This models squaring a price value for demonstration purposes.
51
+ const scaled = builder.core.multiply('scale-up', {
52
+ bind: { a: oracleResult.result, b: oracleResult.result },
53
+ });
54
+
55
+ // Divide down (floor) by a divisor — models conservative conversion.
56
+ const floorResult = builder.core.divideDown('floor-convert', {
57
+ bind: { a: scaled.result, b: oracleResult.result },
58
+ });
59
+
60
+ // Divide up (ceil) by the same divisor — models optimistic conversion.
61
+ const ceilResult = builder.core.divideUp('ceil-convert', {
62
+ bind: { a: scaled.result, b: oracleResult.result },
63
+ });
64
+
65
+ // Verify the floor result is no greater than the ceil result.
66
+ builder.core.assertLte('check-floor-lte-ceil', {
67
+ bind: { a: floorResult.result, b: ceilResult.result },
68
+ });
69
+
70
+ const flow = builder.build();
71
+
72
+ const request = sdk.request(flow, {
73
+ signer: owner,
74
+ inputs: {},
75
+ });
76
+
77
+ return { flow, request };
78
+ };
@@ -0,0 +1,77 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import { createComposeSdk } from '../index.js';
4
+ import type { Address } from '../types.js';
5
+
6
+ import { BASE_URL } from './config.js';
7
+
8
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
9
+ // Example ERC-4626 vault address (Steakhouse USDC on Ethereum mainnet)
10
+ const VAULT = '0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB';
11
+
12
+ export interface ReadContractStateInput {
13
+ readonly owner: Address;
14
+ }
15
+
16
+ /**
17
+ * Read on-chain state using three different strategies:
18
+ * peek (compile-time), staticCall (execution-time), and balanceOf (resource).
19
+ *
20
+ * Demonstrates:
21
+ * - core.peek to read a vault's totalAssets at compile time (baked as literal)
22
+ * - core.staticCall to read totalSupply at execution time (fresh value)
23
+ * - core.balanceOf to read a token balance as a tracked resource
24
+ */
25
+ export const buildReadContractState = ({
26
+ owner,
27
+ }: ReadContractStateInput): {
28
+ flow: Flow;
29
+ request: ComposeCompileRequest;
30
+ } => {
31
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
32
+
33
+ const builder = sdk.flow(1, {
34
+ name: 'read-contract-state',
35
+ inputs: {},
36
+ });
37
+
38
+ // Read vault totalAssets at compile time.
39
+ // The result is resolved off-chain and baked into the program as a literal.
40
+ builder.core.peek('total-assets', {
41
+ bind: {},
42
+ config: {
43
+ target: VAULT,
44
+ functionSignature: 'function totalAssets() view returns (uint256)',
45
+ },
46
+ });
47
+
48
+ // Read vault totalSupply at execution time.
49
+ // Unlike peek, this value is read on-chain during VM execution.
50
+ builder.core.staticCall('total-supply', {
51
+ bind: {},
52
+ config: {
53
+ target: VAULT,
54
+ functionSignature: 'function totalSupply() view returns (uint256)',
55
+ },
56
+ });
57
+
58
+ // Read the owner's USDC balance as a tracked resource.
59
+ // Produces a resource handle that downstream nodes can consume.
60
+ builder.core.balanceOf('usdc-balance', {
61
+ bind: {},
62
+ config: {
63
+ token: USDC,
64
+ owner,
65
+ },
66
+ });
67
+
68
+ const flow = builder.build();
69
+
70
+ const request = sdk.request(flow, {
71
+ signer: owner,
72
+ inputs: {},
73
+ sweepTo: builder.context.sender,
74
+ });
75
+
76
+ return { flow, request };
77
+ };
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Example harness — builds a request and sends it to a live compose backend.
3
+ *
4
+ * Usage:
5
+ * COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>
6
+ *
7
+ * Pass LIFI_API_KEY to authenticate:
8
+ * LIFI_API_KEY=your-key COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>
9
+ *
10
+ * Available examples:
11
+ * approve-deposit — approve vault allowance then deposit USDC
12
+ * consolidate — consolidate ERC-20 balances to USDC
13
+ * consolidate-eth — consolidate ERC-20 balances to native ETH
14
+ * deposit-proxy — deposit tokens already on the proxy into Aave
15
+ * dust-sweep — split USDC 80/20 and sweep leftover dust
16
+ * swap — swap WETH to USDC via LI.FI
17
+ * split-zap — split USDC 60/40 and zap into Aave + Morpho vaults
18
+ * split-arithmetic — split USDC 70/30 with arithmetic assertions
19
+ * zap — zap USDC into Aave lending position
20
+ * swap-zap — swap WETH to USDC then zap into Aave
21
+ * swap-check — swap WETH to USDC with balance check
22
+ * swap-recipient — swap WETH + DAI to USDC and send to recipient
23
+ * swap-validate — swap WETH to USDC with output validation bounds
24
+ * swap-allow-revert — swap WETH to USDC with allow-revert policy
25
+ * raw-call — query a contract with raw calldata + arithmetic
26
+ * read-state — read on-chain state via peek, staticCall, balanceOf
27
+ * redeem — redeem ERC-4626 vault shares via core.call
28
+ * claim — claim rewards from a contract (resource-free call)
29
+ * wrap-eth — wrap native ETH into WETH via ValueCall
30
+ * transfer — transfer full token balance to a recipient
31
+ * partial-transfer — transfer a specific amount, keeping the remainder
32
+ * untyped-ref — mix untypedOp with typed handles via raw.ref
33
+ */
34
+ import type { ComposeCompileRequest } from '@lifi/compose-spec';
35
+
36
+ import { createComposeSdk } from '../sdk.js';
37
+
38
+ import { buildApproveAndDeposit } from './approveAndDeposit.js';
39
+ import {
40
+ buildClaimRewards,
41
+ buildRedeemFromVault,
42
+ buildWrapEth,
43
+ } from './callContract.js';
44
+ import { API_KEY, BASE_URL, OWNER, PROXY, RECIPIENT } from './config.js';
45
+ import { buildConsolidateToEth } from './consolidateToEth.js';
46
+ import { buildConsolidateStablesToUsdc } from './consolidateToUsdc.js';
47
+ import { buildDepositFromProxy } from './depositFromProxy.js';
48
+ import { buildDustSweepExample } from './dustSweep.js';
49
+ import { buildLifiSwapExample } from './lifiSwap.js';
50
+ import { buildLifiZapExample } from './lifiZap.js';
51
+ import { buildRawCallWithArithmetic } from './rawCallWithArithmetic.js';
52
+ import { buildReadContractState } from './readContractState.js';
53
+ import { buildSplitAndZapExample } from './splitAndZap.js';
54
+ import { buildSplitWithArithmetic } from './splitWithArithmetic.js';
55
+ import { buildSwapAndZapExample } from './swapAndZap.js';
56
+ import { buildSwapToRecipient } from './swapToRecipient.js';
57
+ import { buildSwapWithAllowRevertExample } from './swapWithAllowRevert.js';
58
+ import { buildSwapWithBalanceCheck } from './swapWithBalanceCheck.js';
59
+ import { buildSwapWithOutputValidation } from './swapWithOutputValidation.js';
60
+ import { buildPartialTransfer, buildTransferTokens } from './transferTokens.js';
61
+ import { buildUntypedOpWithTypedRef } from './untypedOpWithTypedRef.js';
62
+
63
+ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
64
+ 'approve-deposit': () =>
65
+ buildApproveAndDeposit({ owner: OWNER, amount: '1000000000' }).request,
66
+ consolidate: () =>
67
+ buildConsolidateStablesToUsdc({
68
+ owner: OWNER,
69
+ usdtAmount: '1000000000',
70
+ daiAmount: '1000000000000000000000',
71
+ fraxAmount: '1000000000000000000000',
72
+ lusdAmount: '1000000000000000000000',
73
+ }).request,
74
+ 'consolidate-eth': () =>
75
+ buildConsolidateToEth({
76
+ owner: OWNER,
77
+ wethAmount: '1000000000000000000',
78
+ usdcAmount: '1000000000',
79
+ usdtAmount: '1000000000',
80
+ daiAmount: '1000000000000000000000',
81
+ }).request,
82
+ 'deposit-proxy': () =>
83
+ buildDepositFromProxy({
84
+ owner: OWNER,
85
+ proxyAddress: PROXY,
86
+ expectedAmount: '1000000000',
87
+ }).request,
88
+ 'dust-sweep': () => buildDustSweepExample().request,
89
+ swap: () => buildLifiSwapExample().request,
90
+ 'split-zap': () => buildSplitAndZapExample().request,
91
+ 'split-arithmetic': () =>
92
+ buildSplitWithArithmetic({ owner: OWNER, amount: '1000000000' }).request,
93
+ zap: () => buildLifiZapExample().request,
94
+ 'swap-zap': () => buildSwapAndZapExample().request,
95
+ 'swap-check': () =>
96
+ buildSwapWithBalanceCheck({ owner: OWNER, amount: '1000000000000000000' })
97
+ .request,
98
+ 'swap-recipient': () =>
99
+ buildSwapToRecipient({
100
+ owner: OWNER,
101
+ recipient: RECIPIENT,
102
+ wethAmount: '1000000000000000000',
103
+ daiAmount: '500000000000000000000',
104
+ }).request,
105
+ 'swap-validate': () =>
106
+ buildSwapWithOutputValidation({
107
+ owner: OWNER,
108
+ amount: '1000000000000000000',
109
+ expectedOut: '3000000000',
110
+ }).request,
111
+ 'swap-allow-revert': () => buildSwapWithAllowRevertExample().request,
112
+ 'raw-call': () => buildRawCallWithArithmetic({ owner: OWNER }).request,
113
+ 'read-state': () => buildReadContractState({ owner: OWNER }).request,
114
+ redeem: () =>
115
+ buildRedeemFromVault({ owner: OWNER, amount: '1000000000000000000' })
116
+ .request,
117
+ claim: () => buildClaimRewards({ owner: OWNER }).request,
118
+ 'wrap-eth': () =>
119
+ buildWrapEth({ owner: OWNER, amount: '1000000000000000000' }).request,
120
+ transfer: () =>
121
+ buildTransferTokens({
122
+ owner: OWNER,
123
+ recipient: RECIPIENT,
124
+ amount: '1000000000',
125
+ }).request,
126
+ 'partial-transfer': () =>
127
+ buildPartialTransfer({
128
+ owner: OWNER,
129
+ recipient: RECIPIENT,
130
+ amount: '1000000000',
131
+ }).request,
132
+ 'untyped-ref': () => buildUntypedOpWithTypedRef({ owner: OWNER }).request,
133
+ };
134
+
135
+ const run = async () => {
136
+ const name = process.argv[2];
137
+ const builder = name ? EXAMPLES[name] : undefined;
138
+
139
+ if (!builder) {
140
+ const valid = Object.keys(EXAMPLES).join(', ');
141
+ console.error(
142
+ `Error: ${
143
+ name ? `unknown example "${name}"` : 'no example specified'
144
+ }\n` +
145
+ `Valid examples: ${valid}\n` +
146
+ `Usage: COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>`,
147
+ );
148
+ process.exit(1);
149
+ }
150
+ console.log(`Running example: ${name}`);
151
+
152
+ const request = builder();
153
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
154
+
155
+ console.log('--- Request ---');
156
+ console.log(JSON.stringify(request, null, 2));
157
+
158
+ console.log(`\n--- Compiling against ${BASE_URL} ---`);
159
+ const result = await sdk.client.compile(request);
160
+
161
+ console.log('\n--- Result ---');
162
+ console.log(JSON.stringify(result, null, 2));
163
+ };
164
+
165
+ run().catch((err: unknown) => {
166
+ console.error(err);
167
+ process.exit(1);
168
+ });
@@ -0,0 +1,73 @@
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
+
10
+ import { BASE_URL, OWNER } from './config.js';
11
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
12
+ // Aave v3 aEthUSDC receipt token on Ethereum mainnet
13
+ const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';
14
+ // Steakhouse USDC (Morpho MetaMorpho vault) on Ethereum mainnet
15
+ const STEAKHOUSE_USDC = '0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB';
16
+
17
+ /**
18
+ * Split USDC 60/40 and zap each portion into a different vault.
19
+ *
20
+ * Demonstrates:
21
+ * - core.split to divide a resource by basis-point ratio
22
+ * - Threading split outputs into two independent lifi.zap nodes
23
+ * - Slippage guards on both zap outputs
24
+ */
25
+ export const buildSplitAndZapExample = (): {
26
+ flow: Flow;
27
+ request: ComposeCompileRequest;
28
+ } => {
29
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
30
+
31
+ const builder = sdk.flow(1, {
32
+ name: 'split-usdc-to-two-vaults',
33
+ inputs: {
34
+ amountIn: resources.erc20(USDC, 1),
35
+ },
36
+ });
37
+
38
+ // Split USDC 60/40 — 6000 bps to `a`, remainder to `b`.
39
+ const { a, b } = builder.core.split('split', {
40
+ bind: { source: builder.inputs.amountIn },
41
+ config: { bps: 6000 },
42
+ });
43
+
44
+ // Zap 60% into Aave v3 aEthUSDC.
45
+ builder.lifi.zap('zap-aave', {
46
+ bind: { amountIn: a },
47
+ config: {
48
+ resourceOut: resources.erc20(A_ETH_USDC, 1),
49
+ },
50
+ guards: [guards.slippage({ port: 'amountOut', bps: 100 })],
51
+ });
52
+
53
+ // Zap 40% into Steakhouse USDC (Morpho).
54
+ builder.lifi.zap('zap-morpho', {
55
+ bind: { amountIn: b },
56
+ config: {
57
+ resourceOut: resources.erc20(STEAKHOUSE_USDC, 1),
58
+ },
59
+ guards: [guards.slippage({ port: 'amountOut', bps: 100 })],
60
+ });
61
+
62
+ const flow = builder.build();
63
+
64
+ const request = sdk.request(flow, {
65
+ signer: OWNER,
66
+ inputs: {
67
+ amountIn: materialisers.directDeposit({ amount: '10000000000' }),
68
+ },
69
+ sweepTo: builder.context.sender,
70
+ });
71
+
72
+ return { flow, request };
73
+ };
@@ -0,0 +1,93 @@
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 { BASE_URL } from './config.js';
7
+
8
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
9
+
10
+ export interface SplitWithArithmeticInput {
11
+ readonly owner: Address;
12
+ readonly amount: `${bigint}`;
13
+ }
14
+
15
+ /**
16
+ * Split USDC 70/30, then verify the parts with arithmetic and assertions.
17
+ *
18
+ * Demonstrates:
19
+ * - core.add to reconstruct the whole from parts
20
+ * - core.subtract to compute the difference between parts
21
+ * - core.assertEqual to verify reconstruction matches the original
22
+ * - core.assertNotEqual to verify the parts are distinct
23
+ * - core.assertGt / core.assertLt to verify ordering of unequal parts
24
+ */
25
+ export const buildSplitWithArithmetic = ({
26
+ owner,
27
+ amount,
28
+ }: SplitWithArithmeticInput): {
29
+ flow: Flow;
30
+ request: ComposeCompileRequest;
31
+ } => {
32
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
33
+
34
+ const builder = sdk.flow(1, {
35
+ name: 'split-with-arithmetic',
36
+ inputs: {
37
+ amountIn: resources.erc20(USDC, 1),
38
+ },
39
+ });
40
+
41
+ // Split USDC 70/30.
42
+ const { a: larger, b: smaller } = builder.core.split('split', {
43
+ bind: { source: builder.inputs.amountIn },
44
+ config: { bps: 7000 },
45
+ });
46
+
47
+ // Add the two parts back together.
48
+ const sum = builder.core.add('sum', {
49
+ bind: { a: larger, b: smaller },
50
+ });
51
+
52
+ // Compute the difference between the larger and smaller portions.
53
+ const diff = builder.core.subtract('diff', {
54
+ bind: { a: larger, b: smaller },
55
+ });
56
+
57
+ // The sum of parts should equal the original input.
58
+ builder.core.assertEqual('check-sum-equals-input', {
59
+ bind: { a: sum.result, b: builder.inputs.amountIn },
60
+ });
61
+
62
+ // The two parts should not be equal (70/30 split).
63
+ builder.core.assertNotEqual('check-parts-differ', {
64
+ bind: { a: larger, b: smaller },
65
+ });
66
+
67
+ // The 70% portion should be strictly greater than the 30% portion.
68
+ builder.core.assertGt('check-larger-gt-smaller', {
69
+ bind: { a: larger, b: smaller },
70
+ });
71
+
72
+ // The 30% portion should be strictly less than the 70% portion.
73
+ builder.core.assertLt('check-smaller-lt-larger', {
74
+ bind: { a: smaller, b: larger },
75
+ });
76
+
77
+ // The difference should be greater than zero (non-trivial gap).
78
+ builder.core.assertGt('check-diff-positive', {
79
+ bind: { a: diff.result, b: smaller },
80
+ });
81
+
82
+ const flow = builder.build();
83
+
84
+ const request = sdk.request(flow, {
85
+ signer: owner,
86
+ inputs: {
87
+ amountIn: materialisers.directDeposit({ amount }),
88
+ },
89
+ sweepTo: builder.context.sender,
90
+ });
91
+
92
+ return { flow, request };
93
+ };
@@ -0,0 +1,72 @@
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
+
10
+ import { BASE_URL, OWNER } from './config.js';
11
+ const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
12
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
13
+ // Aave aEthUSDC receipt token on Ethereum mainnet
14
+ const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';
15
+
16
+ /**
17
+ * Swap WETH to USDC, then zap the USDC into an Aave lending position via LI.FI.
18
+ *
19
+ * Demonstrates:
20
+ * - Chaining a swap into a zap by threading output handles
21
+ * - The swap's amountOut feeds directly into the zap's amountIn
22
+ * - Slippage guard on the zap output (swap output has providesMinimum)
23
+ */
24
+ export const buildSwapAndZapExample = (): {
25
+ flow: Flow;
26
+ request: ComposeCompileRequest;
27
+ } => {
28
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
29
+
30
+ // Declare the flow with a single WETH input on Ethereum mainnet.
31
+ const builder = sdk.flow(1, {
32
+ name: 'swap-and-zap-weth-to-aave',
33
+ inputs: {
34
+ amountIn: resources.erc20(WETH, 1),
35
+ },
36
+ });
37
+
38
+ // Swap WETH → USDC via LI.FI.
39
+ const swapOutputs = builder.lifi.swap('swap', {
40
+ bind: { amountIn: builder.inputs.amountIn },
41
+ config: {
42
+ resourceOut: resources.erc20(USDC, 1),
43
+ slippage: 0.03,
44
+ },
45
+ });
46
+
47
+ // Zap the swapped USDC into Aave's aEthUSDC position via LI.FI.
48
+ // The swap's amountOut handle is threaded directly into the zap's amountIn.
49
+ builder.lifi.zap('zap', {
50
+ bind: { amountIn: swapOutputs.amountOut },
51
+ config: {
52
+ resourceOut: resources.erc20(A_ETH_USDC, 1),
53
+ },
54
+ guards: [guards.slippage({ port: 'amountOut', bps: 100 })],
55
+ });
56
+
57
+ const flow = builder.build();
58
+
59
+ // Build the compile request.
60
+ // directDeposit transfers a fixed amount of WETH into the VM.
61
+ const request = sdk.request(flow, {
62
+ signer: OWNER,
63
+ inputs: {
64
+ amountIn: materialisers.directDeposit({
65
+ amount: '1000000000000000000',
66
+ }),
67
+ },
68
+ sweepTo: builder.context.sender,
69
+ });
70
+
71
+ return { flow, request };
72
+ };
@@ -0,0 +1,109 @@
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 { BASE_URL } from './config.js';
7
+
8
+ const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
9
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
10
+ const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
11
+
12
+ export interface SwapToRecipientInput {
13
+ readonly owner: Address;
14
+ readonly recipient: Address;
15
+ readonly wethAmount: `${bigint}`;
16
+ readonly daiAmount: `${bigint}`;
17
+ }
18
+
19
+ /**
20
+ <<<<<<< HEAD
21
+ <<<<<<< HEAD
22
+ * Swap WETH and DAI into USDC, merge the outputs, transfer to a recipient,
23
+ =======
24
+ * Swap WETH and DAI into USDC, merge the outputs, transfer to the recipient,
25
+ >>>>>>> a2c178fd (chore: fix examples)
26
+ * and verify the recipient holds the combined balance.
27
+ =======
28
+ * Swap WETH and DAI into USDC, merge the outputs, and deliver to a recipient.
29
+ >>>>>>> 4c49ff9b (fix: support resource bindings for handle ports)
30
+ *
31
+ * Demonstrates:
32
+ * - Multiple resource inputs (two ERC-20 tokens)
33
+ * - A handle input (recipient address as a scalar value)
34
+ * - Chaining two swaps through a merge node
35
+ <<<<<<< HEAD
36
+ <<<<<<< HEAD
37
+ * - Explicit core.transfer to send merged tokens to the recipient
38
+ * - Copy-mode resource input on invariant.balanceAtLeast (reads without consuming)
39
+ =======
40
+ * - core.transfer to send merged tokens to the recipient
41
+ * - Using invariant.balanceAtLeast with a handle input for the account
42
+ >>>>>>> a2c178fd (chore: fix examples)
43
+ =======
44
+ * - Using `sweepTo` with a handle input to deliver tokens to the recipient
45
+ >>>>>>> 4c49ff9b (fix: support resource bindings for handle ports)
46
+ * - Typed request inputs inferred from the flow schema
47
+ */
48
+ export const buildSwapToRecipient = ({
49
+ owner,
50
+ recipient,
51
+ wethAmount,
52
+ daiAmount,
53
+ }: SwapToRecipientInput): {
54
+ flow: Flow;
55
+ request: ComposeCompileRequest;
56
+ } => {
57
+ const sdk = createComposeSdk({ baseUrl: BASE_URL });
58
+
59
+ // Declare the flow on Ethereum mainnet with two token inputs and one address input.
60
+ const builder = sdk.flow(1, {
61
+ name: 'swap-to-recipient',
62
+ inputs: {
63
+ wethIn: resources.erc20(WETH, 1),
64
+ daiIn: resources.erc20(DAI, 1),
65
+ recipient: 'address',
66
+ },
67
+ });
68
+
69
+ // Swap WETH → USDC via LI.FI.
70
+ const wethSwap = builder.lifi.swap('swap-weth', {
71
+ bind: { amountIn: builder.inputs.wethIn },
72
+ config: {
73
+ resourceOut: resources.erc20(USDC, 1),
74
+ slippage: 0.03,
75
+ },
76
+ });
77
+
78
+ // Swap DAI → USDC via LI.FI.
79
+ const daiSwap = builder.lifi.swap('swap-dai', {
80
+ bind: { amountIn: builder.inputs.daiIn },
81
+ config: {
82
+ resourceOut: resources.erc20(USDC, 1),
83
+ slippage: 0.03,
84
+ },
85
+ });
86
+
87
+ // Merge the two USDC outputs into a single resource.
88
+ builder.core.merge('merge-usdc', {
89
+ bind: { a: wethSwap.amountOut, b: daiSwap.amountOut },
90
+ });
91
+
92
+ const flow = builder.build();
93
+
94
+ // Build the compile request with typed inputs matching the flow schema.
95
+ // Resource inputs use directDeposit materialisers with fixed amounts.
96
+ // The handle input passes the recipient address as a plain string.
97
+ // sweepTo delivers all terminal resources (the merged USDC) to the recipient.
98
+ const request = sdk.request(flow, {
99
+ signer: owner,
100
+ inputs: {
101
+ wethIn: materialisers.directDeposit({ amount: wethAmount }),
102
+ daiIn: materialisers.directDeposit({ amount: daiAmount }),
103
+ recipient,
104
+ },
105
+ sweepTo: recipient,
106
+ });
107
+
108
+ return { flow, request };
109
+ };