# 静态钱包

> 与特定订单或用户绑定的永久存款地址，适合周期性和长期支付场景。

静态钱包是用于接收加密货币付款的永久地址，与特定的 `order_id` 关联，按 `project_id + order_id + currency + network` 组合保持唯一。

适用场景：

- 来自同一用户的周期性存款
- 显示在用户资料页的长期收款地址
- 希望为每位用户保留稳定地址的高频充值场景

## 创建静态钱包

`POST /v1/static-wallet`

### 请求参数

| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `currency` | string | 是 | 加密货币（USDT、BTC、ETH 等） |
| `network` | string | 是 | 网络代码 |
| `order_id` | string | 是 | 您的订单 / 用户 ID（最多 255 个字符） |
| `label` | string | 否 | 钱包标签（最多 255 个字符） |
| `url_callback` | string | 是 | webhook 通知 URL |
| `invite_code` | string | 否 | 推荐人代码 |

### 请求示例

```json
{
  "currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "USER-123",
  "label": "User deposit #123",
  "url_callback": "https://your-site.com/webhook/static"
}
```

### 响应示例

```json
{
  "state": 0,
  "result": {
    "uuid": "019b2265-34d8-7001-a230-8f97de90d481",
    "address": "TXYZabc123...",
    "currency": "USDT",
    "network": "TRX-TRC20",
    "label": "User deposit #123",
    "order_id": "USER-123",
    "status": "active",
    "url": "https://go.2328.io/static/019b2265-34d8-7001-a230-8f97de90d481",
    "created_at": "2026-01-20T12:00:00Z",
    "qr": "data:image/png;base64,iVBORw0..."
  }
}
```

## 钱包信息

通过 `uuid` 或 `address` 获取静态钱包信息。

`POST /v1/static-wallet/info`

| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `uuid` | string | 是* | 静态钱包 UUID |
| `address` | string | 是* | 区块链钱包地址 |

> **INFO:** `uuid` 或 `address` 至少需要提供一个。

## 钱包列表

`POST /v1/static-wallet/list`

| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `status` | string | 否 | 按状态过滤（`active`、`inactive`） |
| `currency` | string | 否 | 按币种过滤 |
| `network` | string | 否 | 按网络过滤 |
| `order_id` | string | 否 | 按 order_id 过滤 |
| `page` | int | 否 | 页码（默认：1） |
| `per_page` | int | 否 | 每页条数（默认：20，最大：100） |

## 启用 / 禁用钱包

切换静态钱包是否接受新的支付。

`POST /v1/static-wallet/disable`

`POST /v1/static-wallet/enable`

两个端点都只接受单一参数：

```json
{
  "uuid": "019b2265-34d8-7001-a230-8f97de90d481"
}
```

## 钱包交易记录

获取静态钱包收到的所有充值。

`POST /v1/static-wallet/transactions`

| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `uuid` | string | 是 | 静态钱包 UUID |
| `date_from` | date | 否 | 起始日期（YYYY-MM-DD） |
| `date_to` | date | 否 | 结束日期（YYYY-MM-DD） |
| `page` | int | 否 | 页码（默认：1） |
| `per_page` | int | 否 | 每页条数（默认：15，最大：5000） |

## 静态钱包 webhook

当静态钱包收到付款时，系统会向 `url_callback` 发送 webhook。

> **WARNING:** 静态钱包 webhook 与常规支付 webhook 格式不同。特别是，静态钱包 webhook 包含 `merchant_amount` 字段，应使用该字段进行入账。

### Webhook 载荷

```json
{
  "uuid": "a28b293f-5c76-4053-8062-ae9ca4ab784b",
  "order_id": "USER-7666308594",
  "amount": "10.00000000",
  "currency": "USDT",
  "amount_usd": "10.00000000",
  "exchange_rate": "1.00000000",
  "payer_currency": "USDT",
  "payer_amount": "10.00000000",
  "network": "TRX-TRC20",
  "address": "TMU9Tgpchvgbywkbj5SdC8KJS73t5m3M7G",
  "payment_status": "paid",
  "txid": "8369ede26a0da05b1bae154b4bb4072eb2453db30ba86b21831902670929454f",
  "tx_explorer_url": "https://tronscan.org/#/transaction/8369ede26a0da05b1bae154b4bb4072eb2453db30ba86b21831902670929454f",
  "payment_amount": "10.00000000",
  "merchant_amount": "9.920000000000000000",
  "created_at": "2026-05-09T16:13:04+03:00",
  "sign": "dd958d1405febce670a9a196e9141784b9f2a5f39cd6d1832d6f3f68d0de1e10"
}
```

> **INFO:** 静态钱包 webhook **不包含** `url` 与 `expires_at`（地址是永久的，不存在会话概念），但**包含** `exchange_rate` 与 `created_at`。

### 字段说明

| 字段 | 类型 | 说明 |
|------|------|------|
| `uuid` | string | 本次充值的交易（账单）UUID |
| `order_id` | string | 您配置的静态钱包 `order_id` |
| `amount` | decimal (8 位小数) | 收到的加密货币金额 |
| `currency` | string | 收到的加密货币（与钱包 `currency` 一致） |
| `amount_usd` | decimal (8 位小数) | 收款时的美元等值 |
| `exchange_rate` | decimal | 加密货币 / 美元的汇率 |
| `payer_currency` | string | 静态钱包场景下与 `currency` 一致 |
| `payer_amount` | decimal (8 位小数) | 静态钱包场景下与 `amount` 一致 |
| `network` | string | 区块链网络 |
| `address` | string | 静态钱包地址 |
| `payment_status` | string | ?????????? `paid`?AML ?????????????? `aml_lock` |
| `txid` | string | 链上交易哈希 |
| `tx_explorer_url` | string \| null | 区块链浏览器中的交易链接。若没有 `txid` 或该转账为内部 P2P，则为 `null`。 |
| `payment_amount` | decimal (8 位小数) | 与 `amount` 一致 |
| `merchant_amount` | decimal (18 位小数) | **扣除手续费后的入账金额** — 应使用此字段为用户入账 |
| `created_at` | string (ISO 8601) | 收到充值的时间 |
| `sign` | string (hex) | 载荷的 HMAC-SHA256 签名 |

## 最佳实践

- **唯一的 `order_id`** — 为每个用户或订单使用唯一的 `order_id`
- **幂等性** — 入账前先按 `txid` 去重，避免重复入账
- **校验签名** — 入账资金前务必校验 `sign` 签名
- **使用 `merchant_amount`** — 按 `merchant_amount`（而非 `payment_amount`）为用户入账

## 生命周期和 idempotency

static wallet 是可重复使用的存款身份，而不是 invoice。它没有预期金额，也没有到期日。一个地址在其生命周期内可以产生任意数量的存款交易。

对于同一个 merchant 项目，创建为 idempotent、`order_id`、`currency` 和 `network`：返回现有钱包。保持该元组稳定并保留返回的钱包`uuid`；请勿在每次同一客户打开存款屏幕时使用新的 `order_id`。

充值idempotency与钱包idempotency不同：

- `order_id` 标识可重复使用的钱包/客户映射；
- 钱包`uuid`标识永久钱包记录；
- webhook `uuid` 识别出一笔检测到的存款交易；
- `txid` 标识链上转账，是记入的主去重密钥。

对已处理的链/网络/txid 身份使用数据库唯一性约束，并在记入客户内部余额的同一交易中声明它。

## 启用和禁用语义

禁用钱包会阻止应用程序将其作为活动存款目标处理；它不会删除地址或其历史记录，也无法停止用户已发送的区块链传输。

> **DANGER:** 切勿告诉用户发送到非活动地址的资金会自动退回。区块链转账是不可逆转的。仅在从用户界面中删除地址后禁用，并保留针对延迟存款的操作恢复程序。

重新启用会保留相同的钱包身份和地址。不要仅仅为了改变标签而创建替代品；标签不是 settlement 标识符。

## Static wallet 边缘情况

| 情况 | 正确处理 |
|-----------|------------------|
| 重复创建请求 | 接受返回的现有钱包并验证其持久元组，而不是期待新地址。 |
| 向一个地址进行多笔存款 | 为每笔交易创建单独的本地存款行`uuid`/`txid`；切勿将钱包本身标记为“已付款”。 |
| 重复 webhook | 找到已经提交的txid后返回HTTP 200；永远不要再赊账。 |
| 确认延迟或链重新观察 | 继续处理 idempotent 并从 `/v1/static-wallet/transactions` 进行调节。 |
| 存款低于最低 auto-convert | 预计源货币信贷没有完成 `convert` 块。 |
| Auto-convert 成功 | 分别存储源付款值和目标 `convert` 结果。 |
| 错误的令牌或错误的网络 | 请勿伪造信用。记录证据并升级为支持/恢复，因为可恢复性是特定于链的。 |
| 基于备忘录/标签的链 | 显示并验证平台返回的每个目标字段；当需要备忘录时，仅地址可能是不够的。 |
| 反洗钱锁定 | 在通过合规流程发布权威状态之前，请勿信任最终用户。 |
| 地址显示后钱包被禁用 | 立即将其从 UI 中删除，但继续监控延迟传输的操作警报。 |

## Reconciliation 型号

运行定期作业，对 `/v1/static-wallet/transactions` 进行分页，按 txid 更新插入存款，并将其 `merchant_amount`、状态和可选转换结果与您的内部分类帐进行比较。 Webhook 交付应该使 reconciliation 快速，但 reconciliation 必须使其完整。