# 签名算法

## 签名原文

签名原文由 **5 行**组成，行之间使用 `\n` 分隔：

```
METHOD
URI
TIMESTAMP
NONCE
RAW_BODY
```

各字段说明：

| 字段          | 说明                                           |
| ----------- | -------------------------------------------- |
| `METHOD`    | HTTP 方法大写，例如 `GET`、`POST`、`DELETE`。          |
| `URI`       | 请求路径加排序后的 query string，不含域名，不含 context path。 |
| `TIMESTAMP` | 与 `x-api-ts` 完全一致，单位为毫秒。                     |
| `NONCE`     | 与 `x-api-nonce` 完全一致。                        |
| `RAW_BODY`  | 原始请求体字符串。无请求体时为空字符串。                         |

## Query String 排序规则

Query string 按参数名**升序**参与签名。例如实际请求为：

```
GET /api/v1/orders?page=1&limit=10
```

服务端用于签名的 `URI` 会重排序为：

```
/api/v1/orders?limit=10&page=1
```

{% hint style="warning" %}
同名参数出现多次时，服务端按参数名排序并保留同名参数解析后的值顺序。签名接口应避免使用同名 query 参数。
{% endhint %}

## Body 签名规则

JSON 请求必须使用 `Content-Type: application/json`。签名时使用的 `RAW_BODY` 必须与实际发送的 body 字符串**完全一致**，包括空格、换行和字段顺序。

`GET` 请求以及没有 body 的 `POST` 请求，`RAW_BODY` 使用空字符串。

## HMAC-SHA256 算法

```
x-api-sign = hex(HMAC_SHA256(payload, apiSecret))
```

其中 `payload` 为 5 行签名原文，`apiSecret` 是 API Key 对应的密钥。服务端按 UTF-8 编码计算 HMAC，输出 hex 字符串。

<details>

<summary>Python 签名实现</summary>

```python
import hmac
import hashlib
import json
from urllib.parse import urlencode

def canonical_uri(path: str, query: dict = None) -> str:
    if not query:
        return path
    sorted_pairs = sorted(query.items(), key=lambda x: x[0])
    return f"{path}?{urlencode(sorted_pairs)}"

def sign_trading_api(
    method: str,
    path: str,
    query: dict = None,
    timestamp: int = None,
    nonce: str = None,
    raw_body: str = "",
    api_secret: str = "",
) -> str:
    import time
    import uuid
    timestamp = timestamp or int(time.time() * 1000)
    nonce = nonce or str(uuid.uuid4())

    uri = canonical_uri(path, query)
    payload = f"{method.upper()}\n{uri}\n{timestamp}\n{nonce}\n{raw_body}"

    return hmac.new(
        api_secret.encode("utf-8"),
        payload.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
```

</details>

<details>

<summary>cURL 签名示例</summary>

```bash
# 1. 构造签名原文
METHOD="GET"
URI="/api/v1/symbols"
TIMESTAMP=$(date +%s%3N)
NONCE=$(uuidgen)
RAW_BODY=""

# 2. 拼接 payload
PAYLOAD="${METHOD}\n${URI}\n${TIMESTAMP}\n${NONCE}\n${RAW_BODY}"

# 3. 计算 HMAC-SHA256
SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$API_SECRET" -hex | awk '{print $NF}')

# 4. 发送请求
curl -X GET "https://rwa-api.anchored.finance/rwa/trading/api/v1/symbols" \
  -H "x-api-key: ${API_KEY}" \
  -H "x-api-ts: ${TIMESTAMP}" \
  -H "x-api-nonce: ${NONCE}" \
  -H "x-api-sign: ${SIGNATURE}" \
  -H "x-api-chain-id: 10143" \
  -H "x-api-p: Anchored"
```

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.anchored.finance/trading-api-docs-zh/jian-quan/signature.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
