Skip to content

Give each faucet token card its own independent claim state - #179

Merged
IbrahimIjai merged 7 commits into
SO4-Markets:mainfrom
Chidubemkingsley:Faucet-give-each-token-card-its-own-claim-state
Jun 23, 2026
Merged

Give each faucet token card its own independent claim state#179
IbrahimIjai merged 7 commits into
SO4-Markets:mainfrom
Chidubemkingsley:Faucet-give-each-token-card-its-own-claim-state

Conversation

@Chidubemkingsley

Copy link
Copy Markdown
Contributor

Task done

  • Track per-token pending state via pendingTokens Set in useClaim

  • Separate isBulkPending for bulk claim button state

  • Each card derives isPending from pendingTokens membership

  • Bulk button shows pending only during bulk claim

  • Add spinner to individual card Claim button when pending

  • Closes Issue #2 — Faucet: give each token card its own claim state #175

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

@Chidubemkingsley is attempting to deploy a commit to the Ijai's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Chidubemkingsley
Chidubemkingsley force-pushed the Faucet-give-each-token-card-its-own-claim-state branch from e81e9ab to 6b3371b Compare June 23, 2026 09:37
@IbrahimIjai

Copy link
Copy Markdown
Contributor

Nice work, this is close, and a few things are done right that are easy to get wrong: the functional setPendingTokens((prev) => …) updater (no stale-closure bug), keeping pendingTokens out of the useCallback deps so claim isn't recreated on every pending change, and splitting isBulkPending from the per-token set. The per-card spinner is clean too.
Before we merge, a few things:

  1. Concurrency on a shared wallet (blocking, this is the real one).

The UI state is now independent per card, but walletKit.signTransaction is a single shared signer. Two claims in flight = two concurrent signing prompts, which the kit can't handle cleanly. Two ways to hit it today:

During a bulk claim, the individual cards stay enabled (claimDisabled doesn't include isBulkPending) and show no pending state, so a token already in the in-flight bulk tx can be claimed again → overlapping tx + cooldown collision + a second wallet prompt.
Same problem with two individual cards clicked back-to-back.

The issue asked us to define and document the rule. I'd keep per-token success/error state independent (so each card surfaces its own result), but serialize initiation through the shared signer — only one claim being signed at a time. Minimum viable: gate new claim triggers while anything is mid-flight. Nicer: queue them so each card still lights up its own pending state in turn. Either is fine, just pick one and write it in the PR description.
2. While bulk is running, reflect it on the cards. Right now all four show idle/clickable mid-bulk. They should at least read as pending (or disabled) so the user isn't firing a redundant individual claim on a token that's already being claimed.
3. Make "bulk" explicit instead of inferred. const isBulk = tokenIds.length === FAUCET_TOKENS.length couples intent to count — it breaks if the token list ever changes, and a single-token claim would read as bulk if there's ever one token. Prefer an explicit claimAll() vs claim(tokenId) (or a flag) so the caller states intent.
4. Guard double-submit in the hook, not just the button. Correctness shouldn't depend only on disabled. Early-return if every id is already pending, cheap defense in depth.
5. Nit: success toast is always plural "Test tokens claimed!" even for a single claim — mirror the singular/plural you already do on the loading toast.
6. DoD: confirm bun run typecheck + bun run lint pass, and drop the before/after GIF (claim one card → others stay idle; claim bulk → cards reflect it). That closes the issue's definition of done.
#1 is the only blocker — the rest are quick. Solid first pass.

@Chidubemkingsley
Chidubemkingsley force-pushed the Faucet-give-each-token-card-its-own-claim-state branch 2 times, most recently from 5613b42 to 8ba1d5c Compare June 23, 2026 09:47
- Track per-token pending state via pendingTokens Set<string> in useClaim
- Separate isBulkPending for bulk claim button state
- Each card derives isPending from pendingTokens membership
- Bulk button shows pending only during bulk claim
- Add spinner to individual card Claim button when pending
@Chidubemkingsley
Chidubemkingsley force-pushed the Faucet-give-each-token-card-its-own-claim-state branch from 8ba1d5c to 49d189f Compare June 23, 2026 09:49
- Serialize through shared signer via isClaimingRef (prevents concurrent
  wallet prompts)
- Explicit claimOne(tokenId) / claimAll() instead of inferring bulk
  from array length
- isBulkPending reflected on all cards during bulk claim
- Defense-in-depth: isClaimingRef gates new claims while any in-flight
- Singular/plural success toast matches single vs bulk claim
- Each card owns its own pending state via pendingTokens Set
- Per-card spinner shown while pending or during bulk claim
- Balance refresh via invalidateQueries preserved on success
@Chidubemkingsley
Chidubemkingsley force-pushed the Faucet-give-each-token-card-its-own-claim-state branch from 62a749c to c19bb18 Compare June 23, 2026 09:56
- earn: Remove unnecessary optional chaining/nullish coalescing on
  non-nullish values; fix import ordering and member sorting; merge
  duplicate imports
- referrals: Reorder imports (parent before internal); merge duplicate
  imports; convert string[] to Array<string>; remove unnecessary type
  assertions; fix import member sorting
- trade: Reorder imports across 15 files; remove unnecessary optional
  chaining, nullish coalescing, type assertions, async without await;
  merge duplicate imports; fix always-true conditionals
- pools: Fix import ordering (sibling after parent imports)
- wallet: Fix import ordering; split inline type imports; remove
  duplicate type imports
- glv-router-client: Merge duplicate imports; fix import ordering
- shared: Fix import ordering in NumberInput.tsx
- vite.config: Remove unnecessary nullish coalescing
- discover-tab.tsx: make handleEarn async (void -> Promise<void>)
- earn.ts: remove unused runMockWrite and fakeTxDelay
- affiliates-tab.tsx: normalize code with ?? null
- ConfirmationDialog.tsx: non-null assert collateralAddress at 4 usage sites
- TradePanel.tsx: non-null assert collateralAddress (fixes cascading index/param errors)
- useMarketsInfo.ts: remove unused totalOI
- AccountBadge.tsx: guard nullable useBalance() return
- bignum.test.ts: replace assert calls with vitest expect
@Chidubemkingsley

Copy link
Copy Markdown
Contributor Author

@IbrahimIjai

Pushed as c3e489b. All 38 typecheck errors should now resolve on the next CI run.

@IbrahimIjai

Copy link
Copy Markdown
Contributor

CCool

@IbrahimIjai
IbrahimIjai merged commit 775df6b into SO4-Markets:main Jun 23, 2026
1 of 2 checks passed
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.

Issue #2 — Faucet: give each token card its own claim state

2 participants