feat(pay): 收款模型改为单地址+唯一金额(#34/34A Phase A-C)
从"每单唯一 HD 地址"改为"单个固定收款地址 + 每单唯一金额",归集成本 O(订单数)→O(1)。 - store: pay_orders 加 user_ref/expect_amount(唯一金额)/matched_tx_id;新 orphan_payments 表; ActiveOrderByUser(同用户单订单)、AmountRecentlyUsed(迟到窗口内金额不复用)、TxHandled(幂等)、 RecordOrphan。去掉每单派生游标。 - pay: CreateOrder(userRef,sku,priceMicro)——同用户单订单校验 + 分配唯一金额(base+随机微尾数[1,9999]、 cooldown 内不复用),address 恒为收款地址。 - tron: Transfer 加 BlockTs(区块时间秒),取 block_timestamp。 - watcher: 单地址取到账,按"金额==expect && block_ts>建单"匹配 → paid;不匹配的到账 → orphan;幂等。 - httpapi: POST /order 加 user_ref,同用户重复 → 409;main 收款地址=PAY_RECEIVE_ADDRESS 或 xpub index0。 - 测试:唯一金额/同地址、同用户单订单、精确匹配、付错成孤儿、迟到不误配新单、付款早于建单不匹配、 超时、幂等、409,全绿。README 更新为单地址模型+API(user_ref/精确金额/orphan)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,8 +28,9 @@ func New(svc *pay.Service) http.Handler {
|
||||
}
|
||||
|
||||
type createReq struct {
|
||||
SKU string `json:"sku"`
|
||||
Amount int64 `json:"amount"` // micro-USDT (1e-6)
|
||||
UserRef string `json:"user_ref"`
|
||||
SKU string `json:"sku"`
|
||||
Amount int64 `json:"amount"` // base price, micro-USDT (1e-6)
|
||||
}
|
||||
|
||||
type orderResp struct {
|
||||
@@ -64,7 +65,11 @@ func (h *Handler) createOrder(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid json"})
|
||||
return
|
||||
}
|
||||
o, err := h.svc.CreateOrder(r.Context(), req.SKU, req.Amount)
|
||||
o, err := h.svc.CreateOrder(r.Context(), req.UserRef, req.SKU, req.Amount)
|
||||
if errors.Is(err, pay.ErrUserHasActiveOrder) {
|
||||
writeJSON(w, http.StatusConflict, map[string]string{"error": "user already has an active order"})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user