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

# Builder 钱包注册

> 通过钱包签名，为开发者的用户创建主账户交易密钥

开发者可通过以下两个接口接入以太坊钱包用户，并获得其主账户的 QFEX API 密钥，用于交易、读取数据及向已登记地址提取加密资产：

| 接口 | 身份认证 | 返回结果 |
| - | - | - |
| `GET /builder/web3/message` | 公开接口 | 需要钱包签署的消息 |
| `POST /builder/web3/api-key` | 具备 `register_user` 权限的 Builder API 密钥 | 用户交易密钥及账户标识符 |

示例使用预生产 REST API `https://api.qfex.io` 和交易 WebSocket `wss://trade.qfex.io`。实际集成请使用 QFEX 为您提供的环境 URL 和凭据。

本流程返回 API 密钥。[钱包会话认证](https://docs.qfex.com/cn/api-reference/wallet-authentication.md)返回访问令牌和刷新令牌；[OAuth](https://docs.qfex.com/cn/api-reference/builder-integration.md)则使用应用授权。

## 开始之前

开发者需要：

* 一个拥有有效 [Builder Code](https://docs.qfex.com/cn/api-reference/builder-codes.md) 的 QFEX 账户。
* 该账户的用户名，用于生成密钥标签。
* 由 Builder Code 所属账户拥有的现有 API 公开密钥和私密密钥。
* 在该 Builder API 密钥上启用 `register_user` 权限。请联系 [support@qfex.com](mailto:support@qfex.com)申请启用；`subaccount_ops` 不提供注册权限。

将 Builder 私密密钥保留在后端。浏览器只需要 Builder Code 和用户选定的钱包提供者，例如通过 EIP-6963 发现的 Rabby。浏览器将签名消息发送给您的后端，再由后端向 QFEX 发起已认证的注册请求。

## 1. 获取钱包消息

传入用户的以太坊地址及您的 Builder Code UUID：

```sh theme={null}
curl --get 'https://api.qfex.io/builder/web3/message' \
  --data-urlencode 'address=0x0000000000000000000000000000000000000001' \
  --data-urlencode 'builder_code=aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'
```

`200 OK` 响应包含 `message` 字符串。例如：

```text theme={null}
www.qfex.com wants you to sign in with your Ethereum account:
0x0000000000000000000000000000000000000001

Authorize QFEX to create a trading-only API key for builder aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa on my main account.

URI: https://www.qfex.com
Version: 1
Chain ID: 1
Nonce: 27c41a80ab6a61cf914075b1caffe3d8
Issued At: 2026-10-01T12:00:00Z
Expiration Time: 2026-10-01T12:10:00Z
```

上述仅为示例。必须原样签署接口实际返回的 `message`，不得修改。域名和 URI 由 QFEX 按环境配置，不要替换为您的应用 URL，也不要翻译签名消息。

接口会生成新的 nonce 及十分钟有效期。若签名或提交耗时过长，请重新获取消息。返回消息并不代表开发者代码存在或有效；这些检查在注册时执行。

## 2. 请求钱包签名

使用用户选定的 EIP-1193 提供者。Rabby 支持此接口。安装多个钱包时，请使用 EIP-6963 发现机制，不要假设 `window.ethereum` 就是用户选定的钱包。

```javascript theme={null}
export async function signBuilderMessage({ provider, builderCode }) {
  const accounts = await provider.request({ method: "eth_requestAccounts" });
  const address = accounts?.[0];
  if (!address) throw new Error("The wallet did not return an address");

  const chainId = await provider.request({ method: "eth_chainId" });
  if (Number.parseInt(chainId, 16) !== 1) {
    await provider.request({
      method: "wallet_switchEthereumChain",
      params: [{ chainId: "0x1" }],
    });
  }

  const url = new URL("https://api.qfex.io/builder/web3/message");
  url.searchParams.set("address", address);
  url.searchParams.set("builder_code", builderCode);

  const response = await fetch(url, { cache: "no-store", credentials: "omit" });
  const result = await response.json();
  if (!response.ok) {
    throw new Error(result.detail ?? "Could not fetch the wallet message");
  }

  const message = result.message;
  const hexMessage = "0x" + Array.from(
    new TextEncoder().encode(message),
    (byte) => byte.toString(16).padStart(2, "0"),
  ).join("");

  const signature = await provider.request({
    method: "personal_sign",
    params: [hexMessage, address],
  });

  return { message, signature };
}
```

用户授权前，应向其展示返回的消息。签名证明钱包所有权并授权创建交易密钥；不会提交链上交易，也不需要 gas。

将返回的 `{ message, signature }` 发送至后端。不要在消息字符串中添加 `Wallet signature` 字样或签名本身。

## 3. 注册用户并创建交易密钥

后端使用开发者凭据和以下四个 HMAC 请求头调用 `POST /builder/web3/api-key`：

| 请求头 | 值 |
| - | - |
| `x-qfex-public-key` | 开发者现有 API 公开密钥 |
| `x-qfex-nonce` | 为本次 HTTP 请求生成的全新密码学安全随机十六进制 nonce |
| `x-qfex-timestamp` | 当前 Unix 时间，单位为秒 |
| `x-qfex-hmac-signature` | 使用开发者私密密钥对 `nonce:timestamp` 进行 HMAC-SHA256 签名，再编码为十六进制 |

HTTP nonce 与钱包消息中的 nonce 相互独立。每次请求或重试都必须生成新的 HMAC 请求头。

Node.js 后端示例：

```javascript theme={null}
import crypto from "node:crypto";

export async function registerWalletUser({ message, signature }) {
  const publicKey = process.env.QFEX_BUILDER_PUBLIC_KEY;
  const secretKey = process.env.QFEX_BUILDER_SECRET_KEY;
  if (!publicKey || !secretKey) {
    throw new Error("Builder credentials are not configured");
  }

  const nonce = crypto.randomBytes(16).toString("hex");
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const hmacSignature = crypto.createHmac("sha256", secretKey)
    .update(`${nonce}:${timestamp}`)
    .digest("hex");

  const response = await fetch("https://api.qfex.io/builder/web3/api-key", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-qfex-public-key": publicKey,
      "x-qfex-nonce": nonce,
      "x-qfex-timestamp": timestamp,
      "x-qfex-hmac-signature": hmacSignature,
    },
    body: JSON.stringify({ message, signature }),
    cache: "no-store",
  });

  const result = await response.json();
  if (!response.ok) {
    throw new Error(result.detail ?? "Could not create the trading key");
  }
  return result;
}
```

请求体仅包含 `message` 和 `signature`。QFEX 从已认证的开发者账户解析 Builder Code，并要求签名消息明确授权同一个代码。此请求应使用开发者自己的 API 密钥，而非终端用户交易密钥。

钱包签名必须与消息中的地址一致。消息必须在十分钟内签发，不能过期或使用未来的签发时间，且域名与 URI 必须被 QFEX Auth 接受。

首次出现的钱包通过钱包注册创建 QFEX 用户和主账户；已有钱包恢复原用户。账户创建完成后，才能签发密钥。

## 响应与密钥权限

成功创建返回 `201 Created`，并带有 `Cache-Control: no-store`：

```json theme={null}
{
  "user_id": "11111111-1111-4111-8111-111111111111",
  "account_id": "11111111-1111-4111-8111-111111111111",
  "public_key": "qfex_pub_EXAMPLE",
  "secret_key": "qfex_secret_EXAMPLE"
}
```

| 属性 | 含义 |
| - | - |
| `user_id` | 与签名钱包关联的 QFEX 用户 |
| `account_id` | 该用户的主账户，等于 `user_id` |
| `public_key` | 终端用户新签发的 API 公开密钥 |
| `secret_key` | 终端用户新签发的 API 私密密钥，仅在创建时返回 |

该密钥授予主账户的订单执行权限，以及订单、持仓和余额读取权限。其 `view_balance` 权限还允许调用资金服务上的 `GET /address` 和 `GET /withdrawal-addresses`。通过 `POST /builder/web3/api-key` 签发或替换的密钥，还可以调用 `POST /withdraw`，向用户在所请求网络上已登记的地址提现。此权限无法在开发者设置中选择，且要求对所选账户拥有所有者访问权限。

`deposit_withdraw` 仍保持禁用：该密钥不能轮换充值地址、管理银行账户或提取美元。子账户不在其访问范围内。本接口不返回访问令牌或刷新令牌。资金服务 URL、认证请求头及示例见[程序化出入金](https://docs.qfex.com/cn/api-reference/programmatic-funding.md)。

请安全保存返回的凭据，避免记录或缓存。它们用于以钱包用户身份认证后续交易请求，不替代开发者自身的注册凭据。

## 密钥替换与交易归因

密钥标签为 `builder-` 加开发者账户用户名，例如 `builder-alice`。对同一用户、同一 Builder 标签再次签发密钥，会删除之前的密钥及其保存的私密部分。替换失败会回滚并保留旧密钥。其他用户和其他 Builder 标签的密钥不受影响。

密钥不会在使用后立即自动撤销。成功替换后，旧密钥无法再用于后续认证。以 `builder-` 或 `managed` 开头的密钥标签不显示在用户普通 API 密钥列表中。

使用返回的用户密钥执行 [HMAC 交易 WebSocket 身份认证](https://docs.qfex.com/cn/websocket/channels/trade/authenticate.md)，并在 `params.builder_code` 中包含您的 Builder Code UUID。仅凭密钥标签不会归因订单。每次重连都必须再次附加代码。

## 错误

| 状态 | 含义及下一步 |
| - | - |
| `400` | 地址、Builder UUID 或钱包消息无效。为正确的钱包和已认证的 Builder Code 获取新消息。 |
| `401` | 开发者或钱包认证失败。检查 HMAC 凭据、钱包签名及消息有效性。通用钱包错误也可能掩盖注册失败；若新签名消息仍失败，请联系 QFEX 支持团队。 |
| `403` | 开发者密钥缺少 `register_user` 权限，或其账户没有有效 Builder Code。 |
| `422` | 请求不符合所需查询参数或 JSON 模式。 |
| `502` | QFEX 无法加载开发者或签发密钥。开发者用户名及用户主账户必须存在；持续出错时请联系 QFEX 支持团队。 |

从浏览器直接调用时，API 必须通过 CORS 允许您的来源及请求头。底层 Auth 交换由后端处理；此 Builder 流程不要求前端调用 `/auth/v1/token?grant_type=web3`，也不要求前端持有 Auth 客户端密钥。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.