Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
07d8234
feat(frontend): add sign.error.unavailable i18n key
sbpublic Jun 18, 2026
c6fc9e4
feat(frontend): add toastsSignerUnavailableOr helper
sbpublic Jun 18, 2026
4f856b9
fix(frontend): friendly toast when chain-fusion signer is unavailable
sbpublic Jun 18, 2026
f5f199a
docs(frontend): document signer-outage toast behavior
sbpublic Jun 18, 2026
9899dd2
feat(frontend): add sign.error.limit_reached i18n key
sbpublic Jun 19, 2026
6b8915b
fix(frontend): distinguish per-user signing limit from signer outage
sbpublic Jun 19, 2026
5af2faa
fix(frontend): map Schnorr signer errors so SOL signing surfaces paym…
sbpublic Jun 19, 2026
1ba1774
docs(frontend): sync spec with shipped allowance + Schnorr behavior
sbpublic Jun 19, 2026
d680d79
feat(frontend): tag allowance-exceeded cfs_sign events as major, not …
sbpublic Jun 19, 2026
41473b2
feat(frontend): re-grant signer allowance in background on per-user l…
sbpublic Jun 19, 2026
6813678
docs(frontend): document the allowance auto-replenish behavior
sbpublic Jun 19, 2026
1462e33
🤖 Apply formatting changes
github-actions[bot] Jun 19, 2026
5935692
feat(frontend): add self-describing event_code + cfs context to cfs_sign
sbpublic Jun 19, 2026
a4355a3
docs(frontend): document event_code and the cfs event context
sbpublic Jun 19, 2026
d45785e
Merge remote-tracking branch 'origin/fix/frontend/signer-unavailable-…
sbpublic Jun 19, 2026
652c4ac
feat(frontend): finalize signer toast copy (calmer, less technical)
sbpublic Jun 19, 2026
4cb3e28
feat(frontend): translate sign.error.* for all supported languages
sbpublic Jun 19, 2026
9d1fcb8
Merge branch 'feat/frontend/track-cfs-sign-event' into fix/frontend/s…
sbpublic Jun 19, 2026
db777d2
Merge branch 'feat/frontend/track-cfs-sign-event' into fix/frontend/s…
sbpublic Jun 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions docs/ai/PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,25 @@ The event payload is built via the `buildLearnMoreEvent()` factory helper in `sr

Every paid chain-fusion-signer call fires a `cfs_sign` Plausible event on **both** success and error. The calls are wrapped at the single API chokepoint `src/frontend/src/lib/api/signer.api.ts` via the `withCfsSignTracking()` helper, so address/balance reads as well as the signing operations (ETH transaction / prehash / personal-sign, BTC sign / send, Schnorr, generic ECDSA) are all covered.

| Attribute | Value |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_context` | `signer` (`PLAUSIBLE_EVENT_CONTEXTS.SIGNER`) |
| `event_subcontext` | the called signer method (`PLAUSIBLE_EVENT_SUBCONTEXT_CFS`, e.g. `eth_sign_transaction`) |
| `result_status` | `success` / `error` |
| `result_duration_in_seconds`(`_rounded`) | measured wall-clock duration of the call |
| `token_network` | derived from the method prefix (`eth` / `btc` / `sol`); omitted for chain-agnostic generic calls |
| `result_error` / `result_error_text` | mapped message / full raw error text (error only) |
| `result_error_severity` | `blocker` when OISY's backend cannot pay the signer (it is out of cycles — a `SignerCanisterPaymentError`); `critical` for any other signer error (error only) |

The `blocker` severity makes the backend-out-of-cycles outage — which blocks signing for **every** user — visible on dashboards before support tickets arrive. Tracking is fire-and-forget: `withCfsSignTracking` always re-throws so it never swallows the underlying error or interrupts a send.
| Attribute | Value |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_context` | `cfs` (`PLAUSIBLE_EVENT_CONTEXTS.CFS`) — a dedicated context, distinct from the dApp-signer's `signer` |
| `event_subcontext` | the called signer method (`PLAUSIBLE_EVENT_SUBCONTEXT_CFS`, e.g. `eth_sign_transaction`) |
| `event_code` | self-describing outcome (`PLAUSIBLE_EVENT_CODES`), present on every event: `success`, `cfs_payment_failed_backend_out_of_cycles`, `cfs_payment_failed_user_allowance_exhausted`, or `cfs_generic_error`. Filter all payment failures via the `cfs_payment_failed_` prefix |
| `result_status` | `success` / `error` |
| `result_duration_in_seconds`(`_rounded`) | measured wall-clock duration of the call |
| `token_network` | derived from the method prefix (`eth` / `btc` / `sol`); omitted for chain-agnostic generic calls |
| `result_error` / `result_error_text` | mapped message / full raw error text (error only) |
| `result_error_severity` | `blocker` when OISY's backend cannot pay the signer (out of cycles — wallet-wide outage); `major` when the caller's allowance is exhausted (`isSignerCanisterAllowanceError` — an expected per-user limit); `critical` for any other signer error (error only) |

`event_code` (the cause) and `result_error_severity` (the alerting weight) are orthogonal: the code lets a dashboard filter "all payment failures" from one property (the shared `cfs_payment_failed_` prefix), while severity keeps the backend-out-of-cycles outage at `blocker` (it blocks signing for **every** user) and the expected per-user allowance limit at `major` so it isn't over-reported as an incident. Tracking is fire-and-forget: `withCfsSignTracking` always re-throws so it never swallows the underlying error or interrupts a send.

**User-facing behavior when signing can't be paid for.** When a signing call fails because the chain-fusion signer can't be paid (a `SignerCanisterPaymentError`), every affected flow — sending BTC/ETH/SOL, WalletConnect signing, and OpenCryptoPay payments — shows a calm message instead of the raw `Ledger error: …` text, distinguishing two cases:

- **Wallet-wide outage** (e.g. the backend is out of cycles): a neutral "Signing is temporarily unavailable. Please try again shortly." (`sign.error.unavailable`).
- **Per-user signing limit** (the caller's ICRC-2 allowance towards the signer is exhausted — `isSignerCanisterAllowanceError`, detected from a nested `InsufficientAllowance` in the ledger error): "You've reached your signing limit. Please try again shortly." (`sign.error.limit_reached`). In this case OISY also kicks off a best-effort background `allow_signing` re-grant (`replenishSignerAllowance`), so the next attempt can usually succeed without a page reload — unless the user has hit the `allow_signing` rate limit (the real per-user cap). The original operation is **not** auto-retried; the user retries it.

This is centralised in the `toastsSignerUnavailableOr` helper (`toasts.store.ts`), which the catch sites route through; genuine user errors (invalid address, insufficient token balance, gas) keep their existing specific messages. Swap flows already surface a generic failure message and so were left unchanged.

---

Expand Down
Loading
Loading