@lifi/composer-sdk 0.7.1 → 0.9.0

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 (165) hide show
  1. package/README.md +5 -2
  2. package/dist/_virtual/_rolldown/runtime.cjs +33 -0
  3. package/dist/_virtual/_rolldown/runtime.js +13 -0
  4. package/dist/authoring/FlowBuilderCore.cjs +102 -120
  5. package/dist/authoring/FlowBuilderCore.cjs.map +1 -1
  6. package/dist/authoring/FlowBuilderCore.d.cts +58 -61
  7. package/dist/authoring/FlowBuilderCore.d.ts +58 -61
  8. package/dist/authoring/FlowBuilderCore.js +99 -97
  9. package/dist/authoring/FlowBuilderCore.js.map +1 -1
  10. package/dist/authoring/handles.cjs +25 -40
  11. package/dist/authoring/handles.cjs.map +1 -1
  12. package/dist/authoring/handles.d.cts +33 -34
  13. package/dist/authoring/handles.d.ts +33 -34
  14. package/dist/authoring/handles.js +21 -13
  15. package/dist/authoring/handles.js.map +1 -1
  16. package/dist/authoring/raw.cjs +85 -44
  17. package/dist/authoring/raw.cjs.map +1 -1
  18. package/dist/authoring/raw.d.cts +8 -8
  19. package/dist/authoring/raw.d.ts +8 -8
  20. package/dist/authoring/raw.js +83 -19
  21. package/dist/authoring/raw.js.map +1 -1
  22. package/dist/authoring/signatureArgs.cjs +81 -103
  23. package/dist/authoring/signatureArgs.cjs.map +1 -1
  24. package/dist/authoring/signatureArgs.d.cts +63 -64
  25. package/dist/authoring/signatureArgs.d.ts +63 -64
  26. package/dist/authoring/signatureArgs.js +76 -75
  27. package/dist/authoring/signatureArgs.js.map +1 -1
  28. package/dist/client.cjs +172 -220
  29. package/dist/client.cjs.map +1 -1
  30. package/dist/client.d.cts +131 -131
  31. package/dist/client.d.ts +131 -131
  32. package/dist/client.js +165 -198
  33. package/dist/client.js.map +1 -1
  34. package/dist/discovery.cjs +0 -17
  35. package/dist/discovery.d.cts +57 -56
  36. package/dist/discovery.d.ts +57 -56
  37. package/dist/discovery.js +1 -1
  38. package/dist/errors.cjs +211 -159
  39. package/dist/errors.cjs.map +1 -1
  40. package/dist/errors.d.cts +84 -84
  41. package/dist/errors.d.ts +84 -84
  42. package/dist/errors.js +201 -120
  43. package/dist/errors.js.map +1 -1
  44. package/dist/generated/config.generated.cjs +0 -17
  45. package/dist/generated/config.generated.d.cts +805 -895
  46. package/dist/generated/config.generated.d.ts +805 -895
  47. package/dist/generated/config.generated.js +1 -1
  48. package/dist/generated/guards.generated.cjs +27 -31
  49. package/dist/generated/guards.generated.cjs.map +1 -1
  50. package/dist/generated/guards.generated.d.cts +20 -4
  51. package/dist/generated/guards.generated.d.ts +20 -4
  52. package/dist/generated/guards.generated.js +21 -8
  53. package/dist/generated/guards.generated.js.map +1 -1
  54. package/dist/generated/materialisers.generated.cjs +25 -35
  55. package/dist/generated/materialisers.generated.cjs.map +1 -1
  56. package/dist/generated/materialisers.generated.d.cts +17 -4
  57. package/dist/generated/materialisers.generated.d.ts +17 -4
  58. package/dist/generated/materialisers.generated.js +19 -11
  59. package/dist/generated/materialisers.generated.js.map +1 -1
  60. package/dist/generated/operations.generated.cjs +236 -250
  61. package/dist/generated/operations.generated.cjs.map +1 -1
  62. package/dist/generated/operations.generated.d.cts +740 -657
  63. package/dist/generated/operations.generated.d.ts +740 -657
  64. package/dist/generated/operations.generated.js +235 -229
  65. package/dist/generated/operations.generated.js.map +1 -1
  66. package/dist/generated/preconditions.generated.cjs +25 -35
  67. package/dist/generated/preconditions.generated.cjs.map +1 -1
  68. package/dist/generated/preconditions.generated.d.cts +17 -4
  69. package/dist/generated/preconditions.generated.d.ts +17 -4
  70. package/dist/generated/preconditions.generated.js +19 -11
  71. package/dist/generated/preconditions.generated.js.map +1 -1
  72. package/dist/index.cjs +131 -97
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.d.cts +29 -43
  75. package/dist/index.d.ts +29 -43
  76. package/dist/index.js +96 -45
  77. package/dist/index.js.map +1 -1
  78. package/dist/outputs.cjs +11 -32
  79. package/dist/outputs.cjs.map +1 -1
  80. package/dist/outputs.d.cts +5 -5
  81. package/dist/outputs.d.ts +5 -5
  82. package/dist/outputs.js +10 -8
  83. package/dist/outputs.js.map +1 -1
  84. package/dist/raw.cjs +21 -33
  85. package/dist/raw.cjs.map +1 -1
  86. package/dist/raw.d.cts +8 -4
  87. package/dist/raw.d.ts +8 -4
  88. package/dist/raw.js +12 -7
  89. package/dist/raw.js.map +1 -1
  90. package/dist/reachability.cjs +82 -112
  91. package/dist/reachability.cjs.map +1 -1
  92. package/dist/reachability.d.cts +33 -59
  93. package/dist/reachability.d.ts +33 -59
  94. package/dist/reachability.js +81 -88
  95. package/dist/reachability.js.map +1 -1
  96. package/dist/resources.cjs +47 -32
  97. package/dist/resources.cjs.map +1 -1
  98. package/dist/resources.d.cts +50 -3
  99. package/dist/resources.d.ts +50 -3
  100. package/dist/resources.js +42 -9
  101. package/dist/resources.js.map +1 -1
  102. package/dist/responseSchemas.cjs +99 -111
  103. package/dist/responseSchemas.cjs.map +1 -1
  104. package/dist/responseSchemas.d.cts +34 -34
  105. package/dist/responseSchemas.d.ts +34 -34
  106. package/dist/responseSchemas.js +85 -66
  107. package/dist/responseSchemas.js.map +1 -1
  108. package/dist/routeAmount.cjs +61 -31
  109. package/dist/routeAmount.cjs.map +1 -1
  110. package/dist/routeAmount.d.cts +52 -2
  111. package/dist/routeAmount.d.ts +52 -2
  112. package/dist/routeAmount.js +56 -8
  113. package/dist/routeAmount.js.map +1 -1
  114. package/dist/run/inputs.cjs +56 -48
  115. package/dist/run/inputs.cjs.map +1 -1
  116. package/dist/run/inputs.d.cts +70 -74
  117. package/dist/run/inputs.d.ts +70 -74
  118. package/dist/run/inputs.js +54 -23
  119. package/dist/run/inputs.js.map +1 -1
  120. package/dist/run/simulate.cjs +38 -43
  121. package/dist/run/simulate.cjs.map +1 -1
  122. package/dist/run/simulate.d.cts +36 -36
  123. package/dist/run/simulate.d.ts +36 -36
  124. package/dist/run/simulate.js +37 -19
  125. package/dist/run/simulate.js.map +1 -1
  126. package/dist/sdk.cjs +55 -66
  127. package/dist/sdk.cjs.map +1 -1
  128. package/dist/sdk.d.cts +108 -111
  129. package/dist/sdk.d.ts +108 -111
  130. package/dist/sdk.js +52 -44
  131. package/dist/sdk.js.map +1 -1
  132. package/dist/types.cjs +0 -17
  133. package/dist/types.d.cts +22 -22
  134. package/dist/types.d.ts +22 -22
  135. package/dist/types.js +1 -1
  136. package/package.json +4 -4
  137. package/src/client.ts +2 -2
  138. package/src/examples/aaveClaimRewards.ts +2 -1
  139. package/src/examples/emitCustomEvent.ts +1 -2
  140. package/src/examples/run.ts +14 -1
  141. package/src/examples/transferTokens.ts +21 -17
  142. package/src/examples/uniswapV2AddLiquidity.ts +106 -0
  143. package/src/examples/uniswapV3Mint.ts +95 -0
  144. package/src/generated/config.generated.ts +102 -47
  145. package/src/generated/guards.generated.ts +9 -0
  146. package/src/generated/operations.generated.ts +161 -5
  147. package/src/index.ts +0 -3
  148. package/dist/discovery.cjs.map +0 -1
  149. package/dist/discovery.js.map +0 -1
  150. package/dist/generated/config.generated.cjs.map +0 -1
  151. package/dist/generated/config.generated.js.map +0 -1
  152. package/dist/guards.generated-BPLFwe7y.d.ts +0 -19
  153. package/dist/guards.generated-M3VAIevI.d.cts +0 -19
  154. package/dist/materialisers.generated-BMkBQgWZ.d.ts +0 -24
  155. package/dist/materialisers.generated-BWq5oePO.d.cts +0 -24
  156. package/dist/preconditions.generated-DblS13Wq.d.cts +0 -24
  157. package/dist/preconditions.generated-U7YpVh30.d.ts +0 -24
  158. package/dist/raw-BvRghN3r.d.ts +0 -20
  159. package/dist/raw-s1rer8X3.d.cts +0 -20
  160. package/dist/resources-BKlFxjo8.d.cts +0 -56
  161. package/dist/resources-CYis1_DS.d.ts +0 -56
  162. package/dist/routeAmount-DdbJYJyM.d.cts +0 -55
  163. package/dist/routeAmount-DdbJYJyM.d.ts +0 -55
  164. package/dist/types.cjs.map +0 -1
  165. package/dist/types.js.map +0 -1
package/dist/sdk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sdk.ts"],"sourcesContent":["import type {\n ComposeCompileRequest,\n ComposeCompileResult,\n ComposeRouteRequest,\n InputSpec,\n SimulateRequest,\n SimulateResult,\n} from '@lifi/compose-spec';\n\nimport {\n createFlowBuilderCore,\n type FlowBuilderCore,\n type FlowOptions,\n type TypedFlow,\n} from './authoring/FlowBuilderCore.js';\nimport { type ComposeClient, createComposeClient } from './client.js';\nimport type { ChainSummary } from './discovery.js';\nimport {\n bindGeneratedOps,\n type GeneratedOps,\n} from './generated/operations.generated.js';\nimport { buildRun, type ComposeRunInput } from './run/inputs.js';\nimport type { InputSchema } from './types.js';\n\nexport type { ComposeRunInput };\n\n/**\n * A flow builder augmented with generated operation methods and a `compile` method\n * that submits the flow to the Compose backend for compilation.\n *\n * Created via {@link ComposeSdk.flow}.\n *\n * @typeParam T - The input schema describing the flow's required inputs.\n */\nexport type FlowBuilder<T extends InputSchema = InputSchema> =\n FlowBuilderCore<T> &\n GeneratedOps & {\n /**\n * Builds the flow document from the current builder state and submits it\n * to the Compose API for compilation.\n *\n * @param run - Runtime inputs, preconditions, and signer address.\n * @returns The compiled transaction calldata and metadata.\n * @throws {@link ComposeError} on network, validation, or server errors.\n *\n * @example\n * ```ts\n * const result = await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * signer: '0xYourAddress...',\n * });\n * console.log(result.calldata);\n * ```\n */\n readonly compile: (\n run: ComposeRunInput<T>,\n ) => Promise<ComposeCompileResult>;\n };\n\n/**\n * Configuration for creating a Compose SDK instance.\n */\nexport interface ComposeSdkOptions {\n /** Base URL of the Compose API (e.g. `\"https://li.quest\"`). */\n readonly baseUrl: string;\n /** Optional custom `fetch` implementation. Defaults to `globalThis.fetch`. */\n readonly fetch?: typeof globalThis.fetch;\n /** LI.FI API key, sent as the `x-lifi-api-key` header on every request. Required — the Compose API rejects unauthenticated requests. */\n readonly apiKey: string;\n}\n\n/**\n * The top-level Compose SDK interface.\n *\n * Provides methods to build flows, compile them into executable calldata, and\n * interact with the Compose API directly.\n *\n * @example\n * ```ts\n * import { createComposeSdk, resources, materialisers } from '@lifi/composer-sdk';\n *\n * const sdk = createComposeSdk({ baseUrl: 'https://li.quest', apiKey: 'YOUR_API_KEY' });\n *\n * const builder = sdk.flow(1, {\n * inputs: { usdc: resources.erc20('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 1) },\n * });\n *\n * builder.lifi.swap('swap1', {\n * bind: { amountIn: builder.inputs.usdc },\n * config: { resourceOut: resources.native(1) },\n * });\n *\n * const result = await builder.compile({\n * inputs: { usdc: materialisers.balanceOf({}) },\n * signer: '0xYourAddress...',\n * });\n * ```\n */\nexport interface ComposeSdk {\n /** Low-level HTTP client for the Compose API. */\n readonly client: ComposeClient;\n /**\n * Creates a new flow builder targeting the given chain.\n * @param chainId - The EVM chain ID (e.g. `1` for Ethereum mainnet).\n * @param options - Flow configuration including input declarations.\n * @returns A {@link FlowBuilder} with generated operation methods and a `compile` method.\n * @throws Error if any resource input's `chainId` doesn't match the flow's `chainId`.\n */\n readonly flow: <T extends InputSchema>(\n chainId: number,\n options: FlowOptions<T>,\n ) => FlowBuilder<T>;\n /**\n * Fetches the chains this Compose deployment supports, ascending by\n * `chainId`. Thin pass-through to {@link ComposeClient.getChains}; see it\n * for what \"supported\" means and for the caching caveat.\n *\n * Each entry pairs the `chainId` with a display `name`, so one call both\n * gates a chain selector and labels it. Key on `chainId`; `name` is a\n * deployment-maintained label that can change.\n *\n * Use it to fail fast before building a flow for a chain the server would\n * reject.\n *\n * @returns The supported chains, ascending by `chainId`.\n * @throws {@link ComposeError} on network or server errors.\n *\n * @example\n * ```ts\n * const chains = await sdk.getSupportedChains();\n * if (!chains.some((c) => c.chainId === 8453)) {\n * throw new Error('Base is not supported');\n * }\n * for (const { chainId, name } of chains) {\n * console.log(`${name} (${chainId})`);\n * }\n * ```\n */\n readonly getSupportedChains: () => Promise<readonly ChainSummary[]>;\n /**\n * Builds a raw compile request without sending it. Useful for inspecting the\n * request payload or submitting it through a custom transport.\n * @param flow - A built flow document (from `builder.build()`).\n * @param run - Runtime inputs, preconditions, and signer address.\n * @returns A {@link ComposeCompileRequest} ready to send to the Compose API.\n */\n readonly request: <T extends InputSchema>(\n flow: TypedFlow<T>,\n run: ComposeRunInput<T>,\n ) => ComposeCompileRequest;\n /**\n * Compiles a token pair on one chain into a submit-ready transaction. Thin\n * pass-through to {@link ComposeClient.route}; see it for the short chain of\n * catalog edges the server plans, when to prefer `flow(...).compile(...)`,\n * the `success` / `partial` discrimination, and error behaviour. Build the\n * `amount` with `routeAmount.exact(...)` / `routeAmount.all(...)`.\n *\n * @param request - The from/to token pair, amount, signer, and route options.\n * @returns A discriminated result: `status: 'success'` or `status: 'partial'`.\n * @throws {@link ComposeError} on network, validation, or server errors.\n */\n readonly route: (\n request: ComposeRouteRequest,\n ) => Promise<ComposeCompileResult>;\n /**\n * Simulates a raw, pre-encoded transaction. Thin pass-through to\n * {@link ComposeClient.simulate}; see it for the `ok` / `revert` / `error`\n * result discrimination and error behaviour. Pair with `buildSimulateRequest`\n * to assemble the request from a compile result.\n *\n * @param request - The raw transaction plus funding `requirements` and\n * `trackedBalances`.\n * @returns A {@link SimulateResult} (`ok` / `revert` / `error`).\n * @throws {@link ComposeError} on network, validation, or server errors.\n */\n readonly simulate: (request: SimulateRequest) => Promise<SimulateResult>;\n}\n\n/**\n * Creates a new Compose SDK instance.\n *\n * @param options - SDK configuration including the API base URL, required API key, and optional fetch implementation.\n * @returns A {@link ComposeSdk} instance.\n *\n * @example\n * ```ts\n * const sdk = createComposeSdk({ baseUrl: 'https://li.quest', apiKey: 'YOUR_API_KEY' });\n * ```\n */\nexport const createComposeSdk = (options: ComposeSdkOptions): ComposeSdk => {\n const composeClient = createComposeClient(options);\n\n const request = <T extends InputSchema>(\n flowDoc: TypedFlow<T>,\n run: ComposeRunInput<T>,\n ): ComposeCompileRequest => ({\n flow: flowDoc,\n run: buildRun({\n inputs: run.inputs as Record<string, InputSpec>,\n preconditions: run.preconditions,\n signer: run.signer,\n assumptions: run.assumptions as Record<string, bigint> | undefined,\n referrer: run.referrer,\n integratorFeeBps: run.integratorFeeBps,\n maxPriceImpactBps: run.maxPriceImpactBps,\n sweepTo: run.sweepTo,\n simulationPolicy: run.simulationPolicy,\n simulateUserProgram: run.simulateUserProgram,\n checkOnChainAllowances: run.checkOnChainAllowances,\n }),\n });\n\n const flow = <T extends InputSchema>(\n chainId: number,\n opts: FlowOptions<T>,\n ): FlowBuilder<T> => {\n const core = createFlowBuilderCore(chainId, opts);\n const builder = Object.assign(core, bindGeneratedOps(core));\n\n const compile = async (\n run: ComposeRunInput<T>,\n ): Promise<ComposeCompileResult> => {\n const flowDoc = builder.build();\n const req = request(flowDoc, run);\n return composeClient.compile(req);\n };\n\n return Object.assign(builder, { compile });\n };\n\n return {\n client: composeClient,\n flow,\n getSupportedChains: composeClient.getChains,\n request,\n route: composeClient.route,\n simulate: composeClient.simulate,\n };\n};\n"],"mappings":"AASA;AAAA,EACE;AAAA,OAIK;AACP,SAA6B,2BAA2B;AAExD;AAAA,EACE;AAAA,OAEK;AACP,SAAS,gBAAsC;AAwKxC,MAAM,mBAAmB,CAAC,YAA2C;AAC1E,QAAM,gBAAgB,oBAAoB,OAAO;AAEjD,QAAM,UAAU,CACd,SACA,SAC2B;AAAA,IAC3B,MAAM;AAAA,IACN,KAAK,SAAS;AAAA,MACZ,QAAQ,IAAI;AAAA,MACZ,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,aAAa,IAAI;AAAA,MACjB,UAAU,IAAI;AAAA,MACd,kBAAkB,IAAI;AAAA,MACtB,mBAAmB,IAAI;AAAA,MACvB,SAAS,IAAI;AAAA,MACb,kBAAkB,IAAI;AAAA,MACtB,qBAAqB,IAAI;AAAA,MACzB,wBAAwB,IAAI;AAAA,IAC9B,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,CACX,SACA,SACmB;AACnB,UAAM,OAAO,sBAAsB,SAAS,IAAI;AAChD,UAAM,UAAU,OAAO,OAAO,MAAM,iBAAiB,IAAI,CAAC;AAE1D,UAAM,UAAU,OACd,QACkC;AAClC,YAAM,UAAU,QAAQ,MAAM;AAC9B,YAAM,MAAM,QAAQ,SAAS,GAAG;AAChC,aAAO,cAAc,QAAQ,GAAG;AAAA,IAClC;AAEA,WAAO,OAAO,OAAO,SAAS,EAAE,QAAQ,CAAC;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,oBAAoB,cAAc;AAAA,IAClC;AAAA,IACA,OAAO,cAAc;AAAA,IACrB,UAAU,cAAc;AAAA,EAC1B;AACF;","names":[]}
1
+ {"version":3,"file":"sdk.js","names":[],"sources":["../src/sdk.ts"],"sourcesContent":["import type {\n ComposeCompileRequest,\n ComposeCompileResult,\n ComposeRouteRequest,\n InputSpec,\n SimulateRequest,\n SimulateResult,\n} from '@lifi/compose-spec';\n\nimport {\n createFlowBuilderCore,\n type FlowBuilderCore,\n type FlowOptions,\n type TypedFlow,\n} from './authoring/FlowBuilderCore.js';\nimport { type ComposeClient, createComposeClient } from './client.js';\nimport type { ChainSummary } from './discovery.js';\nimport {\n bindGeneratedOps,\n type GeneratedOps,\n} from './generated/operations.generated.js';\nimport { buildRun, type ComposeRunInput } from './run/inputs.js';\nimport type { InputSchema } from './types.js';\n\nexport type { ComposeRunInput };\n\n/**\n * A flow builder augmented with generated operation methods and a `compile` method\n * that submits the flow to the Compose backend for compilation.\n *\n * Created via {@link ComposeSdk.flow}.\n *\n * @typeParam T - The input schema describing the flow's required inputs.\n */\nexport type FlowBuilder<T extends InputSchema = InputSchema> =\n FlowBuilderCore<T> &\n GeneratedOps & {\n /**\n * Builds the flow document from the current builder state and submits it\n * to the Compose API for compilation.\n *\n * @param run - Runtime inputs, preconditions, and signer address.\n * @returns The compiled transaction calldata and metadata.\n * @throws {@link ComposeError} on network, validation, or server errors.\n *\n * @example\n * ```ts\n * const result = await builder.compile({\n * inputs: { token: materialisers.balanceOf({}) },\n * signer: '0xYourAddress...',\n * });\n * console.log(result.calldata);\n * ```\n */\n readonly compile: (\n run: ComposeRunInput<T>,\n ) => Promise<ComposeCompileResult>;\n };\n\n/**\n * Configuration for creating a Compose SDK instance.\n */\nexport interface ComposeSdkOptions {\n /** Base URL of the Compose API (e.g. `\"https://li.quest\"`). */\n readonly baseUrl: string;\n /** Optional custom `fetch` implementation. Defaults to `globalThis.fetch`. */\n readonly fetch?: typeof globalThis.fetch;\n /** LI.FI API key, sent as the `x-lifi-api-key` header on every request. Required — the Compose API rejects unauthenticated requests. */\n readonly apiKey: string;\n}\n\n/**\n * The top-level Compose SDK interface.\n *\n * Provides methods to build flows, compile them into executable calldata, and\n * interact with the Compose API directly.\n *\n * @example\n * ```ts\n * import { createComposeSdk, resources, materialisers } from '@lifi/composer-sdk';\n *\n * const sdk = createComposeSdk({ baseUrl: 'https://li.quest', apiKey: 'YOUR_API_KEY' });\n *\n * const builder = sdk.flow(1, {\n * inputs: { usdc: resources.erc20('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 1) },\n * });\n *\n * builder.lifi.swap('swap1', {\n * bind: { amountIn: builder.inputs.usdc },\n * config: { resourceOut: resources.native(1) },\n * });\n *\n * const result = await builder.compile({\n * inputs: { usdc: materialisers.balanceOf({}) },\n * signer: '0xYourAddress...',\n * });\n * ```\n */\nexport interface ComposeSdk {\n /** Low-level HTTP client for the Compose API. */\n readonly client: ComposeClient;\n /**\n * Creates a new flow builder targeting the given chain.\n * @param chainId - The EVM chain ID (e.g. `1` for Ethereum mainnet).\n * @param options - Flow configuration including input declarations.\n * @returns A {@link FlowBuilder} with generated operation methods and a `compile` method.\n * @throws Error if any resource input's `chainId` doesn't match the flow's `chainId`.\n */\n readonly flow: <T extends InputSchema>(\n chainId: number,\n options: FlowOptions<T>,\n ) => FlowBuilder<T>;\n /**\n * Fetches the chains this Compose deployment supports, ascending by\n * `chainId`. Thin pass-through to {@link ComposeClient.getChains}; see it\n * for what \"supported\" means and for the caching caveat.\n *\n * Each entry pairs the `chainId` with a display `name`, so one call both\n * gates a chain selector and labels it. Key on `chainId`; `name` is a\n * deployment-maintained label that can change.\n *\n * Use it to fail fast before building a flow for a chain the server would\n * reject.\n *\n * @returns The supported chains, ascending by `chainId`.\n * @throws {@link ComposeError} on network or server errors.\n *\n * @example\n * ```ts\n * const chains = await sdk.getSupportedChains();\n * if (!chains.some((c) => c.chainId === 8453)) {\n * throw new Error('Base is not supported');\n * }\n * for (const { chainId, name } of chains) {\n * console.log(`${name} (${chainId})`);\n * }\n * ```\n */\n readonly getSupportedChains: () => Promise<readonly ChainSummary[]>;\n /**\n * Builds a raw compile request without sending it. Useful for inspecting the\n * request payload or submitting it through a custom transport.\n * @param flow - A built flow document (from `builder.build()`).\n * @param run - Runtime inputs, preconditions, and signer address.\n * @returns A {@link ComposeCompileRequest} ready to send to the Compose API.\n */\n readonly request: <T extends InputSchema>(\n flow: TypedFlow<T>,\n run: ComposeRunInput<T>,\n ) => ComposeCompileRequest;\n /**\n * Compiles a token pair on one chain into a submit-ready transaction. Thin\n * pass-through to {@link ComposeClient.route}; see it for the short chain of\n * catalog edges the server plans, when to prefer `flow(...).compile(...)`,\n * the `success` / `partial` discrimination, and error behaviour. Build the\n * `amount` with `routeAmount.exact(...)` / `routeAmount.all(...)`.\n *\n * @param request - The from/to token pair, amount, signer, and route options.\n * @returns A discriminated result: `status: 'success'` or `status: 'partial'`.\n * @throws {@link ComposeError} on network, validation, or server errors.\n */\n readonly route: (\n request: ComposeRouteRequest,\n ) => Promise<ComposeCompileResult>;\n /**\n * Simulates a raw, pre-encoded transaction. Thin pass-through to\n * {@link ComposeClient.simulate}; see it for the `ok` / `revert` / `error`\n * result discrimination and error behaviour. Pair with `buildSimulateRequest`\n * to assemble the request from a compile result.\n *\n * @param request - The raw transaction plus funding `requirements` and\n * `trackedBalances`.\n * @returns A {@link SimulateResult} (`ok` / `revert` / `error`).\n * @throws {@link ComposeError} on network, validation, or server errors.\n */\n readonly simulate: (request: SimulateRequest) => Promise<SimulateResult>;\n}\n\n/**\n * Creates a new Compose SDK instance.\n *\n * @param options - SDK configuration including the API base URL, required API key, and optional fetch implementation.\n * @returns A {@link ComposeSdk} instance.\n *\n * @example\n * ```ts\n * const sdk = createComposeSdk({ baseUrl: 'https://li.quest', apiKey: 'YOUR_API_KEY' });\n * ```\n */\nexport const createComposeSdk = (options: ComposeSdkOptions): ComposeSdk => {\n const composeClient = createComposeClient(options);\n\n const request = <T extends InputSchema>(\n flowDoc: TypedFlow<T>,\n run: ComposeRunInput<T>,\n ): ComposeCompileRequest => ({\n flow: flowDoc,\n run: buildRun({\n inputs: run.inputs as Record<string, InputSpec>,\n preconditions: run.preconditions,\n signer: run.signer,\n assumptions: run.assumptions as Record<string, bigint> | undefined,\n referrer: run.referrer,\n integratorFeeBps: run.integratorFeeBps,\n maxPriceImpactBps: run.maxPriceImpactBps,\n sweepTo: run.sweepTo,\n simulationPolicy: run.simulationPolicy,\n simulateUserProgram: run.simulateUserProgram,\n checkOnChainAllowances: run.checkOnChainAllowances,\n }),\n });\n\n const flow = <T extends InputSchema>(\n chainId: number,\n opts: FlowOptions<T>,\n ): FlowBuilder<T> => {\n const core = createFlowBuilderCore(chainId, opts);\n const builder = Object.assign(core, bindGeneratedOps(core));\n\n const compile = async (\n run: ComposeRunInput<T>,\n ): Promise<ComposeCompileResult> => {\n const flowDoc = builder.build();\n const req = request(flowDoc, run);\n return composeClient.compile(req);\n };\n\n return Object.assign(builder, { compile });\n };\n\n return {\n client: composeClient,\n flow,\n getSupportedChains: composeClient.getChains,\n request,\n route: composeClient.route,\n simulate: composeClient.simulate,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;AA6LA,MAAa,oBAAoB,YAA2C;CAC1E,MAAM,gBAAgB,oBAAoB,OAAO;CAEjD,MAAM,WACJ,SACA,SAC2B;EAC3B,MAAM;EACN,KAAK,SAAS;GACZ,QAAQ,IAAI;GACZ,eAAe,IAAI;GACnB,QAAQ,IAAI;GACZ,aAAa,IAAI;GACjB,UAAU,IAAI;GACd,kBAAkB,IAAI;GACtB,mBAAmB,IAAI;GACvB,SAAS,IAAI;GACb,kBAAkB,IAAI;GACtB,qBAAqB,IAAI;GACzB,wBAAwB,IAAI;EAC9B,CAAC;CACH;CAEA,MAAM,QACJ,SACA,SACmB;EACnB,MAAM,OAAO,sBAAsB,SAAS,IAAI;EAChD,MAAM,UAAU,OAAO,OAAO,MAAM,iBAAiB,IAAI,CAAC;EAE1D,MAAM,UAAU,OACd,QACkC;GAClC,MAAM,UAAU,QAAQ,MAAM;GAC9B,MAAM,MAAM,QAAQ,SAAS,GAAG;GAChC,OAAO,cAAc,QAAQ,GAAG;EAClC;EAEA,OAAO,OAAO,OAAO,SAAS,EAAE,QAAQ,CAAC;CAC3C;CAEA,OAAO;EACL,QAAQ;EACR;EACA,oBAAoB,cAAc;EAClC;EACA,OAAO,cAAc;EACrB,UAAU,cAAc;CAC1B;AACF"}
package/dist/types.cjs CHANGED
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
- var types_exports = {};
16
- module.exports = __toCommonJS(types_exports);
17
- //# sourceMappingURL=types.cjs.map
package/dist/types.d.cts CHANGED
@@ -1,25 +1,25 @@
1
- import { SolType, Ref, LiteralBinding, Resource, MaterialiserInput, InputSpec } from '@lifi/compose-spec';
2
-
1
+ import { InputSpec, LiteralBinding, MaterialiserInput, Ref, Resource, SolType } from "@lifi/compose-spec";
2
+ //#region src/types.d.ts
3
3
  /**
4
4
  * A string that represents a non-negative integer (e.g. "1000000000").
5
5
  * Uses a template literal type so that only numeric-looking strings
6
6
  * are assignable at compile time.
7
7
  */
8
- type IntegerString = `${bigint}`;
8
+ export type IntegerString = `${bigint}`;
9
9
  /**
10
10
  * Accepted input for integer-string config fields.
11
11
  * Callers may pass either a numeric string ("1000000000") or a native bigint
12
12
  * (1000000000n). Bigint values are stringified automatically during JSON
13
13
  * serialization via the SDK's `bigintReplacer`.
14
14
  */
15
- type IntegerStringInput = IntegerString | bigint;
15
+ export type IntegerStringInput = IntegerString | bigint;
16
16
  /**
17
17
  * A `0x`-prefixed hex string representing an Ethereum address.
18
18
  * Template literal type catches obviously wrong values at compile time.
19
19
  */
20
- type Address = `0x${string}`;
20
+ export type Address = `0x${string}`;
21
21
  /** The universe of output port kinds: Solidity scalar types plus `'resource'`. */
22
- type OutputKind = SolType | 'resource';
22
+ export type OutputKind = SolType | "resource";
23
23
  /**
24
24
  * Maps an ABI parameter type string (from abitype's `ParseAbiItem`) to the
25
25
  * closest `OutputKind`. When the ABI type is one of the supported `SolType`
@@ -34,7 +34,7 @@ type OutputKind = SolType | 'resource';
34
34
  * Extending `SolType` with new members automatically widens the exact-match
35
35
  * branch — no changes needed here.
36
36
  */
37
- type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
37
+ export type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
38
38
  /**
39
39
  * Phantom brand key for {@link TypedRef}.
40
40
  *
@@ -42,7 +42,7 @@ type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
42
42
  * typed ref from an arbitrary `{ $ref }` object. Keying it on a `unique
43
43
  * symbol` means no caller can produce one by writing an object literal.
44
44
  */
45
- declare const typedRefKind: unique symbol;
45
+ export declare const typedRefKind: unique symbol;
46
46
  /**
47
47
  * A typed `$ref` pointer carrying a phantom type parameter.
48
48
  *
@@ -52,8 +52,8 @@ declare const typedRefKind: unique symbol;
52
52
  * advertises: an untyped `{ $ref }` never enters a typed bind slot. Build one
53
53
  * with `raw.ref<T>()`.
54
54
  */
55
- interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
56
- readonly [typedRefKind]: T;
55
+ export interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
56
+ readonly [typedRefKind]: T;
57
57
  }
58
58
  /**
59
59
  * A literal bind value carrying a phantom type parameter.
@@ -67,35 +67,35 @@ interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
67
67
  *
68
68
  * @typeParam T - The Solidity type of the literal (e.g. `'address'`).
69
69
  */
70
- interface TypedLiteral<T extends SolType = SolType> extends LiteralBinding {
71
- readonly kind: T;
72
- readonly __outputKind?: T;
70
+ export interface TypedLiteral<T extends SolType = SolType> extends LiteralBinding {
71
+ readonly kind: T;
72
+ readonly __outputKind?: T;
73
73
  }
74
74
  /**
75
75
  * An input declaration in a flow schema.
76
76
  * `Resource` values become resource inputs (token amounts);
77
77
  * `SolType` strings become handle inputs (scalars like addresses).
78
78
  */
79
- type InputDecl = Resource | SolType;
79
+ export type InputDecl = Resource | SolType;
80
80
  /**
81
81
  * A record mapping input names to their declarations.
82
82
  * Used as the type parameter for generic flow builders and requests.
83
83
  */
84
- type InputSchema = Record<string, InputDecl>;
84
+ export type InputSchema = Record<string, InputDecl>;
85
85
  /**
86
86
  * Maps an input declaration to the allowed runtime value type.
87
87
  * Resource inputs accept materialisers or literal amounts.
88
88
  * Handle inputs accept the scalar type matching their SolType.
89
89
  */
90
- type InputSpecOf<D> = D extends Resource ? MaterialiserInput | IntegerStringInput : D extends 'address' ? Address : D extends 'bool' ? boolean : D extends `${'u' | ''}int${string}` ? IntegerStringInput : D extends `bytes${string}` ? `0x${string}` : D extends 'string' ? string : InputSpec;
90
+ export type InputSpecOf<D> = D extends Resource ? MaterialiserInput | IntegerStringInput : D extends "address" ? Address : D extends "bool" ? boolean : D extends `${"u" | ""}int${string}` ? IntegerStringInput : D extends `bytes${string}` ? `0x${string}` : D extends "string" ? string : InputSpec;
91
91
  /**
92
92
  * A guard applied to an operation, with the `port` field constrained
93
93
  * to a specific set of output port names.
94
94
  */
95
- interface TypedGuard<Port extends string = string> {
96
- readonly kind: string;
97
- readonly port: Port;
98
- readonly [key: string]: unknown;
95
+ export interface TypedGuard<Port extends string = string> {
96
+ readonly kind: string;
97
+ readonly port: Port;
98
+ readonly [key: string]: unknown;
99
99
  }
100
-
101
- export { type AbiTypeToOutputKind, type Address, type InputDecl, type InputSchema, type InputSpecOf, type IntegerString, type IntegerStringInput, type OutputKind, type TypedGuard, type TypedLiteral, type TypedRef, typedRefKind };
100
+ //#endregion
101
+ //# sourceMappingURL=types.d.cts.map
package/dist/types.d.ts CHANGED
@@ -1,25 +1,25 @@
1
- import { SolType, Ref, LiteralBinding, Resource, MaterialiserInput, InputSpec } from '@lifi/compose-spec';
2
-
1
+ import { InputSpec, LiteralBinding, MaterialiserInput, Ref, Resource, SolType } from "@lifi/compose-spec";
2
+ //#region src/types.d.ts
3
3
  /**
4
4
  * A string that represents a non-negative integer (e.g. "1000000000").
5
5
  * Uses a template literal type so that only numeric-looking strings
6
6
  * are assignable at compile time.
7
7
  */
8
- type IntegerString = `${bigint}`;
8
+ export type IntegerString = `${bigint}`;
9
9
  /**
10
10
  * Accepted input for integer-string config fields.
11
11
  * Callers may pass either a numeric string ("1000000000") or a native bigint
12
12
  * (1000000000n). Bigint values are stringified automatically during JSON
13
13
  * serialization via the SDK's `bigintReplacer`.
14
14
  */
15
- type IntegerStringInput = IntegerString | bigint;
15
+ export type IntegerStringInput = IntegerString | bigint;
16
16
  /**
17
17
  * A `0x`-prefixed hex string representing an Ethereum address.
18
18
  * Template literal type catches obviously wrong values at compile time.
19
19
  */
20
- type Address = `0x${string}`;
20
+ export type Address = `0x${string}`;
21
21
  /** The universe of output port kinds: Solidity scalar types plus `'resource'`. */
22
- type OutputKind = SolType | 'resource';
22
+ export type OutputKind = SolType | "resource";
23
23
  /**
24
24
  * Maps an ABI parameter type string (from abitype's `ParseAbiItem`) to the
25
25
  * closest `OutputKind`. When the ABI type is one of the supported `SolType`
@@ -34,7 +34,7 @@ type OutputKind = SolType | 'resource';
34
34
  * Extending `SolType` with new members automatically widens the exact-match
35
35
  * branch — no changes needed here.
36
36
  */
37
- type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
37
+ export type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
38
38
  /**
39
39
  * Phantom brand key for {@link TypedRef}.
40
40
  *
@@ -42,7 +42,7 @@ type AbiTypeToOutputKind<T extends string> = T extends SolType ? T : SolType;
42
42
  * typed ref from an arbitrary `{ $ref }` object. Keying it on a `unique
43
43
  * symbol` means no caller can produce one by writing an object literal.
44
44
  */
45
- declare const typedRefKind: unique symbol;
45
+ export declare const typedRefKind: unique symbol;
46
46
  /**
47
47
  * A typed `$ref` pointer carrying a phantom type parameter.
48
48
  *
@@ -52,8 +52,8 @@ declare const typedRefKind: unique symbol;
52
52
  * advertises: an untyped `{ $ref }` never enters a typed bind slot. Build one
53
53
  * with `raw.ref<T>()`.
54
54
  */
55
- interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
56
- readonly [typedRefKind]: T;
55
+ export interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
56
+ readonly [typedRefKind]: T;
57
57
  }
58
58
  /**
59
59
  * A literal bind value carrying a phantom type parameter.
@@ -67,35 +67,35 @@ interface TypedRef<T extends OutputKind = OutputKind> extends Ref {
67
67
  *
68
68
  * @typeParam T - The Solidity type of the literal (e.g. `'address'`).
69
69
  */
70
- interface TypedLiteral<T extends SolType = SolType> extends LiteralBinding {
71
- readonly kind: T;
72
- readonly __outputKind?: T;
70
+ export interface TypedLiteral<T extends SolType = SolType> extends LiteralBinding {
71
+ readonly kind: T;
72
+ readonly __outputKind?: T;
73
73
  }
74
74
  /**
75
75
  * An input declaration in a flow schema.
76
76
  * `Resource` values become resource inputs (token amounts);
77
77
  * `SolType` strings become handle inputs (scalars like addresses).
78
78
  */
79
- type InputDecl = Resource | SolType;
79
+ export type InputDecl = Resource | SolType;
80
80
  /**
81
81
  * A record mapping input names to their declarations.
82
82
  * Used as the type parameter for generic flow builders and requests.
83
83
  */
84
- type InputSchema = Record<string, InputDecl>;
84
+ export type InputSchema = Record<string, InputDecl>;
85
85
  /**
86
86
  * Maps an input declaration to the allowed runtime value type.
87
87
  * Resource inputs accept materialisers or literal amounts.
88
88
  * Handle inputs accept the scalar type matching their SolType.
89
89
  */
90
- type InputSpecOf<D> = D extends Resource ? MaterialiserInput | IntegerStringInput : D extends 'address' ? Address : D extends 'bool' ? boolean : D extends `${'u' | ''}int${string}` ? IntegerStringInput : D extends `bytes${string}` ? `0x${string}` : D extends 'string' ? string : InputSpec;
90
+ export type InputSpecOf<D> = D extends Resource ? MaterialiserInput | IntegerStringInput : D extends "address" ? Address : D extends "bool" ? boolean : D extends `${"u" | ""}int${string}` ? IntegerStringInput : D extends `bytes${string}` ? `0x${string}` : D extends "string" ? string : InputSpec;
91
91
  /**
92
92
  * A guard applied to an operation, with the `port` field constrained
93
93
  * to a specific set of output port names.
94
94
  */
95
- interface TypedGuard<Port extends string = string> {
96
- readonly kind: string;
97
- readonly port: Port;
98
- readonly [key: string]: unknown;
95
+ export interface TypedGuard<Port extends string = string> {
96
+ readonly kind: string;
97
+ readonly port: Port;
98
+ readonly [key: string]: unknown;
99
99
  }
100
-
101
- export { type AbiTypeToOutputKind, type Address, type InputDecl, type InputSchema, type InputSpecOf, type IntegerString, type IntegerStringInput, type OutputKind, type TypedGuard, type TypedLiteral, type TypedRef, typedRefKind };
100
+ //#endregion
101
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- //# sourceMappingURL=types.js.map
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/composer-sdk",
3
- "version": "0.7.1",
3
+ "version": "0.9.0",
4
4
  "description": "Public Composer SDK for building and submitting flows",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "access": "public"
30
30
  },
31
31
  "scripts": {
32
- "build": "tsc --noEmit && tsup",
32
+ "build": "tsc --noEmit && tsdown",
33
33
  "clean": "rm -rf dist out",
34
34
  "pack:local": "yarn build && mkdir -p out && yarn pack --out 'out/%s-%v.tgz'",
35
35
  "generate": "tsx scripts/generate-sdk/index.ts",
@@ -47,7 +47,7 @@
47
47
  "example:staged": "tsx src/examples/run.ts --staged"
48
48
  },
49
49
  "peerDependencies": {
50
- "@lifi/compose-spec": "0.7.1"
50
+ "@lifi/compose-spec": "0.9.0"
51
51
  },
52
52
  "dependencies": {
53
53
  "abitype": "^1.2.3",
@@ -67,7 +67,7 @@
67
67
  "eslint-plugin-import": "^2.22.0",
68
68
  "eslint-plugin-require-extensions": "^0.1.3",
69
69
  "json-schema-to-typescript": "^15.0.4",
70
- "tsup": "^8.5.1",
70
+ "tsdown": "^0.23.0",
71
71
  "tsx": "^4.20.4",
72
72
  "typescript": "^6.0.3",
73
73
  "vitest": "^3.2.4"
package/src/client.ts CHANGED
@@ -26,11 +26,11 @@ import {
26
26
  parseSimulateResult,
27
27
  } from './responseSchemas.js';
28
28
 
29
- // __SDK_VERSION__ is a compile-time constant injected by tsup (via `define` in tsup.config.ts)
29
+ // __SDK_VERSION__ is a compile-time constant injected by tsdown (via `define` in tsdown.config.ts)
30
30
  // and by vitest (via `define` in vitest.config.ts). Both read the version from package.json
31
31
  // at build/test time and replace this identifier with the literal string value.
32
32
  // It is sent as the `COMPOSER_SDK_VERSION_HEADER` request header so the server can identify the caller.
33
- // Falls back to 'dev' when running via tsx without tsup substitution (e.g. the example harness).
33
+ // Falls back to 'dev' when running via tsx without tsdown substitution (e.g. the example harness).
34
34
  declare const __SDK_VERSION__: string;
35
35
 
36
36
  const SDK_VERSION: string =
@@ -73,7 +73,8 @@ export const buildAaveClaimRewards = ({
73
73
  inputs: {
74
74
  recipient,
75
75
  },
76
- sweepTo: builder.context.sender,
76
+ // No `sweepTo`: the transfer forwards the whole claim, so the proxy holds
77
+ // nothing left to sweep.
77
78
  });
78
79
 
79
80
  return { flow, request };
@@ -64,8 +64,7 @@ export const buildEmitCustomEvent = ({
64
64
  const flow = builder.build();
65
65
 
66
66
  // No `sweepTo`: this flow only reads and emits a log — it moves no funds, so
67
- // there are no proxy-held terminal resources to sweep. Specifying `sweepTo`
68
- // here would fail compilation with "no ... terminal resources ... to sweep".
67
+ // there are no proxy-held terminal resources to sweep.
69
68
  const request = sdk.request(flow, {
70
69
  signer: owner,
71
70
  inputs: {},
@@ -36,8 +36,10 @@
36
36
  * redeem — redeem ERC-4626 vault shares via core.call
37
37
  * wrap-eth — wrap native ETH into WETH via ValueCall
38
38
  * transfer — transfer full token balance to a recipient
39
- * partial-transfer — transfer a specific amount, keeping the remainder
39
+ * partial-transfer — split off a fixed amount with core.splitAt, transfer it, swap the rest
40
40
  * untyped-ref — mix untypedOp with typed handles via raw.ref
41
+ * uniswap-v2-add — split USDC, swap half to WETH, add both to the Uniswap V2 pair
42
+ * uniswap-v3-mint — open a full-range Uniswap V3 USDC/WETH position
41
43
  * route-exact — wrap 0.1 native ETH into WETH via /compose/route
42
44
  * route-all — unwrap the whole WETH balance to ETH via /compose/route
43
45
  * supported-chains — list the chains this deployment supports, and guard on them
@@ -83,6 +85,8 @@ import { buildSwapWithAllowRevertExample } from './swapWithAllowRevert.js';
83
85
  import { buildSwapWithBalanceCheck } from './swapWithBalanceCheck.js';
84
86
  import { buildSwapWithOutputValidation } from './swapWithOutputValidation.js';
85
87
  import { buildPartialTransfer, buildTransferTokens } from './transferTokens.js';
88
+ import { buildUniswapV2AddLiquidity } from './uniswapV2AddLiquidity.js';
89
+ import { buildUniswapV3Mint } from './uniswapV3Mint.js';
86
90
  import { buildUntypedOpWithTypedRef } from './untypedOpWithTypedRef.js';
87
91
 
88
92
  const stringifyJson = (value: unknown) =>
@@ -196,6 +200,15 @@ const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
196
200
  amount: '1000000000',
197
201
  }).request,
198
202
  'untyped-ref': () => buildUntypedOpWithTypedRef({ owner: OWNER }).request,
203
+ 'uniswap-v2-add': () =>
204
+ buildUniswapV2AddLiquidity({ owner: OWNER, usdcAmount: '1000000000' })
205
+ .request,
206
+ 'uniswap-v3-mint': () =>
207
+ buildUniswapV3Mint({
208
+ owner: OWNER,
209
+ usdcAmount: '1000000000',
210
+ wethAmount: '400000000000000000',
211
+ }).request,
199
212
  };
200
213
 
201
214
  // `/compose/route` examples build a `ComposeRouteRequest` and go to
@@ -17,11 +17,9 @@ export interface TransferTokensInput {
17
17
  * Transfer ERC-20 tokens from the proxy to an arbitrary recipient.
18
18
  *
19
19
  * Demonstrates:
20
- * - `core.transfer` to move tokens to a recipient address
20
+ * - `core.transfer` to move the whole input to a recipient address
21
21
  * - Binding a scalar handle input (`recipient`) alongside a resource input
22
- * - Optionally specifying a partial transfer amount via `config.amount`
23
- * (omit to transfer the full balance)
24
- * - The `transferred` and `remainder` output ports
22
+ * - The `transferred` output port
25
23
  */
26
24
  export const buildTransferTokens = ({
27
25
  owner,
@@ -41,8 +39,8 @@ export const buildTransferTokens = ({
41
39
  },
42
40
  });
43
41
 
44
- // Transfer the full input amount to the recipient.
45
- // The `transferred` port tracks what was sent; `remainder` tracks what's left.
42
+ // Transfer the full input amount to the recipient. The `transferred` port
43
+ // tracks what the recipient received.
46
44
  builder.core.transfer('send', {
47
45
  bind: {
48
46
  amount: builder.inputs.amountIn,
@@ -65,11 +63,12 @@ export const buildTransferTokens = ({
65
63
  };
66
64
 
67
65
  /**
68
- * Transfer a partial amount, keeping the remainder in the proxy.
66
+ * Transfer a fixed amount and swap the rest.
69
67
  *
70
68
  * Demonstrates:
71
- * - `config.amount` to transfer a specific sub-amount
72
- * - Using the `remainder` output port for subsequent operations
69
+ * - `core.splitAt` to carve a fixed sub-amount (`head`) out of a resource,
70
+ * leaving the rest in `tail`
71
+ * - Sending `head` with `core.transfer` and using `tail` in a later operation
73
72
  */
74
73
  export const buildPartialTransfer = ({
75
74
  owner,
@@ -89,19 +88,24 @@ export const buildPartialTransfer = ({
89
88
  },
90
89
  });
91
90
 
92
- // Transfer a fixed 0.5 USDC (500000 base units at 6 decimals);
93
- // the remainder stays on the proxy for subsequent operations.
94
- const out = builder.core.transfer('send-half', {
91
+ // Carve out a fixed 0.5 USDC (500000 base units at 6 decimals). Below that
92
+ // amount, `head` takes the whole input and `tail` is 0.
93
+ const { head, tail } = builder.core.splitAt('split', {
94
+ bind: { source: builder.inputs.amountIn },
95
+ config: { amount: '500000' },
96
+ });
97
+
98
+ builder.core.transfer('send-half', {
95
99
  bind: {
96
- amount: builder.inputs.amountIn,
100
+ amount: head,
97
101
  recipient: builder.inputs.recipient,
98
102
  },
99
- config: { amount: '500000' },
103
+ config: {},
100
104
  });
101
105
 
102
- // Use the remainder in a swap.
103
- builder.lifi.swap('swap-remainder', {
104
- bind: { amountIn: out.remainder },
106
+ // Swap the rest.
107
+ builder.lifi.swap('swap-rest', {
108
+ bind: { amountIn: tail },
105
109
  config: {
106
110
  resourceOut: resources.native(1),
107
111
  slippage: 0.03,
@@ -0,0 +1,106 @@
1
+ import type { ComposeCompileRequest, Flow } from '@lifi/compose-spec';
2
+
3
+ import {
4
+ createComposeSdk,
5
+ guards,
6
+ materialisers,
7
+ resources,
8
+ } from '../index.js';
9
+ import type { Address } from '../types.js';
10
+
11
+ import { API_KEY, BASE_URL } from './config.js';
12
+
13
+ // Ethereum mainnet (chainId 1).
14
+ const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
15
+ const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
16
+ const UNISWAP_V2_ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';
17
+ const UNISWAP_V2_FACTORY = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f';
18
+ const USDC_WETH_PAIR = '0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc';
19
+
20
+ // Tolerance of the swap leg: the aggregator's `toAmountMin` lets the swap
21
+ // deliver up to 3% less WETH than quoted.
22
+ const SWAP_SLIPPAGE = 0.03;
23
+
24
+ export interface UniswapV2AddLiquidityInput {
25
+ readonly owner: Address;
26
+ readonly usdcAmount: `${bigint}`;
27
+ }
28
+
29
+ /**
30
+ * Deposit USDC alone into the Uniswap V2 USDC/WETH pair.
31
+ *
32
+ * - `core.split` halves the USDC input.
33
+ * - `lifi.swap` turns one half into WETH.
34
+ * - `uniswapV2.addLiquidity` deposits the other USDC half and the swapped
35
+ * WETH, minting the UNI-V2 LP token. Unused input comes back as residuals.
36
+ * - The request sweeps the LP token and the residuals to the signer.
37
+ */
38
+ export const buildUniswapV2AddLiquidity = ({
39
+ owner,
40
+ usdcAmount,
41
+ }: UniswapV2AddLiquidityInput): {
42
+ flow: Flow;
43
+ request: ComposeCompileRequest;
44
+ } => {
45
+ const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
46
+
47
+ const builder = sdk.flow(1, {
48
+ name: 'uniswap-v2-add-liquidity-usdc-weth',
49
+ inputs: {
50
+ usdcIn: resources.erc20(USDC, 1),
51
+ },
52
+ });
53
+
54
+ const { a: usdcHalf, b: usdcToSwap } = builder.core.split('split', {
55
+ bind: { source: builder.inputs.usdcIn },
56
+ config: { bps: 5000 },
57
+ });
58
+
59
+ const swap = builder.lifi.swap('swap', {
60
+ bind: { amountIn: usdcToSwap },
61
+ config: {
62
+ resourceOut: resources.erc20(WETH, 1),
63
+ slippage: SWAP_SLIPPAGE,
64
+ },
65
+ });
66
+
67
+ builder.uniswapV2.addLiquidity('add-liquidity', {
68
+ bind: {
69
+ tokenA: usdcHalf,
70
+ tokenB: swap.amountOut,
71
+ },
72
+ config: {
73
+ router: UNISWAP_V2_ROUTER,
74
+ factory: UNISWAP_V2_FACTORY,
75
+ pair: USDC_WETH_PAIR,
76
+ },
77
+ guards: [
78
+ // The router is called with zero minimums, so this band is the sandwich
79
+ // protection: it reverts unless the pool price read before the deposit
80
+ // stays within ±50 bps of the simulated price. It does not depend on the
81
+ // swap leg.
82
+ guards.band({ port: 'poolPrice', bps: 50 }),
83
+ // A swap that fills at its 3% minimum delivers less WETH, so the add
84
+ // mints less LP. The floor must cover that tolerance (300 bps) plus the
85
+ // 50 bps band, or a valid swap fill reverts the transaction.
86
+ guards.slippage({ port: 'liquidity', bps: 350 }),
87
+ ],
88
+ });
89
+
90
+ const flow = builder.build();
91
+
92
+ const request = sdk.request(flow, {
93
+ signer: owner,
94
+ inputs: {
95
+ usdcIn: materialisers.directDeposit({ amount: usdcAmount }),
96
+ },
97
+ // Sweep the LP token and the unused USDC/WETH back to the signer.
98
+ sweepTo: builder.context.sender,
99
+ // The UNI-V2 LP token is unpriced, so the default 500 bps price-impact
100
+ // check reads the deposit as a 100% loss. 0 skips the check; the `band`
101
+ // and `slippage` guards above are the protection.
102
+ maxPriceImpactBps: 0,
103
+ });
104
+
105
+ return { flow, request };
106
+ };