> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> 安装 SDK，并在几分钟内将你的第一个 Flow 编译为 calldata。

本快速入门会构建一个最小化的 Flow，将 WETH 交换为 USDC，并将 USDC zap 进一个 Aave 借贷仓位 —— 与 [`swap-and-zap` 配方](/composer/composer-api/recipes/swap-and-zap)的形态相同。到最后你将得到一个 `ComposeCompileResult`，其中包含可供签名的 `transactionRequest.data`（calldata）。

有关 inputs、handle、materialiser、guard、前置条件（precondition）和提交的完整讲解，请在阅读本页后参见 [Build a Flow](/composer/composer-api/guides/build-a-flow)。

<Tip>
  **你不需要先学会每一个概念。** Composer 有它自己的术语 —— *Flow*、*operation*、*resource*、*input*、*materialiser*、*guard* —— 但本页会在每个术语首次出现在代码中时用一行话解释它。快速浏览一遍，运行示例，只有在你想深入时才去跟进那些链接的概念页面。**仅凭这一个示例就足以开始构建和试用 Composer。**
</Tip>

## 先决条件

* **Node.js ≥ 20** 和一个 TypeScript 项目（`tsc`、`tsx` 或 `ts-node` 都可以）。
* 一个在 Ethereum 主网上持有少量 WETH 的 EVM 账户（本示例使用 `1` WETH 作为演示）。
* 签名者的 `0x` 前缀地址。本快速入门**不会发送**交易；它止步于已编译的 calldata。签名者接线（viem、ethers 等）在 [Build a Flow](/composer/composer-api/guides/build-a-flow#wire-in-a-signer) 中介绍。
* 一个 **LI.FI API key**。Composer 处于技术预览阶段，每个请求都经过认证。在 [portal.li.fi](https://portal.li.fi) 注册，并从你的仪表盘创建一个 key。

<Note>
  **基础 URL。** 公开的 compose 端点由一个专用主机提供；SDK 默认为 `https://composer.li.quest`。如果你的集成使用暂存或内部环境，请向你的 LI.FI 联系人索取正确的 `baseUrl`。
</Note>

## 步骤

<Steps>
  <Step title="Install the SDK">
    `@lifi/composer-sdk` 包已发布在 npm 上。在稳定版本发布之前，请锁定 alpha 范围。

    ```bash theme={"system"}
    npm install @lifi/composer-sdk@alpha
    # or: yarn add @lifi/composer-sdk@alpha
    # or: pnpm add @lifi/composer-sdk@alpha
    ```
  </Step>

  <Step title="Create the SDK">
    `createComposeSdk` 返回一个句柄，其中包含一个 `flow` 工厂、一个低层 `client`，以及一个用于自定义 transport 的 `request` 辅助函数。在技术预览期间，`apiKey` 是**必需的**。

    ```ts theme={"system"}
    import { createComposeSdk } from '@lifi/composer-sdk';

    const sdk = createComposeSdk({
      baseUrl: 'https://composer.li.quest',
      apiKey: process.env.LIFI_API_KEY,
    });
    ```
  </Step>

  <Step title="Build the flow">
    一个 **Flow** 就是你在这里构建的文档：一个有序的步骤列表，会编译成一笔交易。你先声明它的 **inputs**，然后在 builder 上链式调用 **operations**。

    * 一个 **input** 是 flow 所消费的值。这里的 `amountIn` 是一个 **resource** —— 一个代币余额（1 WETH），Composer 会在它于各步骤之间移动时对其进行跟踪。（Input 也可以是普通的标量，比如一个 `uint256` 或一个 `address`。）
    * 一个 **operation**（*op*）是 flow 中的一个具名步骤，比如一次交换或一次存入。`builder.lifi.swap` 和 `builder.lifi.zap` 都是 op；`zap` 将 `swap` 的输出绑定为它自己的输入，把两者串接在一起。这两个只是[完整 op 目录](/composer/composer-api/ops)中的一小部分。

    Input 名称和节点 id（每个 op 的第一个参数）由你自行选择 —— 它们会成为你绑定运行时值的键，以及下游 op 引用的句柄。

    ```ts theme={"system"}
    const builder = sdk.flow(1, {
      name: 'swap-and-zap-quickstart',
      inputs: {
        amountIn: resources.erc20(WETH, 1),
      },
    });

    // Swap WETH → USDC, then zap into Aave.
    const swap = builder.lifi.swap('swap', {
      bind:   { amountIn: builder.inputs.amountIn },
      config: { resourceOut: resources.erc20(USDC, 1), slippage: 0.03 },
    });

    builder.lifi.zap('zap', {
      bind:   { amountIn: swap.amountOut },
      config: { resourceOut: resources.erc20(A_ETH_USDC, 1) },
    });
    ```

    有关 import 和地址常量，请参见下方的[完整示例](#full-example)。
  </Step>

  <Step title="Compile the flow">
    `builder.compile(run)` 会将 flow 发送到 `POST /compose`，对其进行模拟，并返回一个 `ComposeCompileResult`，其中包含你的用户签名所需的 calldata。

    这里的 `inputs` 映射为 flow 声明的每个 input 提供了具体的运行时值。`directDeposit` 是一个 **materialiser** —— 一个小描述符，告诉 Composer 在执行时*如何*获取代币（这里是通过 `transferFrom` 将恰好 1 WETH 拉进代理）。`sweepTo` 说明当 flow 结束时剩余余额去往何处。

    ```ts theme={"system"}
    const result = await builder.compile({
      signer: '0xYourSignerAddress',
      inputs: {
        amountIn: materialisers.directDeposit({
          amount: '1000000000000000000', // 1 WETH (18 decimals)
        }),
      },
      sweepTo: builder.context.sender,
    });
    ```

    `result.transactionRequest` 就是你交给钱包的东西：

    ```json theme={"system"}
    {
      "to":    "0x6b3e…1f04",  // your per-user execution proxy (== userProxy)
      "data":  "0x…",          // calldata the proxy delegatecalls into the VM
      "value": "0"
    }
    ```

    `to` 地址是**你的每用户执行代理** —— 与 `userProxy` 相同的值。在代理首次使用时，它反而是代理**工厂**，工厂会部署你的代理并在一笔交易中运行 flow。无论哪种方式，代理都会 `delegatecall` 共享的 Composer VM，因此 flow 在你自己代理的余额和存储上下文中执行。每条链上的 VM 和代理工厂地址在 [Addresses](/composer/composer-api/reference/addresses) 页面上。

    除了 `transactionRequest`，结果还携带 `userProxy`（执行地址）、`producedResources`（每个终端资源的模拟金额），以及签名者必须首先授予的任何 `approvals`。
  </Step>
</Steps>

## 完整示例

改编自 `composer-sdk-examples` 仓库中的 [`swapAndZap.ts`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/swapAndZap.ts)：

```ts theme={"system"}
import {
  createComposeSdk,
  guards,
  materialisers,
  resources,
} from '@lifi/composer-sdk';

const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';

const run = async () => {
  const sdk = createComposeSdk({
    baseUrl: 'https://composer.li.quest',
    apiKey: process.env.LIFI_API_KEY,
  });

  const builder = sdk.flow(1, {
    name: 'swap-and-zap-quickstart',
    inputs: {
      amountIn: resources.erc20(WETH, 1),
    },
  });

  // Swap WETH → USDC via LI.FI.
  const swapOutputs = builder.lifi.swap('swap', {
    bind: { amountIn: builder.inputs.amountIn },
    config: {
      resourceOut: resources.erc20(USDC, 1),
      slippage: 0.03,
    },
  });

  // Zap the swapped USDC into Aave's aEthUSDC position.
  builder.lifi.zap('zap', {
    bind: { amountIn: swapOutputs.amountOut },
    config: {
      resourceOut: resources.erc20(A_ETH_USDC, 1),
    },
    guards: [guards.slippage({ port: 'amountOut', bps: 100 })],
  });

  const result = await builder.compile({
    signer: '0xYourSignerAddress',
    inputs: {
      amountIn: materialisers.directDeposit({
        amount: '1000000000000000000', // 1 WETH (18 decimals)
      }),
    },
    sweepTo: builder.context.sender,
  });

  console.log(JSON.stringify(result.transactionRequest, null, 2));
};

run().catch((err) => {
  console.error(err);
  process.exit(1);
});
```

<Note>
  完整示例增加了步骤中没有的一个术语：一个 **guard**。zap 上的 `guards.slippage({ port: 'amountOut', bps: 100 })` 是一个 Composer 在执行*期间*强制执行的不变量 —— 这里是对 zap 输出的 1% 滑点下限 —— 因此 flow 会安全地失败，而不是以糟糕的条件执行。交换不需要 guard：它的 `slippage: 0.03` 配置已经将一个下限烘焙进了报价。
</Note>

## SDK 构建了什么

`builder.compile(run)` 不只是调用端点 —— 它会将带类型的 builder 状态序列化为线格式（wire-format）的 Flow 文档，将其发送到 `POST /compose`，并解析响应。如果你想看看线上实际是什么样子，把 `builder.compile(run)` 换成 `builder.build()`：

```ts theme={"system"}
const flow = builder.build();
console.log(JSON.stringify(flow, null, 2));
```

```json theme={"system"}
{
  "version": 1,
  "id": "swap-and-zap-quickstart",
  "chainId": 1,
  "inputs": [
    {
      "name": "amountIn",
      "resource": { "kind": "erc20", "token": "0xC02a…Cc2", "chainId": 1 }
    }
  ],
  "nodes": [
    {
      "id": "swap",
      "op": "lifi.swap",
      "bind":   { "amountIn": { "$ref": "input.amountIn" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0xA0b8…eB48", "chainId": 1 }, "slippage": 0.03 }
    },
    {
      "id": "zap",
      "op": "lifi.zap",
      "bind":   { "amountIn": { "$ref": "swap.amountOut" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0x98C2…6F5c", "chainId": 1 } },
      "guards": [ { "kind": "slippage", "port": "amountOut", "bps": 100 } ]
    }
  ]
}
```

这就是 compose 端点接收到的 Flow 文档。你在这里看到的每个 input 名称（`amountIn`）、节点 id（`swap`、`zap`）和 `$ref` 都恰好是你在上面 builder 中所写的 —— SDK 不会重命名或重写。有关完整的线格式参考，请参见 [Flow Structure](/composer/composer-api/concepts/flow-anatomy)。

## 你拿回了什么

`ComposeCompileResult` 是一个基于 `status` 的**可辨识联合（discriminated union）**。在读取形态专属字段之前先对它进行分支：

```ts theme={"system"}
if (result.status === 'success') {
  // transactionRequest is ready to sign
  await wallet.sendTransaction(result.transactionRequest);
} else {
  // status === 'partial' — only reachable with simulationPolicy: 'allow-revert'.
  // transactionRequest is still present, but simulation reverted.
  console.error(result.error.kind, result.error.message);
  console.error(result.simulationRevert); // structured revert diagnostics
}
```

在 `status: 'success'` 时，载荷包含：

* **`transactionRequest`** —— `{ to, data, value, gasLimit? }`。`to` 是你的执行代理（在代理首次使用时是代理工厂）；`data` 是代理 delegatecall 进 VM 的 calldata。
* **`userProxy`** —— 预测的执行代理地址（由代理工厂派生的一个确定性的每签名者合约；参见 [Account model](/composer/composer-api/overview#account-model)）。
* **`producedResources`** —— 终端资源名称到每个资源记录的映射。模拟金额位于 `<resource>.simulated?.amountOut` 和 `<resource>.simulated?.amountOutMin`。
* **`approvals`** —— 签名者在执行交易之前必须授予的 ERC-20 授权（不需要时省略）。
* **`priceImpact`** —— 当在 run 上设置了 `maxPriceImpactBps` 时，可选的美元价格影响明细。

在 `status: 'partial'` 时，载荷还额外携带 `error`（`{ kind, message }`）和 `simulationRevert`。仅当你在 run 上传入 `simulationPolicy: 'allow-revert'` 时才会返回这种形态；在默认的 `'strict'` 策略下，回滚会转而抛出一个 `ComposeError`。

## 后续步骤

你现在已经在实践中见过每一个核心概念 —— Flow、operation、resource、input、materialiser、guard。上面的示例足以开始试用。当你想要全面了解其中任何一个时，以下页面会更深入：

* [Build a Flow](/composer/composer-api/guides/build-a-flow) —— inputs、handle、materialiser、guard、前置条件和提交的完整讲解。
* [Flow Structure](/composer/composer-api/concepts/flow-anatomy) —— 你的 builder 所产生的 JSON 文档形态。
* [References](/composer/composer-api/concepts/ref-grammar) —— handle 如何在线上变成 `$ref` 字符串。
* [Recipes](/composer/composer-api/recipes) —— 三种典型的 flow 形态（Dust Sweep、Swap and Deposit、Split Deposits）。
