Harden claimCred post-transaction lifecycle (#347) #518

Merged
PlasticDigits merged 1 commit from issue-347-claim-cred-lifecycle into main 2026-06-25 22:23:04 +00:00
PlasticDigits commented 2026-06-25 21:59:21 +00:00 (Migrated from gitlab.com)

Summary

Hardens ArenaCharmCredCard claimCred post-transaction lifecycle (#347), parent gap #342.

  • After claimCred submit, waitForWriteReceipt runs before clearing pending UI (mirrors claimWarBowFlag in useArenaSaleSession).
  • On successful receipt, invalidateArenaWalletStatsQueries refetches indexer wallet stats (no RPC balance mirrors).
  • Reverted receipts do not invalidate; write errors surface via friendlyRevertFromUnknown under the claim button.
  • Claim button stays disabled through write + receipt wait (claimSubmitting).

Acceptance checklist

Criterion Verification Result
Claim waits for receipt before clearing pending state ArenaCharmCredCard.tsx claimSubmitting + executeClaimCred → waitForWriteReceipt; arenaCharmCredClaim.test.ts PASS
Wallet stats refetch after successful claim executeClaimCred calls invalidateArenaWalletStatsQueries; unit tests PASS
Button disabled during pending write disabled={!claimReady || claimPending || !address} where claimPending = claimWritePending || claimSubmitting PASS
ArenaCharmCredCard.test.tsx covers success path invalidation cd frontend && npm test -- ArenaCharmCredCard.test.tsx arenaCharmCredClaim.test.ts PASS
Frontend typecheck + lint + full tests cd frontend && npm run typecheck && npm run lint && npm test PASS
Manual Anvil: claim updates CRED balance without reload Requires live stack + Rabby; not run in this session SKIP

Third-party verification

cd frontend && npm run typecheck && npm run lint && npm test -- ArenaCharmCredCard.test.tsx arenaCharmCredClaim.test.ts

Manual (optional):

  1. bash scripts/start-qa-local-full-stack.sh --live-sale --no-swarm (or existing Anvil stack).
  2. Buy CHARM, advance epoch (hard reset / time warp), confirm claimable CRED in YOUR WALLET.
  3. Click Claim CRED — button stays disabled until receipt; CRED Balance updates within one indexer poll without full page reload.

Docs: INV-FRONTEND-347-CLAIM-CRED-LIFECYCLE in docs/testing/invariants-and-business-logic.md, docs/frontend/arena-views.md §347, skills/play-time-arena-doub/SKILL.md.

## Summary Hardens **`ArenaCharmCredCard`** `claimCred` post-transaction lifecycle ([#347](https://gitlab.com/PlasticDigits/yieldomega/-/issues/347)), parent gap [#342](https://gitlab.com/PlasticDigits/yieldomega/-/issues/342). - After `claimCred` submit, **`waitForWriteReceipt`** runs before clearing pending UI (mirrors `claimWarBowFlag` in `useArenaSaleSession`). - On successful receipt, **`invalidateArenaWalletStatsQueries`** refetches indexer wallet stats (no RPC balance mirrors). - Reverted receipts do **not** invalidate; write errors surface via **`friendlyRevertFromUnknown`** under the claim button. - Claim button stays disabled through write + receipt wait (`claimSubmitting`). ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Claim waits for receipt before clearing pending state | `ArenaCharmCredCard.tsx` `claimSubmitting` + `executeClaimCred` → `waitForWriteReceipt`; `arenaCharmCredClaim.test.ts` | PASS | | Wallet stats refetch after successful claim | `executeClaimCred` calls `invalidateArenaWalletStatsQueries`; unit tests | PASS | | Button disabled during pending write | `disabled={!claimReady \|\| claimPending \|\| !address}` where `claimPending = claimWritePending \|\| claimSubmitting` | PASS | | `ArenaCharmCredCard.test.tsx` covers success path invalidation | `cd frontend && npm test -- ArenaCharmCredCard.test.tsx arenaCharmCredClaim.test.ts` | PASS | | Frontend typecheck + lint + full tests | `cd frontend && npm run typecheck && npm run lint && npm test` | PASS | | Manual Anvil: claim updates CRED balance without reload | Requires live stack + Rabby; not run in this session | SKIP | ## Third-party verification ```bash cd frontend && npm run typecheck && npm run lint && npm test -- ArenaCharmCredCard.test.tsx arenaCharmCredClaim.test.ts ``` Manual (optional): 1. `bash scripts/start-qa-local-full-stack.sh --live-sale --no-swarm` (or existing Anvil stack). 2. Buy CHARM, advance epoch (hard reset / time warp), confirm claimable CRED in **YOUR WALLET**. 3. Click **Claim CRED** — button stays disabled until receipt; **CRED Balance** updates within one indexer poll without full page reload. Docs: **`INV-FRONTEND-347-CLAIM-CRED-LIFECYCLE`** in `docs/testing/invariants-and-business-logic.md`, `docs/frontend/arena-views.md` §347, `skills/play-time-arena-doub/SKILL.md`.
PlasticDigits commented 2026-06-25 22:01:25 +00:00 (Migrated from gitlab.com)

Security review — MR !518

Commit reviewed: da317e1d3d854b4f16007ee22f59def7bf10b9ce
Scope: Frontend hardening of ArenaCharmCredCard claimCred post-transaction lifecycle (executeClaimCred, receipt wait, wallet-stats invalidation, error surfacing). Docs/tests/skills only elsewhere in diff.

Outcome: FINDINGS: 0 medium+

Summary

Reviewed added/modified paths in arenaCharmCredClaim.ts, ArenaCharmCredCard.tsx, and related tests/docs. Traced attacker-controlled inputs to sinks:

Surface Attacker input Sink / control
claimEpoch Indexer claimable_cred_epoch (pre-existing) On-chain TimeArena.claimCred enforces epoch < lastBuyEpoch and weight > 0 || bonus > 0; bad epoch reverts (gas only). MR does not widen trust in indexer-derived epoch.
writeContractAsync Wallet-signed tx to configured addresses.timeArena User wallet is signer; contract nonReentrant + double-claim tests block repeat mint.
claimError UI RPC/wallet error strings via friendlyRevertFromUnknown React text escape; existing RPC URL redaction (redactSensitiveUrlsInUserMessage). No new HTML/dangerouslySetInnerHTML.
invalidateArenaWalletStatsQueries Only after non-reverted receipt Reverted txs throw before invalidation — avoids stale “claimed” UI; no authz boundary crossed (read-only indexer refetch).
Double-submit Rapid clicks claimPending disables button + onClick guard; on-chain revert on second claim if race wins. Same class as other arena writes; MR improves vs fire-and-forget submit.

waitForWriteReceipt / executeClaimCred mirror the established claimWarBowFlag pattern in useArenaSaleSession.ts and add an explicit reverted-receipt guard.

Prior security-review threads: none on this MR; nothing to re-report.

Inline findings: none (no block:security label applied).

## Security review — MR !518 **Commit reviewed:** `da317e1d3d854b4f16007ee22f59def7bf10b9ce` **Scope:** Frontend hardening of `ArenaCharmCredCard` `claimCred` post-transaction lifecycle (`executeClaimCred`, receipt wait, wallet-stats invalidation, error surfacing). Docs/tests/skills only elsewhere in diff. **Outcome:** `FINDINGS: 0` medium+ ### Summary Reviewed added/modified paths in `arenaCharmCredClaim.ts`, `ArenaCharmCredCard.tsx`, and related tests/docs. Traced attacker-controlled inputs to sinks: | Surface | Attacker input | Sink / control | |---------|----------------|----------------| | `claimEpoch` | Indexer `claimable_cred_epoch` (pre-existing) | On-chain `TimeArena.claimCred` enforces `epoch < lastBuyEpoch` and `weight > 0 \|\| bonus > 0`; bad epoch reverts (gas only). MR does not widen trust in indexer-derived epoch. | | `writeContractAsync` | Wallet-signed tx to configured `addresses.timeArena` | User wallet is signer; contract `nonReentrant` + double-claim tests block repeat mint. | | `claimError` UI | RPC/wallet error strings via `friendlyRevertFromUnknown` | React text escape; existing RPC URL redaction (`redactSensitiveUrlsInUserMessage`). No new HTML/`dangerouslySetInnerHTML`. | | `invalidateArenaWalletStatsQueries` | Only after non-reverted receipt | Reverted txs throw before invalidation — avoids stale “claimed” UI; no authz boundary crossed (read-only indexer refetch). | | Double-submit | Rapid clicks | `claimPending` disables button + onClick guard; on-chain revert on second claim if race wins. Same class as other arena writes; MR improves vs fire-and-forget submit. | `waitForWriteReceipt` / `executeClaimCred` mirror the established `claimWarBowFlag` pattern in `useArenaSaleSession.ts` and add an explicit reverted-receipt guard. **Prior security-review threads:** none on this MR; nothing to re-report. **Inline findings:** none (no `block:security` label applied).
PlasticDigits commented 2026-06-25 22:23:05 +00:00 (Migrated from gitlab.com)

mentioned in commit 7e8129dc1a

mentioned in commit 7e8129dc1a4d4321f7cd2cb5c13e3778b8c3ee8c
PlasticDigits (Migrated from gitlab.com) merged commit 7e8129dc1a into main 2026-06-25 22:23:05 +00:00
Sign in to join this conversation.
No reviewers
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!518
No description provided.