Investigate: swap path rejects fee-less small tokens — CU107 'Outputs are required and must be an array' (1-sat single-proof V3)
メンテナーはふだん 1 日以内に返信
評価
調査の方向性
Start by tracing the receive path from merchant.Fund to the wallet swap and locating where swap outputs are constructed; the issue does not name files or tests. Compare fee/reserve handling with the mint’s reported input_fee_ppk and determine whether a real wallet can reproduce the failure. Done means identifying the cause and establishing whether this is a user-facing bug or a test-tooling artifact, with an appropriate response for affected payments.
索引モデルが issue の本文から書いたものです。
説明
Migrated from Amperstrand/tollgate-module-basic-go#95 as part of the fork retirement — OpenTollGate/tollgate-module-basic-go is the single source of truth; the fork issue carries the original discussion and any lab evidence. Retirement plan: see the tracking issue linked in the migration comment there.]
What happened
During PR validation on the QEMU virtual lab (ai-legion, OpenWrt 24.10.1 VM, testnut mint), a fee-less 1-sat V3 token (single proof, keyset 008e808b89acc141) was submitted through the captive portal. Client-side validation passed ("Valid Cashu token / 1 sat / You will receive 30.00 MiB"), then payment failed with:
Payment failed — #CU107
Payment processing failed: could not swap proofs: Outputs are required and must be an array
The error text is the mint's NUT-03 response — the swap request reached testnut with an empty/missing outputs array.
A fee-buffered token (11 sats minted, mirroring physical-router-test-automation/scripts/mint-token/main.go's feeBuffer = 10) succeeds through the identical path, as do 4-sat tokens (multiple proofs).
Repro (lab)
- Lab: OpenWrt VM 10.99.99.1, backend merchant mode (1 sat/step, 30 MiB steps), testnut.cashu.exchange.
- Mint 1 sat, single proof, V3 (
HttpMinter.mint(1)from PRTAlib/cashu.py). - Submit through the portal (or raw-body POST
text/plainto:2121). - Observe CU107 + mint error above;
logreadshows the swap failure.
Is it fees? — evidence both ways (needs a dig)
For the fee hypothesis: the failure boundary so far is amount/proof-count dependent (1 sat fails, 4/11 sats pass), which smells like a fee reserve being subtracted before outputs are constructed (outputs = amount − fee; fee ≥ amount → empty array). The Gonuts-era mint-token tool explicitly carries feeBuffer = 10 "because of fees".
Against: testnut's /v1/keysets reports input_fee_ppk: 0 for all keysets (including active 008e808b89acc141). If the mint charges nothing, a fee-based explanation requires a locally computed reserve (wallet-side heuristic, not the mint's advertised fee) — or the empty-outputs bug is something else entirely (e.g. single-proof denomination split edge in the swap-output construction).
Questions for whoever digs in
- Where exactly are swap outputs constructed on the receive path (merchant.Fund → wallet swap)? Gonuts vs backend code?
- Is there a fee/reserve computation that ignores
input_fee_ppkor assumes a minimum? - Can a real wallet produce a token that hits this? (If yes → user-facing bug, needs a clean error like "token amount below network fee"; if no → close as test-tooling artifact.)
- Should the backend pre-check
amount ≤ keyset feeand return a proper CU-code instead of surfacing the mint's raw 400?
Environment
- Backend: deployed on lab VM, gonuts-tollgate (version unconfirmed — binary undated; this repro predates any fresh-main deployment)
- Mint: testnut.cashu.exchange (Nutshell-CF/0.0.1),
input_fee_ppk: 0on all keysets - Full session log and portal error snapshot available in PRTA PR #114/#115 validation notes (2026-09-18)
- 主要言語
- Go
- スター
- 12
- フォーク
- 14
- 平均マージ
- 1日 6時間
- マージ済み PR(30日)
- 217
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
OpenTollGate/tollgate-module-basic-go のほかの issue
-
go-battery needs an ndsctl on PATH: TestPurchaseSessionGuardHoldsThroughTheOutcomeUnknownWindow fails on bare hosts (passes with stub)対応中かも @Amperstrand が 1 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
OpenTollGate/tollgate-module-basic-go#726 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
rebrand-literal-gutter: uhttpd section-vocabulary check trips on a COMMENT (uhttpd.luci in 92-tollgate-admin-setup:178)対応中かも @Amperstrand が 1 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
OpenTollGate/tollgate-module-basic-go#723 ·
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 20/100
OpenTollGate/tollgate-module-basic-go#768 ·
メンテナーはふだん 1 日以内に返信
-
Four drift fences for tests/contract/ (+ test.yml clean-container lane + pre-commit wiring)対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
OpenTollGate/tollgate-module-basic-go#767 ·
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 20/100
OpenTollGate/tollgate-module-basic-go#763 ·
メンテナーはふだん 1 日以内に返信
OpenTollGate/tollgate-module-basic-go の issue をすべて見る
似ている issue
-
agent-research agent-review-finding chore
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
jordansmall/spindrift#4922 ·
メンテナーはふだん 1 日以内に返信
-
gcsartifact: deleting a missing version returns an error対応中かも @ktsoator が今日担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 2 日以内に返信
-
govulncheck
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
Change wording for init command success message対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
enhancement pkg:sdk
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
aws/aws-durable-execution-sdk-go#144 ·
メンテナーはふだん 1 日以内に返信