@lifi/composer-sdk 0.10.0 → 0.11.3

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 (58) hide show
  1. package/README.md +36 -2
  2. package/dist/authoring/raw.cjs +12 -7
  3. package/dist/authoring/raw.cjs.map +1 -1
  4. package/dist/authoring/raw.d.cts +12 -7
  5. package/dist/authoring/raw.d.ts +12 -7
  6. package/dist/authoring/raw.js +12 -7
  7. package/dist/authoring/raw.js.map +1 -1
  8. package/dist/client.cjs +11 -1
  9. package/dist/client.cjs.map +1 -1
  10. package/dist/client.js +11 -1
  11. package/dist/client.js.map +1 -1
  12. package/dist/errors.cjs +35 -13
  13. package/dist/errors.cjs.map +1 -1
  14. package/dist/errors.d.cts +19 -1
  15. package/dist/errors.d.ts +19 -1
  16. package/dist/errors.js +35 -14
  17. package/dist/errors.js.map +1 -1
  18. package/dist/generated/config.generated.d.cts +96 -1
  19. package/dist/generated/config.generated.d.ts +96 -1
  20. package/dist/generated/operations.generated.cjs +10 -0
  21. package/dist/generated/operations.generated.cjs.map +1 -1
  22. package/dist/generated/operations.generated.d.cts +56 -1
  23. package/dist/generated/operations.generated.d.ts +56 -1
  24. package/dist/generated/operations.generated.js +10 -0
  25. package/dist/generated/operations.generated.js.map +1 -1
  26. package/dist/index.cjs +1 -0
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +4 -4
  29. package/dist/index.d.ts +4 -4
  30. package/dist/index.js +2 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/outputs.cjs +3 -2
  33. package/dist/outputs.cjs.map +1 -1
  34. package/dist/outputs.d.cts +3 -2
  35. package/dist/outputs.d.ts +3 -2
  36. package/dist/outputs.js +3 -2
  37. package/dist/outputs.js.map +1 -1
  38. package/dist/responseSchemas.cjs.map +1 -1
  39. package/dist/responseSchemas.d.cts +2 -2
  40. package/dist/responseSchemas.d.ts +2 -2
  41. package/dist/responseSchemas.js.map +1 -1
  42. package/dist/run/inputs.cjs.map +1 -1
  43. package/dist/run/inputs.d.cts +3 -3
  44. package/dist/run/inputs.d.ts +3 -3
  45. package/dist/run/inputs.js.map +1 -1
  46. package/package.json +2 -2
  47. package/src/authoring/raw.ts +12 -7
  48. package/src/client.ts +24 -1
  49. package/src/errors.ts +48 -17
  50. package/src/examples/continuationBridgeSettle.ts +100 -0
  51. package/src/examples/continuationSettle.ts +113 -0
  52. package/src/examples/run.ts +8 -0
  53. package/src/generated/config.generated.ts +109 -1
  54. package/src/generated/operations.generated.ts +98 -0
  55. package/src/index.ts +5 -1
  56. package/src/outputs.ts +3 -2
  57. package/src/responseSchemas.ts +9 -5
  58. package/src/run/inputs.ts +3 -3
@@ -0,0 +1,100 @@
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
+ const ARBITRUM = 42161;
14
+ const BASE = 8453;
15
+ const ARB_USDC = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
16
+ const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
17
+ // Aave V3 aToken for USDC on Base.
18
+ const A_BAS_USDC = '0x4e65fE4DbA92790696d040ac24Aa414708F5c0AB';
19
+ const VALIDITY_WINDOW_MS = 3_600_000;
20
+
21
+ export interface ContinuationBridgeSettleInput {
22
+ readonly owner: Address;
23
+ // Receives the aBasUSDC position on Base; defaults to `owner`.
24
+ readonly recipient?: Address;
25
+ }
26
+
27
+ /**
28
+ * Bridge USDC from Arbitrum to Base, and escrow the bridged USDC on Base for a
29
+ * deferred settlement that supplies it to Aave and delivers the aBasUSDC
30
+ * position to the recipient.
31
+ *
32
+ * Demonstrates:
33
+ * - `lifi.bridge` with no `destination`: its `amountOut` funds the settle's
34
+ * escrow on Base instead of landing at an address
35
+ * - `continuation.settle` bound to `bridge.amountOut` (delivered funding): the
36
+ * bridge delivers straight into the escrow, so the user signs one
37
+ * transaction on Arbitrum, and the settle must omit `funding` and
38
+ * `perpetual`
39
+ * - `validity.expiresAtMs` at least `max(3 × the bridge ETA, 30 minutes)` away
40
+ * - A leg on the escrow chain (Base) that does the work the user could not do
41
+ * from Arbitrum: `lifi.zap` supplies the landed USDC to Aave. The aBasUSDC
42
+ * stays in the leg's proxy; the settlement epilogue the composer appends at
43
+ * commit forwards it to the recipient
44
+ * - An outcome in a token the leg produces (aBasUSDC), not the funding token:
45
+ * the zap's slippage guard proves the floor, so `minAmount` is omitted
46
+ */
47
+ export const buildContinuationBridgeSettleExample = ({
48
+ owner,
49
+ recipient = owner,
50
+ }: ContinuationBridgeSettleInput): {
51
+ flow: Flow;
52
+ request: ComposeCompileRequest;
53
+ } => {
54
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
55
+
56
+ // The leg: runs from the escrow on Base once the bridged USDC has landed.
57
+ // The zap supplies the USDC to Aave; the aBasUSDC it mints lands in the
58
+ // leg's proxy, where the settlement epilogue picks it up. The slippage guard
59
+ // on `amountOut` is the enforced floor the compiler commits.
60
+ const leg = sdk.flow(BASE, {
61
+ name: 'bridge-settle-leg',
62
+ inputs: { funding: resources.erc20(BASE_USDC, BASE) },
63
+ });
64
+ leg.lifi.zap('supply', {
65
+ bind: { amountIn: leg.inputs.funding },
66
+ config: { resourceOut: resources.erc20(A_BAS_USDC, BASE) },
67
+ guards: [guards.slippage({ port: 'amountOut', bps: 50 })],
68
+ });
69
+
70
+ // The main flow on Arbitrum: bridge to Base, then escrow the delivery.
71
+ const builder = sdk.flow(ARBITRUM, {
72
+ name: 'bridge-and-settle',
73
+ inputs: { amountIn: resources.erc20(ARB_USDC, ARBITRUM) },
74
+ });
75
+ const bridge = builder.lifi.bridge('bridge', {
76
+ bind: { amountIn: builder.inputs.amountIn },
77
+ config: { resourceOut: resources.erc20(BASE_USDC, BASE) },
78
+ });
79
+ builder.continuation.settle('settle', {
80
+ bind: { input: bridge.amountOut },
81
+ config: {
82
+ outcomes: [{ token: A_BAS_USDC, destination: recipient, chainId: BASE }],
83
+ validity: { expiresAtMs: Date.now() + VALIDITY_WINDOW_MS },
84
+ provider: 'intent-factory',
85
+ refund: owner,
86
+ continuationFlow: leg.build(),
87
+ },
88
+ });
89
+
90
+ const flow = builder.build();
91
+
92
+ const request = sdk.request(flow, {
93
+ signer: owner,
94
+ inputs: {
95
+ amountIn: materialisers.directDeposit({ amount: '1000000000' }),
96
+ },
97
+ });
98
+
99
+ return { flow, request };
100
+ };
@@ -0,0 +1,113 @@
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
+ const BASE = 8453;
14
+ const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
15
+ const WETH = '0x4200000000000000000000000000000000000006';
16
+ // Aave V3 aToken for WETH on Base.
17
+ const A_BAS_WETH = '0xD4a0e0b9149BCee3C920d2E00b5dE09138fd8bb7';
18
+ const VALIDITY_WINDOW_MS = 3_600_000;
19
+
20
+ export interface ContinuationSettleInput {
21
+ readonly owner: Address;
22
+ // Receives the aBasWETH position; defaults to `owner`.
23
+ readonly recipient?: Address;
24
+ }
25
+
26
+ /**
27
+ * Swap USDC to WETH on Base, then escrow the WETH for a deferred settlement
28
+ * whose leg supplies it to Aave and delivers the aBasWETH position to the
29
+ * recipient.
30
+ *
31
+ * Demonstrates:
32
+ * - `continuation.settle` funded by an upstream output (`swap.amountOut`)
33
+ * - The leg (`continuationFlow`) as an ordinary flow built with `sdk.flow`
34
+ * and assigned with `leg.build()`: here one `lifi.zap` that supplies the
35
+ * escrowed WETH to Aave
36
+ * - An outcome in the token the leg produces (aBasWETH): the zap's slippage
37
+ * guard proves the floor, so `minAmount` is omitted
38
+ * - `refund` naming the address that receives the escrow balance on expiry
39
+ * and the leg's residual (optional; defaults to the signer)
40
+ *
41
+ * The leg contract:
42
+ * - Exactly one input: a resource input in the funding token on the escrow
43
+ * chain. The solver binds the escrow balance to it.
44
+ * - Produce each outcome into the leg's own proxy and end there. A zap or a
45
+ * deposit mints into the proxy by default; a node that needs a receiver
46
+ * binds `leg.context.executionAddress`. A funding input no node consumes
47
+ * stays in the proxy as the terminal `input.<name>`. Never
48
+ * pay a recipient: not `destination`, not the provider's settlement
49
+ * recipient, and never `context.sender` (inside the leg that is the
50
+ * settlement account, not the user). Never set the leg's own epilogue. At
51
+ * commit the composer appends the settlement epilogue, which forwards each
52
+ * outcome to the provider's recipient and the residual to `refund`.
53
+ * - Omit `funding` and `perpetual` when the settle input is a bridge's
54
+ * `amountOut` (see `continuationBridgeSettle.ts`).
55
+ * - `minAmount` is optional: a guard or an op floor on the outcome token
56
+ * proves it, and an unconsumed funding input proves the full funding floor.
57
+ */
58
+ export const buildContinuationSettleExample = ({
59
+ owner,
60
+ recipient = owner,
61
+ }: ContinuationSettleInput): {
62
+ flow: Flow;
63
+ request: ComposeCompileRequest;
64
+ } => {
65
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
66
+
67
+ // The leg: runs from the escrow on Base once the WETH has landed there. The
68
+ // zap supplies the WETH to Aave; the aBasWETH it mints lands in the leg's
69
+ // proxy, where the settlement epilogue picks it up. The slippage guard on
70
+ // `amountOut` is the enforced floor the compiler commits.
71
+ const leg = sdk.flow(BASE, {
72
+ name: 'settle-leg',
73
+ inputs: { funding: resources.erc20(WETH, BASE) },
74
+ });
75
+ leg.lifi.zap('supply', {
76
+ bind: { amountIn: leg.inputs.funding },
77
+ config: { resourceOut: resources.erc20(A_BAS_WETH, BASE) },
78
+ guards: [guards.slippage({ port: 'amountOut', bps: 50 })],
79
+ });
80
+
81
+ // The main flow: swap USDC to WETH, then escrow the WETH for the leg.
82
+ const builder = sdk.flow(BASE, {
83
+ name: 'swap-and-settle',
84
+ inputs: { amountIn: resources.erc20(USDC, BASE) },
85
+ });
86
+ const swap = builder.lifi.swap('swap', {
87
+ bind: { amountIn: builder.inputs.amountIn },
88
+ config: { resourceOut: resources.erc20(WETH, BASE) },
89
+ });
90
+ builder.continuation.settle('settle', {
91
+ bind: { input: swap.amountOut },
92
+ config: {
93
+ outcomes: [{ token: A_BAS_WETH, destination: recipient, chainId: BASE }],
94
+ validity: { expiresAtMs: Date.now() + VALIDITY_WINDOW_MS },
95
+ provider: 'intent-factory',
96
+ refund: owner,
97
+ continuationFlow: leg.build(),
98
+ },
99
+ });
100
+
101
+ const flow = builder.build();
102
+
103
+ // No `sweepTo`: the swap output funds the escrow and the settle output is
104
+ // delivered by the settlement, never landing in the VM.
105
+ const request = sdk.request(flow, {
106
+ signer: owner,
107
+ inputs: {
108
+ amountIn: materialisers.directDeposit({ amount: '1000000000' }),
109
+ },
110
+ });
111
+
112
+ return { flow, request };
113
+ };
@@ -16,6 +16,8 @@
16
16
  * approve-deposit — approve vault allowance then deposit USDC
17
17
  * consolidate — consolidate ERC-20 balances to USDC
18
18
  * consolidate-eth — consolidate ERC-20 balances to native ETH
19
+ * continuation-settle — swap USDC to WETH on Base, escrow it for a deferred settlement
20
+ * continuation-bridge-settle — bridge Arbitrum USDC into a Base settlement escrow
19
21
  * deposit-proxy — deposit tokens already on the proxy into Aave
20
22
  * dust-sweep — split USDC 80/20 and sweep leftover dust
21
23
  * swap — swap WETH to USDC via LI.FI
@@ -62,6 +64,8 @@ import { buildRedeemFromVault, buildWrapEth } from './callContract.js';
62
64
  import { API_KEY, BASE_URL, OWNER, PROXY, RECIPIENT } from './config.js';
63
65
  import { buildConsolidateToEth } from './consolidateToEth.js';
64
66
  import { buildConsolidateStablesToUsdc } from './consolidateToUsdc.js';
67
+ import { buildContinuationBridgeSettleExample } from './continuationBridgeSettle.js';
68
+ import { buildContinuationSettleExample } from './continuationSettle.js';
65
69
  import { buildDepositFromProxy } from './depositFromProxy.js';
66
70
  import { buildDustSweepExample } from './dustSweep.js';
67
71
  import { buildFlySwapExample } from './flySwap.js';
@@ -134,6 +138,10 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
134
138
  usdtAmount: '1000000000',
135
139
  daiAmount: '1000000000000000000000',
136
140
  }).request,
141
+ 'continuation-settle': () =>
142
+ buildContinuationSettleExample({ owner: OWNER }).request,
143
+ 'continuation-bridge-settle': () =>
144
+ buildContinuationBridgeSettleExample({ owner: OWNER }).request,
137
145
  'deposit-proxy': () =>
138
146
  buildDepositFromProxy({
139
147
  owner: OWNER,
@@ -1,6 +1,8 @@
1
1
  // AUTO-GENERATED from manifest.json — do not edit by hand.
2
2
  // Regenerate with: yarn workspace @lifi/composer-sdk generate
3
3
 
4
+ import type { Flow } from '@lifi/compose-spec';
5
+
4
6
  import type { Address, IntegerStringInput } from '../types.js';
5
7
 
6
8
  /**
@@ -253,7 +255,7 @@ export interface LifiBridgeConfig {
253
255
  token: Address;
254
256
  chainId: Positive;
255
257
  };
256
- destination: StartsWith0X;
258
+ destination?: StartsWith0X;
257
259
  slippage?: Between01;
258
260
  timing?: {
259
261
  swapStepTimingStrategies?: {
@@ -1278,6 +1280,54 @@ export interface FlySwapConfig {
1278
1280
  maxSlippageBps?: Between05000;
1279
1281
  }
1280
1282
 
1283
+ /**
1284
+ * a number between -8640000000000000 and 8640000000000000
1285
+ */
1286
+ export type Between86400000000000008640000000000000 = number;
1287
+
1288
+ export interface ContinuationSettleConfig {
1289
+ /**
1290
+ * @minItems 1
1291
+ */
1292
+ outcomes: [
1293
+ {
1294
+ /**
1295
+ * EVM address: 0x followed by 40 hex characters
1296
+ */
1297
+ token: Address;
1298
+ minAmount?: IntegerStringInput;
1299
+ /**
1300
+ * EVM address: 0x followed by 40 hex characters
1301
+ */
1302
+ destination: Address;
1303
+ chainId: Positive;
1304
+ },
1305
+ ...{
1306
+ /**
1307
+ * EVM address: 0x followed by 40 hex characters
1308
+ */
1309
+ token: Address;
1310
+ minAmount?: IntegerStringInput;
1311
+ /**
1312
+ * EVM address: 0x followed by 40 hex characters
1313
+ */
1314
+ destination: Address;
1315
+ chainId: Positive;
1316
+ }[],
1317
+ ];
1318
+ continuationFlow?: Flow;
1319
+ validity: {
1320
+ expiresAtMs: Between86400000000000008640000000000000;
1321
+ };
1322
+ perpetual?: boolean;
1323
+ provider?: string;
1324
+ funding?: 'inline' | 'external';
1325
+ /**
1326
+ * EVM address: 0x followed by 40 hex characters
1327
+ */
1328
+ refund?: Address;
1329
+ }
1330
+
1281
1331
  export interface UniswapV2AddLiquidityConfig {
1282
1332
  /**
1283
1333
  * EVM address: 0x followed by 40 hex characters
@@ -1355,6 +1405,64 @@ export interface UniswapV3IncreaseLiquidityConfig {
1355
1405
  tokenId: string;
1356
1406
  }
1357
1407
 
1408
+ /**
1409
+ * a number less than 1
1410
+ */
1411
+ export type LessThan1 = number;
1412
+ /**
1413
+ * a number between 1 and 300
1414
+ */
1415
+ export type Between1300 = number;
1416
+ /**
1417
+ * a number between 0 and 120
1418
+ */
1419
+ export type Between0120 = number;
1420
+
1421
+ export interface LifiIntentsOrderConfig {
1422
+ resourceOut:
1423
+ | {
1424
+ kind: 'native';
1425
+ chainId: Positive;
1426
+ }
1427
+ | {
1428
+ kind: 'erc20';
1429
+ /**
1430
+ * EVM address: 0x followed by 40 hex characters
1431
+ */
1432
+ token: Address;
1433
+ chainId: Positive;
1434
+ };
1435
+ destination?: StartsWith0X;
1436
+ slippage?: LessThan1;
1437
+ validitySeconds?: Between1300;
1438
+ exclusiveSeconds?: Between0120;
1439
+ }
1440
+
1441
+ export interface LifiIntentsRefundConfig {
1442
+ /**
1443
+ * The order id: lifiIntents.order's delivery.trackingId, or topic1 of the escrow's Open log
1444
+ */
1445
+ orderId: string;
1446
+ }
1447
+
1448
+ export interface LifiIntentsAttestNonFillConfig {
1449
+ /**
1450
+ * The order id: lifiIntents.order's delivery.trackingId, or topic1 of the escrow's Open log
1451
+ */
1452
+ orderId: string;
1453
+ }
1454
+
1455
+ export interface LifiIntentsRefundOnNonFillConfig {
1456
+ /**
1457
+ * The order id: lifiIntents.order's delivery.trackingId, or topic1 of the escrow's Open log
1458
+ */
1459
+ orderId: string;
1460
+ /**
1461
+ * The output-chain transaction of lifiIntents.attestNonFill
1462
+ */
1463
+ attestationTxHash: string;
1464
+ }
1465
+
1358
1466
  export interface SlippageGuardConfig {
1359
1467
  port: string;
1360
1468
  bps: Between010000;
@@ -27,6 +27,7 @@ import type {
27
27
  AaveRepayConfig,
28
28
  AaveRepayWithATokensConfig,
29
29
  AaveSetEModeConfig,
30
+ ContinuationSettleConfig,
30
31
  CoreApproveConfig,
31
32
  CoreAsResourceConfig,
32
33
  CoreBalanceOfConfig,
@@ -54,6 +55,10 @@ import type {
54
55
  InvariantNumericConfig,
55
56
  InvariantNumericInRangeConfig,
56
57
  LifiBridgeConfig,
58
+ LifiIntentsAttestNonFillConfig,
59
+ LifiIntentsOrderConfig,
60
+ LifiIntentsRefundConfig,
61
+ LifiIntentsRefundOnNonFillConfig,
57
62
  LifiSwapConfig,
58
63
  LifiZapAsyncConfig,
59
64
  LifiZapConfig,
@@ -668,6 +673,15 @@ export interface FlySwapArgs {
668
673
  readonly guards?: readonly TypedGuard<'unspentIn'>[];
669
674
  }
670
675
 
676
+ /** Fund a deferred settlement and commit to a future outcome */
677
+ export interface ContinuationSettleArgs {
678
+ readonly bind: {
679
+ readonly input: Bindable<'resource'>;
680
+ };
681
+ readonly config: ContinuationSettleConfig;
682
+ readonly guards?: readonly TypedGuard<never>[];
683
+ }
684
+
671
685
  /** Deposit two ERC-20 tokens into an existing Uniswap V2 pair (or an ABI-identical fork such as SushiSwap V2) through its Router02 and receive the pair's LP token; unused input returns as residuals. Asserts on chain that the router's factory is `factory`, that the factory's pair for the two tokens is `pair`, and that the pair holds non-zero reserves. Exposes the pool price read before the deposit as `poolPrice`. The deposit is protected only with a `band` guard on `poolPrice` and a `slippage` guard on `liquidity`. Fee-on-transfer tokens are unsupported. */
672
686
  export interface UniswapV2AddLiquidityArgs {
673
687
  readonly bind: {
@@ -715,6 +729,36 @@ export interface UniswapV3IncreaseLiquidityArgs {
715
729
  >[];
716
730
  }
717
731
 
732
+ /** Swap or bridge tokens through a LI.FI Intents order a solver fills */
733
+ export interface LifiIntentsOrderArgs {
734
+ readonly bind: {
735
+ readonly amountIn: Bindable<'resource'>;
736
+ };
737
+ readonly config: LifiIntentsOrderConfig;
738
+ readonly guards?: readonly TypedGuard<'unspentIn'>[];
739
+ }
740
+
741
+ /** Refund a LI.FI Intents escrow order after its expiry. Anyone may call; the escrow pays the order's user. Only an order the order server reports before delivery (status Open or Signed) is refunded. */
742
+ export interface LifiIntentsRefundArgs {
743
+ readonly bind: Record<string, never>;
744
+ readonly config: LifiIntentsRefundConfig;
745
+ readonly guards?: readonly TypedGuard<never>[];
746
+ }
747
+
748
+ /** Step 1 of the early refund of a cross-chain LI.FI Intents order: on the order's output chain, after its fill deadline, record that the output was not filled. Keep the transaction hash for lifiIntents.refundOnNonFill. */
749
+ export interface LifiIntentsAttestNonFillArgs {
750
+ readonly bind: Record<string, never>;
751
+ readonly config: LifiIntentsAttestNonFillConfig;
752
+ readonly guards?: readonly TypedGuard<never>[];
753
+ }
754
+
755
+ /** Step 2 of the early refund of a cross-chain LI.FI Intents order: on the order's input chain, prove the non-fill attestation through Polymer and refund the order's user. A resolution_error means the proof is not ready yet; retry. */
756
+ export interface LifiIntentsRefundOnNonFillArgs {
757
+ readonly bind: Record<string, never>;
758
+ readonly config: LifiIntentsRefundOnNonFillConfig;
759
+ readonly guards?: readonly TypedGuard<never>[];
760
+ }
761
+
718
762
  export interface CoreSplitOutputs {
719
763
  readonly a: OutputHandle<'resource'>;
720
764
  readonly b: OutputHandle<'resource'>;
@@ -872,6 +916,10 @@ export interface FlySwapOutputs {
872
916
  readonly unspentIn: OutputHandle<'resource'>;
873
917
  }
874
918
 
919
+ export interface ContinuationSettleOutputs {
920
+ readonly output: OutputHandle<'resource'>;
921
+ }
922
+
875
923
  export interface UniswapV2AddLiquidityOutputs {
876
924
  readonly liquidity: OutputHandle<'resource'>;
877
925
  readonly residualA: OutputHandle<'resource'>;
@@ -899,6 +947,11 @@ export interface UniswapV3IncreaseLiquidityOutputs {
899
947
  readonly residualB: OutputHandle<'resource'>;
900
948
  }
901
949
 
950
+ export interface LifiIntentsOrderOutputs {
951
+ readonly amountOut: OutputHandle<'resource'>;
952
+ readonly unspentIn: OutputHandle<'resource'>;
953
+ }
954
+
902
955
  export type GeneratedOps = {
903
956
  readonly core: {
904
957
  /** Split a resource into two outputs by basis-point ratio. Output `a` receives `bps` of the source, rounded up, and `b` takes the remainder. — original id: "core.split" */
@@ -1149,6 +1202,13 @@ export type GeneratedOps = {
1149
1202
  args: MorphoBlueGetPositionArgs,
1150
1203
  ) => MorphoBlueGetPositionOutputs;
1151
1204
  };
1205
+ readonly continuation: {
1206
+ /** Fund a deferred settlement and commit to a future outcome — original id: "continuation.settle" */
1207
+ readonly settle: (
1208
+ nodeId: string,
1209
+ args: ContinuationSettleArgs,
1210
+ ) => ContinuationSettleOutputs;
1211
+ };
1152
1212
  readonly paraswap: {
1153
1213
  /** Exact-output (BUY) swap via the Paraswap/Velora Market API: produce exactly `exactAmountOut` of the destination token, pulling only the source needed and exposing the genuinely-unspent source as `unspentIn`. — original id: "paraswap.buy" */
1154
1214
  readonly buy: (nodeId: string, args: ParaswapBuyArgs) => ParaswapBuyOutputs;
@@ -1181,6 +1241,25 @@ export type GeneratedOps = {
1181
1241
  args: UniswapV3IncreaseLiquidityArgs,
1182
1242
  ) => UniswapV3IncreaseLiquidityOutputs;
1183
1243
  };
1244
+ readonly lifiIntents: {
1245
+ /** Swap or bridge tokens through a LI.FI Intents order a solver fills — original id: "lifiIntents.order" */
1246
+ readonly order: (
1247
+ nodeId: string,
1248
+ args: LifiIntentsOrderArgs,
1249
+ ) => LifiIntentsOrderOutputs;
1250
+ /** Refund a LI.FI Intents escrow order after its expiry. Anyone may call; the escrow pays the order's user. Only an order the order server reports before delivery (status Open or Signed) is refunded. — original id: "lifiIntents.refund" */
1251
+ readonly refund: (nodeId: string, args: LifiIntentsRefundArgs) => void;
1252
+ /** Step 1 of the early refund of a cross-chain LI.FI Intents order: on the order's output chain, after its fill deadline, record that the output was not filled. Keep the transaction hash for lifiIntents.refundOnNonFill. — original id: "lifiIntents.attestNonFill" */
1253
+ readonly attestNonFill: (
1254
+ nodeId: string,
1255
+ args: LifiIntentsAttestNonFillArgs,
1256
+ ) => void;
1257
+ /** Step 2 of the early refund of a cross-chain LI.FI Intents order: on the order's input chain, prove the non-fill attestation through Polymer and refund the order's user. A resolution_error means the proof is not ready yet; retry. — original id: "lifiIntents.refundOnNonFill" */
1258
+ readonly refundOnNonFill: (
1259
+ nodeId: string,
1260
+ args: LifiIntentsRefundOnNonFillArgs,
1261
+ ) => void;
1262
+ };
1184
1263
  };
1185
1264
 
1186
1265
  export const bindGeneratedOps = (
@@ -1470,6 +1549,12 @@ export const bindGeneratedOps = (
1470
1549
  collateral: 'uint128',
1471
1550
  } as const),
1472
1551
  },
1552
+ continuation: {
1553
+ settle: (nodeId: string, args: ContinuationSettleArgs) =>
1554
+ builder.call(nodeId, 'continuation.settle', args, {
1555
+ output: 'resource',
1556
+ } as const),
1557
+ },
1473
1558
  paraswap: {
1474
1559
  buy: (nodeId: string, args: ParaswapBuyArgs) =>
1475
1560
  builder.call(nodeId, 'paraswap.buy', args, {
@@ -1515,4 +1600,17 @@ export const bindGeneratedOps = (
1515
1600
  residualB: 'resource',
1516
1601
  } as const),
1517
1602
  },
1603
+ lifiIntents: {
1604
+ order: (nodeId: string, args: LifiIntentsOrderArgs) =>
1605
+ builder.call(nodeId, 'lifiIntents.order', args, {
1606
+ amountOut: 'resource',
1607
+ unspentIn: 'resource',
1608
+ } as const),
1609
+ refund: (nodeId: string, args: LifiIntentsRefundArgs) =>
1610
+ builder.call(nodeId, 'lifiIntents.refund', args, {}),
1611
+ attestNonFill: (nodeId: string, args: LifiIntentsAttestNonFillArgs) =>
1612
+ builder.call(nodeId, 'lifiIntents.attestNonFill', args, {}),
1613
+ refundOnNonFill: (nodeId: string, args: LifiIntentsRefundOnNonFillArgs) =>
1614
+ builder.call(nodeId, 'lifiIntents.refundOnNonFill', args, {}),
1615
+ },
1518
1616
  });
package/src/index.ts CHANGED
@@ -51,6 +51,7 @@ export type {
51
51
  ComposeFill,
52
52
  ComposeFee,
53
53
  ComposeUserProgramSimulation,
54
+ ComposeWarning,
54
55
  ComposeCompileRequest,
55
56
  ComposeCompileResult,
56
57
  ComposeCompileSuccessData,
@@ -83,8 +84,10 @@ export type {
83
84
  RouteAmountExact,
84
85
  SimulationPolicy,
85
86
  SimulationRevert,
87
+ DeliveryErrorDetails,
88
+ DeliveryErrorReason,
86
89
  SolType,
87
- SweepTo,
90
+ ForwardTo,
88
91
  SimulateRequest,
89
92
  SimulateResult,
90
93
  SimulateOkResult,
@@ -107,6 +110,7 @@ export {
107
110
  SIMULATE_MAX_REQUIREMENTS,
108
111
  } from '@lifi/compose-spec';
109
112
  export {
113
+ isComposeDeliveryError,
110
114
  isComposeError,
111
115
  isComposePreparationError,
112
116
  isComposeSdkOutdatedError,
package/src/outputs.ts CHANGED
@@ -2,8 +2,9 @@ import type { Outputs, TerminalOutput } from '@lifi/compose-spec';
2
2
 
3
3
  /**
4
4
  * The entries of `outputs` the caller actually receives: every port no later
5
- * node spends, keyed `<nodeId>.<portName>` as on the wire. Consumed ports
6
- * (intermediate amounts a later op takes as input) are dropped.
5
+ * node spends, keyed `<nodeId>.<portName>` as on the wire, and every resource
6
+ * input no node spends, keyed `input.<name>`. Consumed ports (intermediate
7
+ * amounts a later op takes as input) are dropped.
7
8
  */
8
9
  export const terminalOutputs = (
9
10
  outputs: Outputs,
@@ -1,4 +1,8 @@
1
- import type { SimulateResult, SimulationRevert } from '@lifi/compose-spec';
1
+ import type {
2
+ DeliveryErrorDetails,
3
+ SimulateResult,
4
+ SimulationRevert,
5
+ } from '@lifi/compose-spec';
2
6
  import z from 'zod';
3
7
 
4
8
  /**
@@ -138,7 +142,7 @@ export interface ServerErrorBody {
138
142
  readonly sdkVersion?: string;
139
143
  readonly serverVersion?: string;
140
144
  readonly minimumSdkVersion?: string;
141
- readonly details?: SimulationRevert;
145
+ readonly details?: SimulationRevert | DeliveryErrorDetails;
142
146
  readonly failedOps?: readonly ServerFailedPreparedOp[];
143
147
  readonly succeededOps?: readonly string[];
144
148
  };
@@ -155,8 +159,8 @@ const failedPreparedOpSchema = z.object({
155
159
  });
156
160
 
157
161
  // `details` is passed through (`z.custom`) rather than parsed: the SDK does not
158
- // own the `SimulationRevert` schema and forwards the field verbatim onto
159
- // `ComposeError`.
162
+ // own the `SimulationRevert` or `DeliveryErrorDetails` schemas and forwards
163
+ // the field verbatim onto `ComposeError`.
160
164
  //
161
165
  // `failedOps`/`succeededOps` are optional here because every error kind shares
162
166
  // this envelope; they are only populated for `preparation_error` (422). Zod
@@ -174,7 +178,7 @@ const serverErrorBodySchema = z.object({
174
178
  sdkVersion: z.string().optional(),
175
179
  serverVersion: z.string().optional(),
176
180
  minimumSdkVersion: z.string().optional(),
177
- details: z.custom<SimulationRevert>().optional(),
181
+ details: z.custom<SimulationRevert | DeliveryErrorDetails>().optional(),
178
182
  failedOps: z.array(failedPreparedOpSchema).readonly().optional(),
179
183
  succeededOps: z.array(z.string()).readonly().optional(),
180
184
  })
package/src/run/inputs.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import type {
2
2
  ComposeRun,
3
+ ForwardTo,
3
4
  InputSpec,
4
5
  MaterialiserInput,
5
6
  Precondition,
6
7
  SimulationPolicy,
7
- SweepTo,
8
8
  } from '@lifi/compose-spec';
9
9
 
10
10
  import type { Address, InputSchema, InputSpecOf } from '../types.js';
@@ -47,7 +47,7 @@ export interface ComposeRunInput<T extends InputSchema = InputSchema> {
47
47
  * Pass a literal `0x`-prefixed address or `{ $ref: "context.sender" }` to
48
48
  * send remaining tokens to the signer.
49
49
  */
50
- readonly sweepTo?: SweepTo;
50
+ readonly sweepTo?: ForwardTo;
51
51
  /**
52
52
  * Controls behavior when simulation detects a revert.
53
53
  * `'strict'` (default) returns an error; `'allow-revert'` returns a partial
@@ -125,7 +125,7 @@ export const buildRun = (run: {
125
125
  referrer?: string;
126
126
  integratorFeeBps?: number;
127
127
  maxPriceImpactBps?: number;
128
- sweepTo?: SweepTo;
128
+ sweepTo?: ForwardTo;
129
129
  simulationPolicy?: SimulationPolicy;
130
130
  simulateUserProgram?: boolean;
131
131
  checkOnChainAllowances?: boolean;