Skip to content

01a0a46b - Disclose whole-REALU rounding on OpenCryptoPay pay - #987

Open
TaprootFreakAI wants to merge 13 commits into
stagingfrom
feature/01a0a46b-pay-whole-realu-round-up
Open

TaprootFreakAI wants to merge 13 commits into
stagingfrom
feature/01a0a46b-pay-whole-realu-round-up

Conversation

@TaprootFreakAI

Copy link
Copy Markdown
Collaborator

EN:
The OpenCryptoPay intro and confirm screens now tell the user that every payment is rounded up to whole REALU shares, because there are no fractional shares, and leftover ZCHF stays in the wallet.
Invalid swap quotes no longer look payable, Pay re-enables after the process route pops, and handbook spec-81 documents the notice (slots 291–293).

DE:
Die OpenCryptoPay-Intro- und Bestätigungsseite sagen jetzt, dass jede Zahlung auf ganze REALU-Anteile aufgerundet wird, weil es keine halben Anteile gibt, und dass Rest-ZCHF in der Wallet bleibt.
Ungültige Swap-Quotes wirken nicht mehr zahlbar, Bezahlen wird nach dem Prozess-Route wieder aktiv, Handbook spec-81 dokumentiert den Hinweis (Slots 291–293).

Details

The confirm screen previously rendered a 0-REALU quote as Ready and left Pay disabled after a failed process step. Copy also never stated the whole-share rule.

This change:

  • Appends the rounding rule to payInfoBody and adds always-visible payQuoteRoundingNotice on the confirm screen.
  • Emits PayQuoteError when swap.isValid is false (AmountTooLow → existing insufficient-holdings copy).
  • Awaits Navigator.push and clears _navigating so Pay works again after pop.
  • Adds cubit/page tests for invalid quotes, the notice, and the re-enable path.
  • Adds handbook spec-81 with mappings 291–293 and bumps the screenshot count 299 → 302.

Golden PNGs are not regenerated in this commit. After merge-ready review, dispatch golden-regenerate.yaml on this branch so Visual Regression picks up the new notice.

The payment API remains the authority on the integer share count; the app only displays and explains it.

TaprootFreakAI and others added 5 commits September 15, 2026 13:16
Every payment rounds up to whole REALU shares because there are no
fractional shares. The intro and confirm screens state that leftover
ZCHF stays in the wallet. Invalid swap quotes no longer look payable,
and Pay re-enables after the process route pops.

Handbook spec-81 documents the confirm-screen notice (slots 291-293).
The confirm-screen regression test now pops the debug-wallet failure
sheet and process route the same way production Close does, so Pay is
asserted enabled after return.
Invalid swap quotes emit a typed PayQuoteError.insufficientHoldings
state. The view maps that to the existing insufficient-holdings string
via S.of(context), matching CONTRIBUTING localization rules.
After rebasing onto staging, bind-error overlays occupy 291-292. The
pay rounding cards keep 293-295 in both mapping and visible permalinks.
@TaprootFreakAI
TaprootFreakAI force-pushed the feature/01a0a46b-pay-whole-realu-round-up branch from 79737c3 to 0dcbaa8 Compare September 15, 2026 11:17
The cubit emits typed errors; copy lives in the view. Document pay
handbook slots 293-295 on PayInfoPage and PayQuotePage.
PayProcess now returns whether the swap ran. Success or retry-close
pops the quote page so Pay cannot sell REALU twice. A pre-swap failure
still returns to the quote with Pay enabled.
Pay re-enables only when the process route pops false (pre-swap
failure). A completed swap, retry-close, or AppBar/system back leaves
the quote so REALU cannot be sold twice. Failure sheets now read the
cubit swapCompleted flag.
A timeout or dropped 2xx can still have sent the REALU sale. Marking
swapCompleted before broadcastSwapTransaction keeps Pay from running
twice if the HTTP call then fails.
AmountTooLow is the API volume signal. Mapping it onto insufficient
holdings re-interpreted a backend string. Invalid quotes stay unpayable.
Once swapCompleted is set, a broadcast timeout is recovery, not a
re-scan. The retry sheet can close the quote without offering Pay again.
Invalid swaps already surface the API error 1:1. The named constructor
and view branch had no production caller.
The process cubit used to map every !isValid quote to insufficientZchf.
The API error string is now the failure message; Pay still does not run.
@TaprootFreakAI

Copy link
Copy Markdown
Collaborator Author

EN:
Ready after 3 review passes.
OpenCryptoPay pay rounds up to whole REALU shares, tells the user leftover ZCHF stays in the wallet, and leaves the quote after a swap so Pay cannot sell twice.

DE:
Bereit nach 3 Review-Durchläufen.
OpenCryptoPay-Zahlen rundet auf ganze REALU-Aktien auf, sagt dass Rest-ZCHF in der Wallet bleibt, und verlässt die Quote nach einem Swap, damit Pay nicht zweimal verkauft.

Details

Head f35b270deee7be856481b086db397a723934c4df (verified). Base staging. mergeable: MERGEABLE.

Review:

  • Quality/logic iterated on quote leave-after-swap, swapCompleted before broadcast, pay-only retry after a signed broadcast failure, and API error strings 1:1 (no mapping onto missing holdings).
  • One later note asked the re-enable widget test to drop the second Navigator.pop(false). Rejected: on this test surface the first pop only dismisses the debug-wallet sheet; without the second pop PayProcessView stays. Production already pops false after the sheet (pay_process_page.dart).
  • Navigator.pop instead of tapping Close: Close is off-screen (y=2660 vs 2400). Same pattern as the existing re-enable test.

Local check: Flutter 3.41.6 Docker — pay quote/process cubit and page tests.

@TaprootFreakAI
TaprootFreakAI marked this pull request as ready for review September 15, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant