@lifi/composer-sdk 0.6.3 → 0.7.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 (38) hide show
  1. package/README.md +4 -0
  2. package/dist/authoring/FlowBuilderCore.cjs +17 -4
  3. package/dist/authoring/FlowBuilderCore.cjs.map +1 -1
  4. package/dist/authoring/FlowBuilderCore.d.cts +12 -4
  5. package/dist/authoring/FlowBuilderCore.d.ts +12 -4
  6. package/dist/authoring/FlowBuilderCore.js +20 -4
  7. package/dist/authoring/FlowBuilderCore.js.map +1 -1
  8. package/dist/authoring/handles.cjs.map +1 -1
  9. package/dist/authoring/handles.d.cts +35 -1
  10. package/dist/authoring/handles.d.ts +35 -1
  11. package/dist/authoring/handles.js.map +1 -1
  12. package/dist/client.cjs +1 -1
  13. package/dist/client.js +1 -1
  14. package/dist/generated/config.generated.cjs.map +1 -1
  15. package/dist/generated/config.generated.d.cts +500 -6
  16. package/dist/generated/config.generated.d.ts +500 -6
  17. package/dist/generated/operations.generated.cjs +36 -1
  18. package/dist/generated/operations.generated.cjs.map +1 -1
  19. package/dist/generated/operations.generated.d.cts +101 -5
  20. package/dist/generated/operations.generated.d.ts +101 -5
  21. package/dist/generated/operations.generated.js +36 -1
  22. package/dist/generated/operations.generated.js.map +1 -1
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +3 -3
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js.map +1 -1
  27. package/package.json +3 -3
  28. package/src/authoring/FlowBuilderCore.ts +59 -19
  29. package/src/authoring/handles.ts +67 -0
  30. package/src/examples/aaveBorrow.ts +129 -0
  31. package/src/examples/aaveHealthFactorExplode.ts +63 -0
  32. package/src/examples/morphoBlueBorrow.ts +94 -0
  33. package/src/examples/morphoBlueRepay.ts +133 -0
  34. package/src/examples/run.ts +30 -0
  35. package/src/examples/splitAndZap.ts +9 -8
  36. package/src/generated/config.generated.ts +516 -5
  37. package/src/generated/operations.generated.ts +211 -3
  38. package/src/index.ts +5 -1
package/dist/index.d.cts CHANGED
@@ -2,8 +2,8 @@ export { AbiTypeToOutputKind, Address, InputDecl, InputSchema, InputSpecOf, Inte
2
2
  export { ChainSummary, GetZapPacksOptions, ZapPackEdge, ZapPackOverview } from './discovery.cjs';
3
3
  export { Reachability, ReachabilityOptions, RoutablePair, TokenRef, buildReachability } from './reachability.cjs';
4
4
  export { ComposeError, ComposeErrorCode, ComposePreparationOps, ComposeSdkOutdated, ComposeServerOutdated, isComposeError, isComposePreparationError, isComposeSdkOutdatedError, isComposeServerOutdatedError } from './errors.cjs';
5
- export { Amount, AppliedGuard, ApprovalEntry, Call, Check, CheckComparator, ComposeAction, ComposeCompilePartialData, ComposeCompileRequest, ComposeCompileResult, ComposeCompileSuccessData, ComposeErrorKind, ComposeFee, ComposeFill, ComposeRouteRequest, ComposeTransactionRequest, ComposeUserProgramSimulation, ConsumedOutput, ContinuationIntent, ContinuationOutcome, ContinuationPlanWire, Delivery, Erc20AllowanceRequirement, Erc20BalanceRequirement, Estimate, EstimateBasis, FailedPreparedOp, Flow, InputSpec, MaterialiserConfigOf, MaterialiserInput, Minimum, MinimumBasis, NativeBalanceRequirement, Output, OutputAmount, Outputs, Phase1ArtifactWire, Precondition, PreconditionConfigOf, PriceImpact, Ref, Resource, RouteAmount, RouteAmountAll, RouteAmountExact, SIMULATE_MAX_REQUIREMENTS, SIMULATE_MAX_TRACKED_BALANCES, SimulateBalanceEntry, SimulateOkResult, SimulateRequest, SimulateResult, SimulateRevertDecodeResult, SimulateRevertResult, SimulateSetupErrorResult, SimulationPolicy, SimulationRevert, SlotFinderRequirement, SolType, SweepTo, TerminalOutput, TrackedBalance } from '@lifi/compose-spec';
6
- export { AnyHandle, AnyRefBindable, Bindable, InputHandle, OutputHandle, RefBindable, ResourceInputHandle, isInputHandle, isOutputHandle } from './authoring/handles.cjs';
5
+ export { Amount, AppliedGuard, ApprovalEntry, Call, Check, CheckComparator, ComposeAction, ComposeCompilePartialData, ComposeCompileRequest, ComposeCompileResult, ComposeCompileSuccessData, ComposeErrorKind, ComposeFee, ComposeFill, ComposeRouteRequest, ComposeTransactionRequest, ComposeUserProgramSimulation, ConsumedOutput, ContinuationIntent, ContinuationOutcome, ContinuationPlanWire, Delivery, Erc20AllowanceRequirement, Erc20BalanceRequirement, Estimate, EstimateBasis, FailedPreparedOp, Flow, InputSpec, MaterialiserConfigOf, MaterialiserInput, Minimum, MinimumBasis, NativeBalanceRequirement, Output, OutputAmount, Outputs, Precondition, PreconditionConfigOf, PriceImpact, Ref, Resource, RouteAmount, RouteAmountAll, RouteAmountExact, SIMULATE_MAX_REQUIREMENTS, SIMULATE_MAX_TRACKED_BALANCES, SettlementEscrowWire, SettlementWire, SimulateBalanceEntry, SimulateOkResult, SimulateRequest, SimulateResult, SimulateRevertDecodeResult, SimulateRevertResult, SimulateSetupErrorResult, SimulationPolicy, SimulationRevert, SlotFinderRequirement, SolType, SweepTo, TerminalOutput, TrackedBalance } from '@lifi/compose-spec';
6
+ export { AnyHandle, AnyRefBindable, Bindable, FamilyCount, FamilySource, InputHandle, OutputFamilyHandles, OutputHandle, RefBindable, ResourceInputHandle, isInputHandle, isOutputHandle } from './authoring/handles.cjs';
7
7
  export { ref } from './authoring/raw.cjs';
8
8
  export { AnyBindable, FlowOptions, TypedFlow } from './authoring/FlowBuilderCore.cjs';
9
9
  export { ComposeRunInput, materialiser } from './run/inputs.cjs';
@@ -16,7 +16,7 @@ import { p as preconditionsMod } from './preconditions.generated-DblS13Wq.cjs';
16
16
  import { r as rawMod } from './raw-s1rer8X3.cjs';
17
17
  import { r as resourcesMod } from './resources-BKlFxjo8.cjs';
18
18
  import { r as routeAmountMod } from './routeAmount-DdbJYJyM.cjs';
19
- export { AaveBorrowConfig, AaveClaimRewardsConfig, AaveGetHealthFactorConfig, AaveRepayConfig, AaveRepayWithATokensConfig, AaveSetEModeConfig, BalanceOfMaterialiserConfig, Between01, Between010000, Between0255, Between03318, Between05000, CallMaterialiserConfig, ContinuationAssertReadyConfig, CoreApproveConfig, CoreAsResourceConfig, CoreBalanceOfConfig, CoreBpsDownConfig, CoreBpsUpConfig, CoreCallConfig, CoreEmitEvent1Config, CoreEmitEvent2Config, CoreEmitEvent3Config, CoreEmitEvent4Config, CoreInvokeConfig, CoreNumericInvariantGuardConfig, CorePeekConfig, CoreRawCallConfig, CoreSplitConfig, CoreStaticCallConfig, CoreTransferConfig, DirectDepositMaterialiserConfig, Erc20AllowancePreconditionConfig, Erc20BalancePreconditionConfig, FlashloanMaterialiserConfig, FlySwapConfig, InvariantEqConfig, InvariantGtConfig, InvariantGteConfig, InvariantLtConfig, InvariantLteConfig, InvariantNeqConfig, InvariantNumericConfig, InvariantNumericInRangeConfig, LifiBridgeConfig, LifiFlashloanRepayConfig, LifiSwapConfig, LifiZapAsyncConfig, LifiZapConfig, MaxItems50, MaxLength64, MaxLength65536, MorphoBlueBorrowConfig, MorphoBlueGetPositionConfig, MorphoBlueRepayConfig, MorphoBlueSupplyCollateralConfig, MorphoBlueSupplyConfig, MorphoBlueWithdrawCollateralConfig, MorphoBlueWithdrawConfig, NativeBalancePreconditionConfig, NonNegative, ParaswapBuyConfig, Positive, SlippageGuardConfig, StartsWith0X } from './generated/config.generated.cjs';
19
+ export { AaveBorrowConfig, AaveClaimRewardsConfig, AaveGetHealthFactorConfig, AaveRepayConfig, AaveRepayWithATokensConfig, AaveSetEModeConfig, BalanceOfMaterialiserConfig, Between01, Between010000, Between0255, Between03318, Between05000, Between19999, CallMaterialiserConfig, ContinuationAssertReadyConfig, CoreApproveConfig, CoreAsResourceConfig, CoreBalanceOfConfig, CoreBpsDownConfig, CoreBpsUpConfig, CoreCallConfig, CoreEmitEvent1Config, CoreEmitEvent2Config, CoreEmitEvent3Config, CoreEmitEvent4Config, CoreInvokeConfig, CoreNumericInvariantGuardConfig, CorePartitionConfig, CorePeekConfig, CoreRawCallConfig, CoreSplitConfig, CoreStaticCallConfig, CoreTransferConfig, DirectDepositMaterialiserConfig, Erc20AllowancePreconditionConfig, Erc20BalancePreconditionConfig, FlashloanMaterialiserConfig, FlySwapConfig, InvariantEqConfig, InvariantGtConfig, InvariantGteConfig, InvariantLtConfig, InvariantLteConfig, InvariantNeqConfig, InvariantNumericConfig, InvariantNumericInRangeConfig, LifiBridgeConfig, LifiFlashloanRepayConfig, LifiSwapConfig, LifiZapAsyncConfig, LifiZapConfig, MaxItems16, MaxItems50, MaxLength64, MaxLength65536, MorphoBlueBorrowConfig, MorphoBlueGetPositionConfig, MorphoBlueRepayConfig, MorphoBlueSupplyCollateralConfig, MorphoBlueSupplyConfig, MorphoBlueWithdrawCollateralConfig, MorphoBlueWithdrawConfig, NativeBalancePreconditionConfig, NonNegative, ParaswapBuyConfig, Positive, SlippageGuardConfig, StartsWith0X } from './generated/config.generated.cjs';
20
20
  import './client.cjs';
21
21
  import './generated/operations.generated.cjs';
22
22
  import './authoring/signatureArgs.cjs';
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ export { AbiTypeToOutputKind, Address, InputDecl, InputSchema, InputSpecOf, Inte
2
2
  export { ChainSummary, GetZapPacksOptions, ZapPackEdge, ZapPackOverview } from './discovery.js';
3
3
  export { Reachability, ReachabilityOptions, RoutablePair, TokenRef, buildReachability } from './reachability.js';
4
4
  export { ComposeError, ComposeErrorCode, ComposePreparationOps, ComposeSdkOutdated, ComposeServerOutdated, isComposeError, isComposePreparationError, isComposeSdkOutdatedError, isComposeServerOutdatedError } from './errors.js';
5
- export { Amount, AppliedGuard, ApprovalEntry, Call, Check, CheckComparator, ComposeAction, ComposeCompilePartialData, ComposeCompileRequest, ComposeCompileResult, ComposeCompileSuccessData, ComposeErrorKind, ComposeFee, ComposeFill, ComposeRouteRequest, ComposeTransactionRequest, ComposeUserProgramSimulation, ConsumedOutput, ContinuationIntent, ContinuationOutcome, ContinuationPlanWire, Delivery, Erc20AllowanceRequirement, Erc20BalanceRequirement, Estimate, EstimateBasis, FailedPreparedOp, Flow, InputSpec, MaterialiserConfigOf, MaterialiserInput, Minimum, MinimumBasis, NativeBalanceRequirement, Output, OutputAmount, Outputs, Phase1ArtifactWire, Precondition, PreconditionConfigOf, PriceImpact, Ref, Resource, RouteAmount, RouteAmountAll, RouteAmountExact, SIMULATE_MAX_REQUIREMENTS, SIMULATE_MAX_TRACKED_BALANCES, SimulateBalanceEntry, SimulateOkResult, SimulateRequest, SimulateResult, SimulateRevertDecodeResult, SimulateRevertResult, SimulateSetupErrorResult, SimulationPolicy, SimulationRevert, SlotFinderRequirement, SolType, SweepTo, TerminalOutput, TrackedBalance } from '@lifi/compose-spec';
6
- export { AnyHandle, AnyRefBindable, Bindable, InputHandle, OutputHandle, RefBindable, ResourceInputHandle, isInputHandle, isOutputHandle } from './authoring/handles.js';
5
+ export { Amount, AppliedGuard, ApprovalEntry, Call, Check, CheckComparator, ComposeAction, ComposeCompilePartialData, ComposeCompileRequest, ComposeCompileResult, ComposeCompileSuccessData, ComposeErrorKind, ComposeFee, ComposeFill, ComposeRouteRequest, ComposeTransactionRequest, ComposeUserProgramSimulation, ConsumedOutput, ContinuationIntent, ContinuationOutcome, ContinuationPlanWire, Delivery, Erc20AllowanceRequirement, Erc20BalanceRequirement, Estimate, EstimateBasis, FailedPreparedOp, Flow, InputSpec, MaterialiserConfigOf, MaterialiserInput, Minimum, MinimumBasis, NativeBalanceRequirement, Output, OutputAmount, Outputs, Precondition, PreconditionConfigOf, PriceImpact, Ref, Resource, RouteAmount, RouteAmountAll, RouteAmountExact, SIMULATE_MAX_REQUIREMENTS, SIMULATE_MAX_TRACKED_BALANCES, SettlementEscrowWire, SettlementWire, SimulateBalanceEntry, SimulateOkResult, SimulateRequest, SimulateResult, SimulateRevertDecodeResult, SimulateRevertResult, SimulateSetupErrorResult, SimulationPolicy, SimulationRevert, SlotFinderRequirement, SolType, SweepTo, TerminalOutput, TrackedBalance } from '@lifi/compose-spec';
6
+ export { AnyHandle, AnyRefBindable, Bindable, FamilyCount, FamilySource, InputHandle, OutputFamilyHandles, OutputHandle, RefBindable, ResourceInputHandle, isInputHandle, isOutputHandle } from './authoring/handles.js';
7
7
  export { ref } from './authoring/raw.js';
8
8
  export { AnyBindable, FlowOptions, TypedFlow } from './authoring/FlowBuilderCore.js';
9
9
  export { ComposeRunInput, materialiser } from './run/inputs.js';
@@ -16,7 +16,7 @@ import { p as preconditionsMod } from './preconditions.generated-U7YpVh30.js';
16
16
  import { r as rawMod } from './raw-BvRghN3r.js';
17
17
  import { r as resourcesMod } from './resources-CYis1_DS.js';
18
18
  import { r as routeAmountMod } from './routeAmount-DdbJYJyM.js';
19
- export { AaveBorrowConfig, AaveClaimRewardsConfig, AaveGetHealthFactorConfig, AaveRepayConfig, AaveRepayWithATokensConfig, AaveSetEModeConfig, BalanceOfMaterialiserConfig, Between01, Between010000, Between0255, Between03318, Between05000, CallMaterialiserConfig, ContinuationAssertReadyConfig, CoreApproveConfig, CoreAsResourceConfig, CoreBalanceOfConfig, CoreBpsDownConfig, CoreBpsUpConfig, CoreCallConfig, CoreEmitEvent1Config, CoreEmitEvent2Config, CoreEmitEvent3Config, CoreEmitEvent4Config, CoreInvokeConfig, CoreNumericInvariantGuardConfig, CorePeekConfig, CoreRawCallConfig, CoreSplitConfig, CoreStaticCallConfig, CoreTransferConfig, DirectDepositMaterialiserConfig, Erc20AllowancePreconditionConfig, Erc20BalancePreconditionConfig, FlashloanMaterialiserConfig, FlySwapConfig, InvariantEqConfig, InvariantGtConfig, InvariantGteConfig, InvariantLtConfig, InvariantLteConfig, InvariantNeqConfig, InvariantNumericConfig, InvariantNumericInRangeConfig, LifiBridgeConfig, LifiFlashloanRepayConfig, LifiSwapConfig, LifiZapAsyncConfig, LifiZapConfig, MaxItems50, MaxLength64, MaxLength65536, MorphoBlueBorrowConfig, MorphoBlueGetPositionConfig, MorphoBlueRepayConfig, MorphoBlueSupplyCollateralConfig, MorphoBlueSupplyConfig, MorphoBlueWithdrawCollateralConfig, MorphoBlueWithdrawConfig, NativeBalancePreconditionConfig, NonNegative, ParaswapBuyConfig, Positive, SlippageGuardConfig, StartsWith0X } from './generated/config.generated.js';
19
+ export { AaveBorrowConfig, AaveClaimRewardsConfig, AaveGetHealthFactorConfig, AaveRepayConfig, AaveRepayWithATokensConfig, AaveSetEModeConfig, BalanceOfMaterialiserConfig, Between01, Between010000, Between0255, Between03318, Between05000, Between19999, CallMaterialiserConfig, ContinuationAssertReadyConfig, CoreApproveConfig, CoreAsResourceConfig, CoreBalanceOfConfig, CoreBpsDownConfig, CoreBpsUpConfig, CoreCallConfig, CoreEmitEvent1Config, CoreEmitEvent2Config, CoreEmitEvent3Config, CoreEmitEvent4Config, CoreInvokeConfig, CoreNumericInvariantGuardConfig, CorePartitionConfig, CorePeekConfig, CoreRawCallConfig, CoreSplitConfig, CoreStaticCallConfig, CoreTransferConfig, DirectDepositMaterialiserConfig, Erc20AllowancePreconditionConfig, Erc20BalancePreconditionConfig, FlashloanMaterialiserConfig, FlySwapConfig, InvariantEqConfig, InvariantGtConfig, InvariantGteConfig, InvariantLtConfig, InvariantLteConfig, InvariantNeqConfig, InvariantNumericConfig, InvariantNumericInRangeConfig, LifiBridgeConfig, LifiFlashloanRepayConfig, LifiSwapConfig, LifiZapAsyncConfig, LifiZapConfig, MaxItems16, MaxItems50, MaxLength64, MaxLength65536, MorphoBlueBorrowConfig, MorphoBlueGetPositionConfig, MorphoBlueRepayConfig, MorphoBlueSupplyCollateralConfig, MorphoBlueSupplyConfig, MorphoBlueWithdrawCollateralConfig, MorphoBlueWithdrawConfig, NativeBalancePreconditionConfig, NonNegative, ParaswapBuyConfig, Positive, SlippageGuardConfig, StartsWith0X } from './generated/config.generated.js';
20
20
  import './client.js';
21
21
  import './generated/operations.generated.js';
22
22
  import './authoring/signatureArgs.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@lifi/composer-sdk` — TypeScript SDK for building and compiling\n * Compose flows into executable EVM calldata.\n *\n * Start by creating an SDK instance with {@link createComposeSdk}, then use\n * {@link ComposeSdk.flow} to build flows and compile them.\n *\n * @packageDocumentation\n */\n\nexport type {\n AbiTypeToOutputKind,\n Address,\n InputDecl,\n InputSchema,\n InputSpecOf,\n IntegerString,\n IntegerStringInput,\n OutputKind,\n TypedGuard,\n TypedRef,\n TypedLiteral,\n} from './types.js';\n\nexport type {\n ChainSummary,\n GetZapPacksOptions,\n ZapPackEdge,\n ZapPackOverview,\n} from './discovery.js';\nexport type {\n Reachability,\n ReachabilityOptions,\n RoutablePair,\n TokenRef,\n} from './reachability.js';\nexport { buildReachability } from './reachability.js';\nexport type {\n ComposeError,\n ComposeErrorCode,\n ComposeSdkOutdated,\n ComposeServerOutdated,\n ComposePreparationOps,\n} from './errors.js';\nexport type {\n AppliedGuard,\n ApprovalEntry,\n Call,\n ComposeCompilePartialData,\n ComposeAction,\n ComposeFill,\n ComposeFee,\n ComposeUserProgramSimulation,\n ComposeCompileRequest,\n ComposeCompileResult,\n ComposeCompileSuccessData,\n ComposeErrorKind,\n ComposeRouteRequest,\n ComposeTransactionRequest,\n FailedPreparedOp,\n Flow,\n InputSpec,\n MaterialiserConfigOf,\n MaterialiserInput,\n OutputAmount,\n Amount,\n ConsumedOutput,\n Delivery,\n Estimate,\n EstimateBasis,\n Minimum,\n MinimumBasis,\n Output,\n Outputs,\n TerminalOutput,\n Precondition,\n PreconditionConfigOf,\n PriceImpact,\n Ref,\n Resource,\n RouteAmount,\n RouteAmountAll,\n RouteAmountExact,\n SimulationPolicy,\n SimulationRevert,\n SolType,\n SweepTo,\n SimulateRequest,\n SimulateResult,\n SimulateOkResult,\n SimulateRevertResult,\n SimulateRevertDecodeResult,\n SimulateSetupErrorResult,\n SimulateBalanceEntry,\n TrackedBalance,\n SlotFinderRequirement,\n Erc20BalanceRequirement,\n NativeBalanceRequirement,\n Erc20AllowanceRequirement,\n ContinuationIntent,\n ContinuationOutcome,\n Check,\n CheckComparator,\n Phase1ArtifactWire,\n ContinuationPlanWire,\n} from '@lifi/compose-spec';\nexport {\n SIMULATE_MAX_TRACKED_BALANCES,\n SIMULATE_MAX_REQUIREMENTS,\n} from '@lifi/compose-spec';\nexport {\n isComposeError,\n isComposePreparationError,\n isComposeSdkOutdatedError,\n isComposeServerOutdatedError,\n} from './errors.js';\n\nexport type {\n Bindable,\n RefBindable,\n AnyRefBindable,\n InputHandle,\n ResourceInputHandle,\n OutputHandle,\n AnyHandle,\n} from './authoring/handles.js';\nexport { isInputHandle, isOutputHandle } from './authoring/handles.js';\nexport { ref } from './authoring/raw.js';\n\nexport type { AnyBindable } from './authoring/FlowBuilderCore.js';\nexport type { TypedFlow, FlowOptions } from './authoring/FlowBuilderCore.js';\n\nexport type { ComposeRunInput } from './run/inputs.js';\nexport { materialiser } from './run/inputs.js';\n\nexport { buildSimulateRequest } from './run/simulate.js';\nexport type { BuildSimulateRequestInput } from './run/simulate.js';\n\nexport { terminalOutputs } from './outputs.js';\n\nexport { createComposeSdk } from './sdk.js';\nexport type { ComposeSdk, ComposeSdkOptions, FlowBuilder } from './sdk.js';\n\nimport * as guardsMod from './generated/guards.generated.js';\nimport * as materialisersMod from './generated/materialisers.generated.js';\nimport * as preconditionsMod from './generated/preconditions.generated.js';\nimport * as rawMod from './raw.js';\nimport * as resourcesMod from './resources.js';\nimport * as routeAmountMod from './routeAmount.js';\n\n/**\n * Guard factories for protecting operation outputs (e.g. slippage tolerance).\n * Pass guards to an operation's `guards` array.\n *\n * @example\n * ```ts\n * builder.lifi.swap('swap1', {\n * bind: { amountIn: builder.inputs.token },\n * config: { resourceOut: resources.native(1) },\n * guards: [guards.slippage({ port: 'amountOut', bps: 300 })],\n * });\n * ```\n */\nexport const guards: typeof guardsMod = guardsMod;\n/**\n * Materialiser factories that tell the runtime how to resolve token input\n * amounts on-chain (e.g. read a wallet balance, accept a direct deposit).\n *\n * @example\n * ```ts\n * await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * signer: '0x...',\n * });\n * ```\n */\nexport const materialisers: typeof materialisersMod = materialisersMod;\n/**\n * Precondition factories for asserting on-chain state before a flow executes\n * (e.g. minimum token balances, ERC-20 allowances).\n *\n * @example\n * ```ts\n * await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * preconditions: [\n * preconditions.erc20Balance({ wallet: '0x...', token: '0x...', balance: 1000n }),\n * ],\n * signer: '0x...',\n * });\n * ```\n */\nexport const preconditions: typeof preconditionsMod = preconditionsMod;\n/**\n * Resource declaration helpers for defining token inputs in a flow schema.\n * Use {@link resources.erc20} for ERC-20 tokens and {@link resources.native}\n * for the chain's native coin (ETH, MATIC, etc.).\n *\n * @example\n * ```ts\n * const builder = sdk.flow(1, {\n * inputs: {\n * usdc: resources.erc20('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 1),\n * eth: resources.native(1),\n * },\n * });\n * ```\n */\nexport const resources: typeof resourcesMod = resourcesMod;\n/**\n * Amount constructors for {@link ComposeSdk.route}. Use\n * {@link routeAmount.exact} to spend a fixed amount of the `fromToken`, and\n * {@link routeAmount.all} to spend the signer's whole balance.\n *\n * @example\n * ```ts\n * // USDC into the Aave v3 aEthUSDC position — one routing-catalog edge.\n * const result = await sdk.route({\n * chainId: 1,\n * fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n * toToken: '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c',\n * amount: routeAmount.exact(1_000_000n),\n * signer: '0xYourAddress...',\n * });\n * ```\n */\nexport const routeAmount: typeof routeAmountMod = routeAmountMod;\nexport * from './generated/config.generated.js';\n\n/**\n * Low-level escape hatch for constructing flow nodes, guards, and materialiser\n * inputs without the typed builder API. Prefer the generated operation methods\n * on {@link FlowBuilder} and the typed `guards`/`materialisers` namespaces\n * for most use cases.\n */\nexport const raw: typeof rawMod = rawMod;\n"],"mappings":"AAoCA,SAAS,yBAAyB;AAsElC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWP,SAAS,eAAe,sBAAsB;AAC9C,SAAS,WAAW;AAMpB,SAAS,oBAAoB;AAE7B,SAAS,4BAA4B;AAGrC,SAAS,uBAAuB;AAEhC,SAAS,wBAAwB;AAGjC,YAAY,eAAe;AAC3B,YAAY,sBAAsB;AAClC,YAAY,sBAAsB;AAClC,YAAY,YAAY;AACxB,YAAY,kBAAkB;AAC9B,YAAY,oBAAoB;AAezB,MAAM,SAA2B;AAajC,MAAM,gBAAyC;AAgB/C,MAAM,gBAAyC;AAgB/C,MAAM,YAAiC;AAkBvC,MAAM,cAAqC;AAClD,cAAc;AAQP,MAAM,MAAqB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@lifi/composer-sdk` — TypeScript SDK for building and compiling\n * Compose flows into executable EVM calldata.\n *\n * Start by creating an SDK instance with {@link createComposeSdk}, then use\n * {@link ComposeSdk.flow} to build flows and compile them.\n *\n * @packageDocumentation\n */\n\nexport type {\n AbiTypeToOutputKind,\n Address,\n InputDecl,\n InputSchema,\n InputSpecOf,\n IntegerString,\n IntegerStringInput,\n OutputKind,\n TypedGuard,\n TypedRef,\n TypedLiteral,\n} from './types.js';\n\nexport type {\n ChainSummary,\n GetZapPacksOptions,\n ZapPackEdge,\n ZapPackOverview,\n} from './discovery.js';\nexport type {\n Reachability,\n ReachabilityOptions,\n RoutablePair,\n TokenRef,\n} from './reachability.js';\nexport { buildReachability } from './reachability.js';\nexport type {\n ComposeError,\n ComposeErrorCode,\n ComposeSdkOutdated,\n ComposeServerOutdated,\n ComposePreparationOps,\n} from './errors.js';\nexport type {\n AppliedGuard,\n ApprovalEntry,\n Call,\n ComposeCompilePartialData,\n ComposeAction,\n ComposeFill,\n ComposeFee,\n ComposeUserProgramSimulation,\n ComposeCompileRequest,\n ComposeCompileResult,\n ComposeCompileSuccessData,\n ComposeErrorKind,\n ComposeRouteRequest,\n ComposeTransactionRequest,\n FailedPreparedOp,\n Flow,\n InputSpec,\n MaterialiserConfigOf,\n MaterialiserInput,\n OutputAmount,\n Amount,\n ConsumedOutput,\n Delivery,\n Estimate,\n EstimateBasis,\n Minimum,\n MinimumBasis,\n Output,\n Outputs,\n TerminalOutput,\n Precondition,\n PreconditionConfigOf,\n PriceImpact,\n Ref,\n Resource,\n RouteAmount,\n RouteAmountAll,\n RouteAmountExact,\n SimulationPolicy,\n SimulationRevert,\n SolType,\n SweepTo,\n SimulateRequest,\n SimulateResult,\n SimulateOkResult,\n SimulateRevertResult,\n SimulateRevertDecodeResult,\n SimulateSetupErrorResult,\n SimulateBalanceEntry,\n TrackedBalance,\n SlotFinderRequirement,\n Erc20BalanceRequirement,\n NativeBalanceRequirement,\n Erc20AllowanceRequirement,\n ContinuationIntent,\n ContinuationOutcome,\n Check,\n CheckComparator,\n SettlementWire,\n SettlementEscrowWire,\n ContinuationPlanWire,\n} from '@lifi/compose-spec';\nexport {\n SIMULATE_MAX_TRACKED_BALANCES,\n SIMULATE_MAX_REQUIREMENTS,\n} from '@lifi/compose-spec';\nexport {\n isComposeError,\n isComposePreparationError,\n isComposeSdkOutdatedError,\n isComposeServerOutdatedError,\n} from './errors.js';\n\nexport type {\n Bindable,\n RefBindable,\n AnyRefBindable,\n InputHandle,\n ResourceInputHandle,\n OutputHandle,\n OutputFamilyHandles,\n FamilyCount,\n FamilySource,\n AnyHandle,\n} from './authoring/handles.js';\nexport { isInputHandle, isOutputHandle } from './authoring/handles.js';\nexport { ref } from './authoring/raw.js';\n\nexport type { AnyBindable } from './authoring/FlowBuilderCore.js';\nexport type { TypedFlow, FlowOptions } from './authoring/FlowBuilderCore.js';\n\nexport type { ComposeRunInput } from './run/inputs.js';\nexport { materialiser } from './run/inputs.js';\n\nexport { buildSimulateRequest } from './run/simulate.js';\nexport type { BuildSimulateRequestInput } from './run/simulate.js';\n\nexport { terminalOutputs } from './outputs.js';\n\nexport { createComposeSdk } from './sdk.js';\nexport type { ComposeSdk, ComposeSdkOptions, FlowBuilder } from './sdk.js';\n\nimport * as guardsMod from './generated/guards.generated.js';\nimport * as materialisersMod from './generated/materialisers.generated.js';\nimport * as preconditionsMod from './generated/preconditions.generated.js';\nimport * as rawMod from './raw.js';\nimport * as resourcesMod from './resources.js';\nimport * as routeAmountMod from './routeAmount.js';\n\n/**\n * Guard factories for protecting operation outputs (e.g. slippage tolerance).\n * Pass guards to an operation's `guards` array.\n *\n * @example\n * ```ts\n * builder.lifi.swap('swap1', {\n * bind: { amountIn: builder.inputs.token },\n * config: { resourceOut: resources.native(1) },\n * guards: [guards.slippage({ port: 'amountOut', bps: 300 })],\n * });\n * ```\n */\nexport const guards: typeof guardsMod = guardsMod;\n/**\n * Materialiser factories that tell the runtime how to resolve token input\n * amounts on-chain (e.g. read a wallet balance, accept a direct deposit).\n *\n * @example\n * ```ts\n * await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * signer: '0x...',\n * });\n * ```\n */\nexport const materialisers: typeof materialisersMod = materialisersMod;\n/**\n * Precondition factories for asserting on-chain state before a flow executes\n * (e.g. minimum token balances, ERC-20 allowances).\n *\n * @example\n * ```ts\n * await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * preconditions: [\n * preconditions.erc20Balance({ wallet: '0x...', token: '0x...', balance: 1000n }),\n * ],\n * signer: '0x...',\n * });\n * ```\n */\nexport const preconditions: typeof preconditionsMod = preconditionsMod;\n/**\n * Resource declaration helpers for defining token inputs in a flow schema.\n * Use {@link resources.erc20} for ERC-20 tokens and {@link resources.native}\n * for the chain's native coin (ETH, MATIC, etc.).\n *\n * @example\n * ```ts\n * const builder = sdk.flow(1, {\n * inputs: {\n * usdc: resources.erc20('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 1),\n * eth: resources.native(1),\n * },\n * });\n * ```\n */\nexport const resources: typeof resourcesMod = resourcesMod;\n/**\n * Amount constructors for {@link ComposeSdk.route}. Use\n * {@link routeAmount.exact} to spend a fixed amount of the `fromToken`, and\n * {@link routeAmount.all} to spend the signer's whole balance.\n *\n * @example\n * ```ts\n * // USDC into the Aave v3 aEthUSDC position — one routing-catalog edge.\n * const result = await sdk.route({\n * chainId: 1,\n * fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n * toToken: '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c',\n * amount: routeAmount.exact(1_000_000n),\n * signer: '0xYourAddress...',\n * });\n * ```\n */\nexport const routeAmount: typeof routeAmountMod = routeAmountMod;\nexport * from './generated/config.generated.js';\n\n/**\n * Low-level escape hatch for constructing flow nodes, guards, and materialiser\n * inputs without the typed builder API. Prefer the generated operation methods\n * on {@link FlowBuilder} and the typed `guards`/`materialisers` namespaces\n * for most use cases.\n */\nexport const raw: typeof rawMod = rawMod;\n"],"mappings":"AAoCA,SAAS,yBAAyB;AAuElC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAcP,SAAS,eAAe,sBAAsB;AAC9C,SAAS,WAAW;AAMpB,SAAS,oBAAoB;AAE7B,SAAS,4BAA4B;AAGrC,SAAS,uBAAuB;AAEhC,SAAS,wBAAwB;AAGjC,YAAY,eAAe;AAC3B,YAAY,sBAAsB;AAClC,YAAY,sBAAsB;AAClC,YAAY,YAAY;AACxB,YAAY,kBAAkB;AAC9B,YAAY,oBAAoB;AAezB,MAAM,SAA2B;AAajC,MAAM,gBAAyC;AAgB/C,MAAM,gBAAyC;AAgB/C,MAAM,YAAiC;AAkBvC,MAAM,cAAqC;AAClD,cAAc;AAQP,MAAM,MAAqB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/composer-sdk",
3
- "version": "0.6.3",
3
+ "version": "0.7.1",
4
4
  "description": "Public Composer SDK for building and submitting flows",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -47,12 +47,12 @@
47
47
  "example:staged": "tsx src/examples/run.ts --staged"
48
48
  },
49
49
  "peerDependencies": {
50
- "@lifi/compose-spec": "0.6.3"
50
+ "@lifi/compose-spec": "0.7.1"
51
51
  },
52
52
  "dependencies": {
53
53
  "abitype": "^1.2.3",
54
54
  "effect": "^3.21.0",
55
- "zod": "^4.1.11"
55
+ "zod": "^4.6.5"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@eslint/compat": "^1.4.0",
@@ -1,12 +1,14 @@
1
- import type {
2
- AppliedGuard,
3
- BindValue,
4
- Call,
5
- Flow,
6
- FlowInput,
7
- Ref,
8
- Resource,
9
- SolType,
1
+ import {
2
+ type AppliedGuard,
3
+ type BindValue,
4
+ type Call,
5
+ familySize,
6
+ type Flow,
7
+ type FlowInput,
8
+ instancePortName,
9
+ type Ref,
10
+ type Resource,
11
+ type SolType,
10
12
  } from '@lifi/compose-spec';
11
13
 
12
14
  import type {
@@ -146,16 +148,34 @@ export interface FlowBuilderCore<T extends InputSchema = InputSchema> {
146
148
  /** Maps output port names to their output kind for compile-time and runtime validation. */
147
149
  export type OutputSpec = Record<string, OutputKind>;
148
150
 
151
+ /**
152
+ * Maps each output family's port name to the config key that sizes it: an
153
+ * array (one instance per element) or a non-negative integer count.
154
+ * A family port is also listed in the {@link OutputSpec}, as `'resource'`.
155
+ */
156
+ export type FamilySpec = Readonly<Record<string, string>>;
157
+
158
+ /** The handles `call` returns for an {@link OutputSpec} and its families. */
159
+ export type OutputHandles<O extends OutputSpec, F extends FamilySpec> = {
160
+ readonly [K in keyof O & string]: K extends keyof F
161
+ ? readonly OutputHandle<'resource'>[]
162
+ : OutputHandle<O[K]>;
163
+ };
164
+
149
165
  /** Internal interface exposed to bindGeneratedOps — not part of the public API. */
150
166
  export interface FlowBuilderInternal<
151
167
  T extends InputSchema = InputSchema,
152
168
  > extends FlowBuilderCore<T> {
153
- readonly call: <O extends OutputSpec>(
169
+ readonly call: <
170
+ O extends OutputSpec,
171
+ F extends FamilySpec = Record<never, string>,
172
+ >(
154
173
  nodeId: string,
155
174
  op: string,
156
175
  args: CallArgs,
157
176
  outputs: O,
158
- ) => { readonly [K in keyof O & string]: OutputHandle<O[K]> };
177
+ families?: F,
178
+ ) => OutputHandles<O, F>;
159
179
  }
160
180
 
161
181
  const isResource = (decl: InputDecl): decl is Resource =>
@@ -194,12 +214,16 @@ export const createFlowBuilderCore = <T extends InputSchema>(
194
214
  }
195
215
  }
196
216
 
197
- const call = <O extends OutputSpec>(
217
+ const call = <
218
+ O extends OutputSpec,
219
+ F extends FamilySpec = Record<never, string>,
220
+ >(
198
221
  nodeId: string,
199
222
  op: string,
200
223
  args: CallArgs,
201
224
  outputs: O,
202
- ): { readonly [K in keyof O & string]: OutputHandle<O[K]> } => {
225
+ families?: F,
226
+ ): OutputHandles<O, F> => {
203
227
  if (nodeIds.has(nodeId)) throw new Error(`Duplicate node id: "${nodeId}"`);
204
228
  nodeIds.add(nodeId);
205
229
 
@@ -208,27 +232,43 @@ export const createFlowBuilderCore = <T extends InputSchema>(
208
232
  bind[key] = toBindValue(val);
209
233
  }
210
234
 
235
+ const config = (args.config ?? {}) as Record<string, unknown>;
211
236
  const node: Call = {
212
237
  id: nodeId,
213
238
  op,
214
239
  bind,
215
- config: (args.config ?? {}) as Record<string, unknown>,
240
+ config,
216
241
  ...(args.guards && args.guards.length > 0 && { guards: args.guards }),
217
242
  };
218
243
  nodes.push(node);
219
244
 
220
- type Result = { readonly [K in keyof O & string]: OutputHandle<O[K]> };
221
- return new Proxy({} as Result, {
222
- get: (_target, prop): OutputHandle | undefined => {
245
+ const outputHandle = (portName: string): OutputHandle => ({
246
+ _tag: 'output',
247
+ nodeId,
248
+ portName,
249
+ });
250
+ return new Proxy({} as OutputHandles<O, F>, {
251
+ get: (
252
+ _target,
253
+ prop,
254
+ ): OutputHandle | readonly OutputHandle[] | undefined => {
223
255
  if (typeof prop !== 'string' || prop === 'then') return undefined;
224
- if (!(prop in outputs)) {
256
+ // Own-key only: the trap sees every property a consumer reads, so `in`
257
+ // would answer a handle for `toString` or `constructor` instead of the
258
+ // unknown-port error.
259
+ if (!Object.hasOwn(outputs, prop)) {
225
260
  throw new Error(
226
261
  `Op "${op}" has no output port "${prop}". Valid ports: ${Object.keys(
227
262
  outputs,
228
263
  ).join(', ')}`,
229
264
  );
230
265
  }
231
- return { _tag: 'output', nodeId, portName: prop };
266
+ const countFrom = families?.[prop];
267
+ if (countFrom === undefined) return outputHandle(prop);
268
+ const size = familySize({ name: prop, countFrom }, config);
269
+ return Array.from({ length: size }, (_, index) =>
270
+ outputHandle(instancePortName(prop, index)),
271
+ );
232
272
  },
233
273
  });
234
274
  };
@@ -39,6 +39,73 @@ export interface OutputHandle<T extends OutputKind = OutputKind> {
39
39
  readonly __outputKind?: T;
40
40
  }
41
41
 
42
+ /**
43
+ * What an output family's sizing parameter accepts, given the config field the
44
+ * family counts from: an array of that field's elements, or a number.
45
+ */
46
+ export type FamilySource<Field> = Field extends readonly (infer E)[]
47
+ ? readonly E[]
48
+ : number;
49
+
50
+ /** Whether a number literal is a valid family count: a non-negative integer. */
51
+ type IsCountLiteral<N extends number> = `${N}` extends
52
+ `-${string}` | `${string}.${string}` | `${string}e${string}`
53
+ ? false
54
+ : true;
55
+
56
+ /**
57
+ * `N` resource handles as a tuple. A non-literal `number`, or a literal that is
58
+ * not a valid count, gives an open array; {@link FamilyCount} rejects the
59
+ * invalid literal at the call site.
60
+ */
61
+ type HandleTuple<
62
+ N extends number,
63
+ Acc extends readonly OutputHandle<'resource'>[] = readonly [],
64
+ > = number extends N
65
+ ? readonly OutputHandle<'resource'>[]
66
+ : IsCountLiteral<N> extends false
67
+ ? readonly OutputHandle<'resource'>[]
68
+ : Acc['length'] extends N
69
+ ? Acc
70
+ : HandleTuple<N, readonly [...Acc, OutputHandle<'resource'>]>;
71
+
72
+ /**
73
+ * The handles of an output family: one resource {@link OutputHandle} per
74
+ * element of the config array the family counts from, or as many as the config
75
+ * count. A literal array or count yields a tuple of that length, so indexing
76
+ * past the last instance is a type error.
77
+ */
78
+ export type OutputFamilyHandles<TCount extends readonly unknown[] | number> =
79
+ TCount extends readonly unknown[]
80
+ ? { readonly [I in keyof TCount]: OutputHandle<'resource'> }
81
+ : TCount extends number
82
+ ? HandleTuple<TCount>
83
+ : never;
84
+
85
+ /**
86
+ * Holds the config value an output family counts from to the op's own type. A
87
+ * runtime-sized array or count passes as is. A literal tuple must also satisfy
88
+ * `Shape`, so a tuple shorter than the op's `minItems` fails at the call site
89
+ * instead of at the server's bind step. A literal count must be a non-negative
90
+ * integer.
91
+ */
92
+ export type FamilyCount<
93
+ TCount extends readonly unknown[] | number,
94
+ Shape,
95
+ > = TCount extends readonly unknown[]
96
+ ? number extends TCount['length']
97
+ ? unknown
98
+ : TCount extends Shape
99
+ ? unknown
100
+ : { readonly 'output family config array has too few entries': never }
101
+ : TCount extends number
102
+ ? IsCountLiteral<TCount> extends true
103
+ ? unknown
104
+ : {
105
+ readonly 'output family count must be a non-negative integer': never;
106
+ }
107
+ : unknown;
108
+
42
109
  /** Discriminated union of all handle types that can be bound to operation arguments. */
43
110
  export type AnyHandle = InputHandle | OutputHandle;
44
111
 
@@ -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
+ };