Frontend: PresaleVestingPage claimError persists across chain switch back to target #166

Closed
opened 2026-05-06 02:33:08 +00:00 by Brouie · 5 comments
Brouie commented 2026-05-06 02:33:08 +00:00 (Migrated from gitlab.com)

split-out from #106 per @PlasticDigits. live walk on db00da4 PASSed items 1-3, item 4 (clear-on-chain-match) leaves a stale red panel.

repro at HEAD 390f9be

  1. /vesting, beneficiary with claimable > 0, on build target chain
  2. switch wallet to wrong chain (e.g. BNB 56)
  3. click Claim DOUB → metamask popup → reject the tx
  4. wagmi claimError renders red StatusMessage in VOUR WALLET card
  5. switch wallet back to build target chain
  6. observed: red error panel persists
  7. expected: clears the same way claimGateError clears via the chainId useEffect

clears today only via F5 reload or successful claim (resetWrite() on claimSuccess).

why

PresaleVestingPage.tsx:105-109 clears claimGateError only. wagmi claimError (line 93 destructure, rendered at line 270) has no chain-match clear path — only resetWrite() on claimSuccess at line 98-103.

suggested fix

extend the chain-match useEffect to call resetWrite() when claimError is set and chain matches. resetWrite already destructured at line 93. mirrors the post-success path.

severity

P3-low. UX polish, no security/correctness impact. matches parent #106 framing.

acceptance

  • chain switch back to target clears the wagmi claimError panel without reload
  • claimGateError semantics preserved
  • <ChainMismatchWriteBarrier> + disabled-button untouched
  • npm run typecheck + npm test clean

ref

parent #106, dev's file separately direction.

split-out from #106 per @PlasticDigits. live walk on `db00da4` PASSed items 1-3, item 4 (clear-on-chain-match) leaves a stale red panel. ## repro at HEAD `390f9be` 1. /vesting, beneficiary with `claimable > 0`, on build target chain 2. switch wallet to wrong chain (e.g. BNB 56) 3. click Claim DOUB → metamask popup → reject the tx 4. wagmi `claimError` renders red StatusMessage in VOUR WALLET card 5. switch wallet back to build target chain 6. observed: red error panel persists 7. expected: clears the same way `claimGateError` clears via the chainId useEffect clears today only via F5 reload or successful claim (`resetWrite()` on `claimSuccess`). ## why `PresaleVestingPage.tsx:105-109` clears `claimGateError` only. wagmi `claimError` (line 93 destructure, rendered at line 270) has no chain-match clear path — only `resetWrite()` on `claimSuccess` at line 98-103. ## suggested fix extend the chain-match useEffect to call `resetWrite()` when `claimError` is set and chain matches. `resetWrite` already destructured at line 93. mirrors the post-success path. ## severity P3-low. UX polish, no security/correctness impact. matches parent #106 framing. ## acceptance - [ ] chain switch back to target clears the wagmi `claimError` panel without reload - [ ] `claimGateError` semantics preserved - [ ] `<ChainMismatchWriteBarrier>` + disabled-button untouched - [ ] `npm run typecheck` + `npm test` clean ## ref parent #106, dev's [file separately direction](https://gitlab.com/PlasticDigits/yieldomega/-/work_items/106).
Brouie commented 2026-05-06 02:33:50 +00:00 (Migrated from gitlab.com)

mentioned in issue #106

mentioned in issue #106
PlasticDigits commented 2026-05-06 08:46:41 +00:00 (Migrated from gitlab.com)

mentioned in commit fe530bd60c

mentioned in commit fe530bd60cafe4f0b07c084cf768409567a4bf86
PlasticDigits commented 2026-05-06 08:47:56 +00:00 (Migrated from gitlab.com)

Implemented (GitLab #166)

Merged to main (c248ec9 merge commit): stale wagmi useWriteContract error on /vesting now clears when the wallet transitions wrong chain → build target, by calling reset() only on that transition (same recovery posture as claimGateError). Same-chain rejects stay visible until retry, successful claim, or another wrong-chain round-trip.

Code

Docs / invariants

Verification checklist (please confirm)

  • Wrong chain → reject claim (or any wagmi error) → switch back to VITE_CHAIN_ID: red claimError panel clears without reload.
  • Stay on target, reject claim: error remains until success / retry / wrong-chain round-trip (per invariant).
  • claimGateError behavior unchanged (clears when on target).
  • <ChainMismatchWriteBarrier> + disabled Claim DOUB unchanged.
  • cd frontend && npm run typecheck && npm test -- --run passes.

/cc @brouie — requesting verification on the above when you have a moment. Leaving this issue open until you sign off.

## Implemented (GitLab #166) Merged to `main` (`c248ec9` merge commit): stale wagmi `useWriteContract` **`error`** on `/vesting` now clears when the wallet transitions **wrong chain → build target**, by calling `reset()` only on that transition (same recovery posture as `claimGateError`). **Same-chain** rejects stay visible until retry, successful claim, or another wrong-chain round-trip. ### Code - `shouldResetWriteContractErrorAfterChainTransition` — [`frontend/src/pages/presaleVesting/presaleVestingWriteErrorChainReset.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/presaleVesting/presaleVestingWriteErrorChainReset.ts) - `usePresaleVestingChainWriteEffects` — [`frontend/src/pages/presaleVesting/usePresaleVestingChainWriteEffects.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/presaleVesting/usePresaleVestingChainWriteEffects.ts) - Vitest — [`presaleVestingWriteErrorChainReset.test.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/presaleVesting/presaleVestingWriteErrorChainReset.test.ts) ### Docs / invariants - **`INV-FRONTEND-166`** — [`docs/testing/invariants-and-business-logic.md` § #166](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/invariants-and-business-logic.md) - Manual QA — [`docs/testing/manual-qa-checklists.md` (#106 step 4 / #166)](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/manual-qa-checklists.md) - [`docs/frontend/presale-vesting.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/frontend/presale-vesting.md), [`docs/testing/strategy.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/strategy.md), [`skills/README.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/skills/README.md), contributor guardrails skill cross-links. ### Verification checklist (please confirm) - [ ] Wrong chain → reject claim (or any wagmi error) → switch **back** to `VITE_CHAIN_ID`: red **claimError** panel **clears** without reload. - [ ] Stay on target, reject claim: error **remains** until success / retry / wrong-chain round-trip (per invariant). - [ ] `claimGateError` behavior unchanged (clears when on target). - [ ] `<ChainMismatchWriteBarrier>` + disabled **Claim DOUB** unchanged. - [ ] `cd frontend && npm run typecheck && npm test -- --run` passes. /cc @brouie — requesting verification on the above when you have a moment. Leaving this issue **open** until you sign off.
Brouie commented 2026-05-07 02:40:12 +00:00 (Migrated from gitlab.com)

@PlasticDigits — source-side verification PASS on c248ec9 (fe530bd impl).

pure helper shouldResetWriteContractErrorAfterChainTransition at frontend/src/pages/presaleVesting/presaleVestingWriteErrorChainReset.ts:12-22 — three-condition gate (has error AND previous chain was mismatch AND current chain is target). deliberately does not trigger on first paint, same-wrong-chain, target → wrong, or wrong-A → wrong-B different-id. funneled through chainMismatchWriteMessage so any future target-predicate change cascades automatically.

custom hook usePresaleVestingChainWriteEffects at :7-38 — prevChainIdRef.current snapshot read at :20 before being overwritten at :21, dep array at :37 correctly includes writeContractError.

walking the checklist:

  1. claimGateError behavior unchanged — PASS. the old useEffect-on-page that cleared claimGateError when on target now lives inside the hook at :23-25 (if (!chainMismatchWriteMessage(chainId, env)) { setClaimGateError(null); }). manual setClaimGateError(null) on click at PresaleVestingPage.tsx:288 and on claimSuccess at :100-106 unchanged.

  2. <ChainMismatchWriteBarrier> + disabled Claim DOUB unchanged — PASS. barrier at PresaleVestingPage.tsx:249 enclosing wallet panel through :311, button predicate at :276-302 matches pre-patch (chainMismatchForWrites || !claimsEnabled || claimable === undefined || claimable === 0n || claimSubmitting || claimConfirming).

  3. typecheck + npm test — PASS. tsc -b clean (no output), vitest run 50 files / 295 passed at HEAD 284c15c. dedicated #166 test file presaleVestingWriteErrorChainReset.test.ts 5/5 PASS in 2ms.

  4. wrong chain → reject → switch back to target → red claimError panel clears — live UX walk pending (need MetaMask + Vite session). source path: helper returns true on the wrong→target transition with hasWriteContractError === true, hook calls resetWrite(), panel re-renders without claimError.

  5. stay-on-target reject → error persists until success / retry / wrong-chain round-trip — live UX walk pending. source path: helper returns false on same-target-chain (no transition), resetWrite() is not invoked, panel stays.

parking 1 + 2 on the live walk debt list — picking up next laptop session, will post follow-up confirmation. nothing on the source or test side suggests they fail; the gate logic + hook wiring + test coverage all check out.

one nit on test coverage worth folding into a follow-up if useful, otherwise drop:

  • wrong-chain → different-wrong-chain (e.g. 1 → 56) asserting no reset
  • chainId === 0 (disconnected wagmi) — wagmi returns 0 not undefined, currently treated as wrong-chain
  • round-trip wrong → target → wrong via renderHook to exercise the useRef "previous" tracking

flagging close-ready on the source side. happy to walk live 1+2 next session.

@PlasticDigits — source-side verification PASS on `c248ec9` (`fe530bd` impl). pure helper `shouldResetWriteContractErrorAfterChainTransition` at `frontend/src/pages/presaleVesting/presaleVestingWriteErrorChainReset.ts:12-22` — three-condition gate (has error AND previous chain was mismatch AND current chain is target). deliberately does not trigger on first paint, same-wrong-chain, target → wrong, or wrong-A → wrong-B different-id. funneled through `chainMismatchWriteMessage` so any future target-predicate change cascades automatically. custom hook `usePresaleVestingChainWriteEffects` at `:7-38` — `prevChainIdRef.current` snapshot read at `:20` before being overwritten at `:21`, dep array at `:37` correctly includes `writeContractError`. walking the checklist: 3. `claimGateError` behavior unchanged — PASS. the old useEffect-on-page that cleared `claimGateError` when on target now lives inside the hook at `:23-25` (`if (!chainMismatchWriteMessage(chainId, env)) { setClaimGateError(null); }`). manual setClaimGateError(null) on click at `PresaleVestingPage.tsx:288` and on claimSuccess at `:100-106` unchanged. 4. `<ChainMismatchWriteBarrier>` + disabled Claim DOUB unchanged — PASS. barrier at `PresaleVestingPage.tsx:249` enclosing wallet panel through `:311`, button predicate at `:276-302` matches pre-patch (`chainMismatchForWrites || !claimsEnabled || claimable === undefined || claimable === 0n || claimSubmitting || claimConfirming`). 5. typecheck + npm test — PASS. `tsc -b` clean (no output), `vitest run` 50 files / 295 passed at HEAD `284c15c`. dedicated `#166` test file `presaleVestingWriteErrorChainReset.test.ts` 5/5 PASS in 2ms. 1. wrong chain → reject → switch back to target → red claimError panel clears — live UX walk pending (need MetaMask + Vite session). source path: helper returns `true` on the wrong→target transition with `hasWriteContractError === true`, hook calls `resetWrite()`, panel re-renders without `claimError`. 2. stay-on-target reject → error persists until success / retry / wrong-chain round-trip — live UX walk pending. source path: helper returns `false` on same-target-chain (no transition), `resetWrite()` is not invoked, panel stays. parking 1 + 2 on the live walk debt list — picking up next laptop session, will post follow-up confirmation. nothing on the source or test side suggests they fail; the gate logic + hook wiring + test coverage all check out. one nit on test coverage worth folding into a follow-up if useful, otherwise drop: - wrong-chain → different-wrong-chain (e.g. 1 → 56) asserting no reset - `chainId === 0` (disconnected wagmi) — wagmi returns 0 not undefined, currently treated as wrong-chain - round-trip wrong → target → wrong via renderHook to exercise the useRef "previous" tracking flagging close-ready on the source side. happy to walk live 1+2 next session.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-09 04:57:31 +00:00
PlasticDigits commented 2026-05-13 15:13:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 42968aa984

mentioned in commit 42968aa984d165fe7e0ce8a09bbd7768e14c50d5
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#166
No description provided.