Skip to content

feat: Deposit refunds for foreclosed applications - #484

Merged
brunomenezes merged 10 commits into
mainfrom
feat/add-deposit-refunds
Oct 28, 2026
Merged

brunomenezes merged 10 commits into
mainfrom
feat/add-deposit-refunds

Conversation

@brunomenezes

@brunomenezes brunomenezes commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Summary

Offer refunds of portal deposits on foreclosed applications, through the permissionless IApplication.issueRefund contract call. The node does not index refunds, so the explorer reads each deposit's refund flag on chain and keeps the rest of the data flow unchanged.

A deposit is refundable when the application is foreclosed and its input sits in an epoch after the last accepted one. Anyone can issue the refund: the contract pays the original depositor and the caller only pays gas.

Refunds

  • Refundable deposits table on the application summary page, shown only for a foreclosed application with at least one such deposit: input, asset, depositor, epoch and status for the latest three deposits. Deposits are fetched per portal sender (Ether, ERC-20, ERC-721, ERC-1155 single and batch) from the last accepted epoch on, so generic inputs never hide them. The table scrolls sideways on phones.
  • Refund action on every refundable deposit card, both in the summary page's latest inputs and on the epoch details page, with the asset and depositor and a call to action. Statuses: refundable, refunding, refunded and failed. Refunded deposits stay listed with their status.
  • Refunds summary card with the number of refunds already issued, read from getNumberOfIssuedRefunds.
  • Token symbol and decimals are read on chain in one batched call per distinct token and cached, so amounts render as 250 USDC rather than raw units; a token without metadata falls back to units and its address.
  • Plain-English error copy keyed by contract error name for the reachable reverts (RefundAlreadyIssued, InsufficientFunds), the token's own revert reason when there is one, and a generic fallback. A wallet rejection simply returns the button to its previous state.
  • When the refund flag cannot be read, the card says so and offers a "Check again" button; a failed simulation is re-run on the next click before anything is sent.
  • After a confirmed refund the page refetches the refundable table and the refunds count through the page Meta refetch, with no block polling.

Summary counters

  • The summary cards collapse beyond the first row, with a drawer-style edge and a caret to expand; phones keep the top two visible.

Components, hooks & helpers

  • Address keeps its icon and text on a single line when given wrap="nowrap", instead of wrapping or breaking the address; callers that pass nothing are unchanged.
  • useDisputeSender renamed to useTransactionSender, since it now guards every permissionless write, not only disputes.
  • getRevertErrorName, getRevertReason and isUserRejection helpers over viem errors.

Testing

  • Stories for every refund state under Components/Refund, including a phone-width table, plus foreclosed scenarios on the epoch details and application summary pages, backed by a shared MSW handler that answers the refund reads.
  • Unit and component tests for the hooks, helpers, views, actions and pages.

Manual check on a local devnet with the Cartesi CLI:

  1. cartesi create
  2. set the withdrawal config in cartesi.toml with the guardian as an account you control
  3. cartesi build → cartesi run
  4. open the explorer and connect it to the node
  5. send a few deposits (cartesi deposit ether, ERC-20, ERC-721, ERC-1155)
  6. as the guardian, foreclose the application before the epoch settles → open the application summary

Then:

  • The summary shows the Refundable deposits table with the latest three deposits and a Refunds card at zero.
  • Each deposit in Latest inputs has a refund section with the asset, the depositor and a Refund deposit button.
  • Click the epoch to open its details: every refundable input carries the same refund area, showing its status or the call to action.
  • Click Refund deposit → sign in the wallet → the card shows refunding, then refunded with the transaction hash, the table row flips to refunded and the Refunds card increments. Repeating the refund on the same input shows the "already refunded" message.

@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
dave Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-arbitrum-mainnet Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-arbitrum-sepolia Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-base-mainnet Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-base-sepolia Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-mainnet Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-optimism-mainnet Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-optimism-sepolia Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-sepolia Ready Ready Preview Oct 26, 2026 12:17pm UTC
rollups-explorer-workshop Ready Ready Preview Oct 26, 2026 12:17pm UTC

Request Review

@brunomenezes

Copy link
Copy Markdown
Member Author

@copilot review this PR for bugs

Copilot AI commented Oct 23, 2026

Copy link
Copy Markdown

@copilot review this PR for bugs

Bug (medium): RefundDepositAction.tsx:58, 95–103 ignores refund.error. If wasRefundForInputIssued fails, refundIssued stays undefined, so status remains unknown; the simulation is disabled (64) and the view renders a perpetually loading button (RefundDepositView.tsx:151). Users cannot retry or issue the refund. Handle the status-read error or expose a retry path.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Refund discovery can omit eligible deposits, missing epoch data can expose invalid offers, and failed simulations cannot be retried through the button.

3 open issues
What changed in this PR

Adds permissionless deposit refunds to the explorer for foreclosed applications, using on-chain refund status while preserving the node’s existing data flow.

Changes:

  • Adds refund discovery, asset metadata, status displays, transaction actions, and summary counters.
  • Integrates refunds into application summaries and epoch pages, and makes summary counters collapsible.
  • Extracts the shared transaction sender and adds refund fixtures, stories, and tests.
File Description
apps/​explorer/​test/​page/​EpochPage.test.tsx Tests foreclosure-based refund visibility.
apps/​explorer/​test/​page/​ApplicationSummaryPage.test.tsx Tests refund displays and refresh callbacks.
apps/​explorer/​test/​lib/​contractErrors.test.ts Tests revert and wallet-rejection helpers.
apps/​explorer/​test/​components/​transactions/​hooks/​useTransactionSender.test.tsx Tests wallet and network guards.
apps/​explorer/​test/​components/​refund/​RefundDepositView.test.tsx Tests refund states and asset displays.
apps/​explorer/​test/​components/​refund/​RefundDepositAction.test.tsx Tests refund transaction behavior.
apps/​explorer/​test/​components/​refund/​RefundableDeposits.test.tsx Tests table contents and links.
apps/​explorer/​test/​components/​refund/​lib/​refundUtils.test.ts Tests decoding, formatting, and eligibility helpers.
apps/​explorer/​test/​components/​refund/​hooks/​useRefundStatus.test.tsx Tests individual and batched status reads.
apps/​explorer/​test/​components/​refund/​hooks/​useRefundAssets.test.tsx Tests token metadata enrichment.
apps/​explorer/​test/​components/​refund/​hooks/​useRefundableDeposits.test.tsx Tests deposit discovery and filtering.
apps/​explorer/​test/​components/​refund/​hooks/​useIssuedRefundCount.test.tsx Tests refund count reads.
apps/​explorer/​test/​components/​input/​InputList.test.tsx Tests refund action integration.
apps/​explorer/​test/​components/​application/​SummaryCards.test.tsx Tests counter expansion and collapse.
apps/​explorer/​src/​stories/​refunds.ts Adds refund fixtures and mocked chain reads.
apps/​explorer/​src/​stories/​deposits.ts Adds encoded portal deposit fixtures.
apps/​explorer/​src/​page/​EpochPage.tsx Supplies application and epoch context to inputs.
apps/​explorer/​src/​page/​EpochPage.stories.tsx Adds foreclosed epoch scenarios.
apps/​explorer/​src/​page/​ApplicationSummaryPage.tsx Integrates refunds and collapsible counters.
apps/​explorer/​src/​page/​ApplicationSummaryPage.stories.tsx Adds a refundable-deposit scenario.
apps/​explorer/​src/​lib/​contractErrors.ts Adds contract error inspection helpers.
apps/​explorer/​src/​content/​refundMessages.ts Defines refund labels and error copy.
apps/​explorer/​src/​content/​index.ts Exposes refund messages.
apps/​explorer/​src/​content/​globalMessages.ts Adds counter controls and shared copy.
apps/​explorer/​src/​containers/​ApplicationSummaryContainer.tsx Connects refund data and refresh callbacks.
apps/​explorer/​src/​components/​transactions/​hooks/​useTransactionSender.ts Extracts the shared transaction guard.
apps/​explorer/​src/​components/​tournament/​InnerTournamentAction.tsx Uses the extracted transaction guard.
apps/​explorer/​src/​components/​refund/​RefundDepositView.tsx Displays refund assets, actions, and states.
apps/​explorer/​src/​components/​refund/​RefundDepositView.stories.ts Covers refund display scenarios.
apps/​explorer/​src/​components/​refund/​RefundDepositAction.tsx Implements simulation, submission, and confirmation.
apps/​explorer/​src/​components/​refund/​RefundDepositAction.stories.ts Adds actionable and refunded scenarios.
apps/​explorer/​src/​components/​refund/​RefundableDeposits.tsx Displays the latest refundable deposits.
apps/​explorer/​src/​components/​refund/​RefundableDeposits.stories.ts Demonstrates the refund table.
apps/​explorer/​src/​components/​refund/​lib/​refundUtils.ts Adds deposit, asset, and status helpers.
apps/​explorer/​src/​components/​refund/​hooks/​useRefundStatus.ts Reads refund flags on chain.
apps/​explorer/​src/​components/​refund/​hooks/​useRefundAssets.ts Batches and caches token metadata reads.
apps/​explorer/​src/​components/​refund/​hooks/​useRefundableDeposits.ts Discovers deposits across portal senders.
apps/​explorer/​src/​components/​refund/​hooks/​useIssuedRefundCount.ts Reads the issued-refund count.
apps/​explorer/​src/​components/​match/​MatchTimeoutAction.tsx Uses the extracted transaction guard.
apps/​explorer/​src/​components/​input/​InputList.tsx Adds refund actions to input cards.
apps/​explorer/​src/​components/​input/​InputCard.tsx Adds a footer slot for refund content.
apps/​explorer/​src/​components/​input/​InputCard.stories.tsx Demonstrates a refund footer.
apps/​explorer/​src/​components/​dispute/​DisputeAction.tsx Removes the extracted sender hook.
apps/​explorer/​src/​components/​application/​SummaryCards.tsx Adds responsive, collapsible counters.
apps/​explorer/​src/​components/​application/​SummaryCards.stories.ts Demonstrates counter layouts and states.
apps/​explorer/​src/​components/​application/​SummaryCards.module.css Styles the counter fade and expansion control.

Review effort: Balanced

@github-project-automation github-project-automation Bot moved this from Todo to Waiting Merge in Rollups SDK Oct 28, 2026
@github-project-automation github-project-automation Bot moved this from 👁 In Review to 👍 Waiting Merge in Rollups Tooling Oct 28, 2026
@brunomenezes
brunomenezes merged commit e2bce93 into main Oct 28, 2026
20 of 21 checks passed
@brunomenezes
brunomenezes deleted the feat/add-deposit-refunds branch October 28, 2026 19:26
@github-project-automation github-project-automation Bot moved this from 👍 Waiting Merge to 📦 Done in Rollups Tooling Oct 28, 2026
@github-project-automation github-project-automation Bot moved this from Waiting Merge to Done in Rollups SDK Oct 28, 2026

This branch was successfully deployed

10 active deployments
Preview – dave — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-workshop — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-optimism-mainnet — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-sepolia — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-mainnet — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-optimism-sepolia — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-base-mainnet — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-arbitrum-mainnet — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-base-sepolia — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Preview – rollups-explorer-arbitrum-sepolia — 4eefe414 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apps:explorer New rollups explorer. Type: Feature Add a new feature to the system

Projects

Status: Done
Status: 📦 Done

Development

Successfully merging this pull request may close these issues.

4 participants