feat: add multi-chain support for Base, Arbitrum, and Ethereum#111
Closed
rube-de wants to merge 50 commits intooasisprotocol:masterfrom
Closed
feat: add multi-chain support for Base, Arbitrum, and Ethereum#111rube-de wants to merge 50 commits intooasisprotocol:masterfrom
rube-de wants to merge 50 commits intooasisprotocol:masterfrom
Conversation
- Remove Roffle contract, tests, deploy tasks, and frontend components - Add beads for issue tracking - Add serena for code intelligence - Add CLAUDE.md and AGENTS.md project docs - Update .gitignore for macOS artifacts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Council review identified 6 P0 and 3 P1 issues. All fixes implemented: P0 Fixes: - P0-1: Fix stale closure bug on currentStep using useRef - P0-2: Validate paymentId before polling to prevent stuck funds - P0-3: Add AbortController for cancellation support - P0-4: Make pollPayment throw on timeout instead of silent null - P0-5: Wrap finally block chain switch in try-catch - P0-6: Add duplicate submission guard with isLoadingRef P1 Fixes: - Increase minIncrease threshold from 1 wei to 0.001 ROSE - Remove currentStep from dependency array (use ref instead) - Add context to additionalSteps errors Breaking change: ProgressStepWithAction.action now accepts AbortSignal Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Codex review identified additional issues:
- Fix memory leak: Add { once: true } to abort signal event listeners
to prevent listener accumulation in polling loops
- Add useEffect cleanup: Abort in-flight operations on component unmount
- Make catch block cancellable: Polling error retry delay now respects
abort signal instead of forcing 4s wait
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ster Replace hardcoded polling and timeout values with descriptive constants: - POLL_INTERVAL_MS (4000): Interval between payment status checks - POLL_MAX_ATTEMPTS (60): Maximum polling attempts before timeout - BALANCE_CHECK_TIMEOUT_MS (180000): Maximum wait for balance increase - MIN_BALANCE_INCREASE_THRESHOLD (1e15): Minimum meaningful balance change Remove temporary code review annotations (P0/P1 FIX comments) and replace with concise inline documentation explaining the purpose of each guard and error handling mechanism. Improves code maintainability by making timing configurations explicit and self-documenting, while reducing visual noise from review artifacts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Re-throw errors in catch block instead of swallowing - Use consistent undefined checks for feed values - Simplify initialLoading logic for readability
- Remove redundant .catch() block that just re-throws - Simplify step initialization (remove duplicate currentStepRef/setCurrentStep) - Include transaction hash in error message when deposit lacks paymentId - Make isLoadingRef check-and-set atomic to prevent theoretical race - Abort any lingering controller before creating new one (defensive)
Components created: - BridgeCard: main container with sections and divider - AmountInput: token amount input with decimal validation and MAX button - TokenSelector: dropdown for source/destination token selection - FeeBreakdown: transaction details and fee estimates display Code review fixes applied: - P0: TokenSelector uses chainId:address composite key for cross-chain safety - P0: AmountInput includes gas buffer support for native tokens - P1: Labels linked to inputs with useId() for accessibility - P1: FeeEstimate rate display uses relative positioning (overflow fix) - P2: Stable keys in FeeBreakdown list rendering - P2: Added aria-hidden to decorative SVGs Closes #2 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address Copilot review comment: BridgeCardSection is a container that wraps children with their own labeled inputs. Using <label> without htmlFor creates dangling/competing label semantics. Changed to <span> for semantic correctness. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add network-specific documentation for gasBuffer prop - Improve getTokenKey fallback to use symbol:name for collision safety Storybook stories tracked in paymaster-ui-xyl for follow-up. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per Copilot review suggestion - the variable is only used for isLast calculation, not as a React key. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete transformation from raffle dApp to cross-chain bridge interface: - Replace raffle components (tickets, winners, timers, FAQ) with bridge UI - Integrate BridgeCard, AmountInput, TokenSelector, and FeeBreakdown components - Implement Base (USDC/USDT) to Sapphire (ROSE) bridging flow via usePaymaster - Reduce component complexity from ~850 to ~345 lines - Fix footer link to use correct oasis.net domain - Return transaction hash from paymasterVault deposit for improved error handling - Update usePaymaster hook to utilize returned hash property Closes #3 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add getRoseEstimate function (inverse of getQuote) to calculate ROSE output for token input amount - Fix slippage direction: subtract from ROSE output (user receives less) - Add null guard for tokenConfig with fallback to first token - Fix useEffect dependency to use stable getRoseEstimate reference - Calculate and display actual exchange rate instead of hardcoded string Fixes: paymaster-ui-7h5, paymaster-ui-l6v, paymaster-ui-tjf, paymaster-ui-dug
- Fix handleTokenChange signature to match TokenSelector API
- Make TokenSelector.onChange optional when singleToken=true
- Add console.warn for estimate fetch errors (aids debugging)
- Remove empty onChange prop from destination selector
Note: depositResult.hash fallback comment rejected - paymasterVault.ts
returns { hash } directly, no transactionHash property exists.
- Fix FeeEstimate to use roseEstimate instead of quote - Fix handleBridge deps: use paymaster.startTopUp not paymaster - Fix handleTokenChange deps: use paymaster.reset not paymaster
Prevents stale exchange rate data from persisting when user changes tokens or resets the bridge flow.
Slippage was being passed both in feeItems array and as a separate slippage prop, causing it to render twice. Keep only the dedicated prop which provides clearer 'Max slippage' labeling.
- Fix duplicate step labels (Connecting to Base/Sapphire) - Export PROGRESS_STEP_COUNT constant for external use - Fix magic number in TopUpButton progress display - Fix progress reset in finally block (preserve failed step visibility) - Add expandable error messages with Show more/less toggle - Add transaction recovery support via localStorage persistence - Save pending transaction after deposit commits - Resume from step 4 if user returns with pending tx - Clear on success or manual dismiss Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The new bridge architecture in master handles everything in App.tsx, not TopUpButton. This adds: - Recovery banner for interrupted bridge transactions - Resume and Dismiss buttons for pending transactions - Disable bridge button when recovery pending Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update project_overview.md: Roffle → Bridge - Update suggested_commands.md: deploy:roffle → deploy Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add complete field validation in getPendingTransaction - Use correct token decimals from pendingTransaction in recovery UI - Preserve pending tx in localStorage when user views different token (allows recovery when they switch back to correct token) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add eslint-disable comments for react-hooks/exhaustive-deps where we intentionally depend on specific methods instead of whole objects to avoid unnecessary re-renders - Add eslint-disable for unused _token parameter required by TokenSelector onChange signature - Apply Prettier formatting to all modified files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove "Build contracts" step from ci-lint workflow (Hardhat no longer needed) - Disable cloudflare-pages automatic triggers until project is configured - Remove dead import for deleted tasks/deploy module in hardhat.config.ts - Track Cloudflare Pages setup in #13 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The existence of pendingTransaction is already guaranteed by the conditional rendering check on line 312, making the optional chaining unnecessary. Addresses Gemini code review comment. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract pendingTransaction to local const in IIFE for TypeScript type narrowing (fixes TS18047 null-safety error) - Clarify comment about ref vs state reset behavior in finally block Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace IIFE pattern with dedicated component for pending transaction recovery UI. This eliminates the need for TypeScript type narrowing workarounds inside closures and improves code clarity. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure Claude Code project settings: - Enable sandbox mode for secure command execution - Add allowed commands for git, package managers, dev tools - Restrict destructive operations (branch deletion, PR merge) - Enable official plugins for features, design, context, security - Address security review: remove dangerous wildcards Security fixes per PR review: - Remove `echo *` (allows arbitrary file writes) - Remove `docker *` (allows sandbox escape) - Remove `gh api *` (allows destructive API calls) - Restrict package managers to specific commands - Restrict gh commands to read-only operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Restructure sandbox config with autoAllowBashIfSandboxed: false - Add git worktree, yarn tsc/eslint, codex, gemini commands - Add WebSearch to permissions.allow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update meta tags, package info, and wagmi config for Oasis Bridge. Remove outdated Roffle social images and non-existent domain URLs. Changes: - Update index.html title, description, and keywords - Update package.json name to @oasisprotocol/oasis-bridge - Update wagmi.ts appName to 'Oasis Bridge' - Remove og:url, twitter:url, canonical (bridge.oasis.io doesn't exist) - Delete og-image.png and twitter.png (old Roffle branding) Closes #4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace inline error display with toast notifications featuring retry button - Stack FeeEstimate component vertically on mobile (<640px) - Trigger wallet connect modal on button click when disconnected - Add vertical arrow icon for mobile fee estimate display - Configure dark theme toaster with custom styling - Fix stale closure in retry handler using ref pattern Closes #6 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address review feedback from Gemini and Copilot: - Updated comment to accurately explain why deps are limited - paymaster object is not memoized (new ref each render) - paymaster.reset is stable but accessed via unstable parent - Only error changes should trigger the effect Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add BridgeSuccessModal component with explorer links and copy-to-clipboard - Add block explorer URL utilities using wagmi chain definitions - Add successData state to usePaymaster hook for modal trigger - Support both startTopUp and resumeFromPending success flows - Add controlled mode to TransactionHistory for external open control - Replace hardcoded basescan URL with dynamic explorer utility Fixes #19 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Cache getExplorerTxUrl result in TransactionHistory to avoid duplicate calls - Add warning log when transaction record is missing txHash in resumeFromPending - Apply Prettier formatting to affected files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds husky + lint-staged to run CI lint checks locally before commits: - ESLint with --max-warnings 0 on staged .ts/.tsx/.js files - Prettier check on staged .ts/.tsx/.js/.json/.md/.css files - TypeScript type check (full project) Implements #24
The prepare script runs 'husky' but husky was only installed in frontend/. CI failed because root yarn install couldn't find husky.
Address review feedback from Gemini and Copilot: - Use --cwd flag for lint-staged and yarn instead of cd - Cleaner approach that doesn't change shell execution context
Add comprehensive Storybook stories for 5 bridge UI components: - BridgeCard: Container with sections and divider variants - AmountInput: Decimal validation, MAX button, gas buffer tests - TokenSelector: Dropdown interaction, keyboard navigation a11y - FeeBreakdown: Loading states, partial loading, collapsed view - FeeEstimate: Responsive layout, loading states Includes interaction tests for: - Decimal input validation (reject excess precision) - MAX button behavior with gas buffer subtraction - Native token vs ERC20 gas buffer handling - Keyboard navigation accessibility (Enter, Arrow, Escape) Fixes #20
- Add maxValue to Disabled story to render MAX button for test - Use args spread in InContext story for Storybook controls
Document that `npx husky install` must be run in each new git worktree to enable pre-commit hooks. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Update to new deployment address: - Old: 0x7D3B4dd07bd523E519e0A91afD8e3B325586fb5b - New: 0x4A390256055264787F1d7d9b75bDBe78F6b7f49C Fixes #29
Change default className from `size-full` to `size-6` to prevent the icon from expanding to fill its container. This matches the visual scale of other token icons (USDCIcon, USDTIcon). Fixes #28
Update all branding references across the project: - index.html: title, meta tags, Open Graph, Twitter cards - wagmi.ts: wallet connect app name - README.md: project description and features - CLAUDE.md: project overview Fixes #31
Enable users to bridge stablecoins from Base, Arbitrum, or Ethereum to Oasis Sapphire. Key changes: - Add ChainSelector component with dropdown UI for source chain selection - Create chain icons (ArbitrumIcon, BaseIcon, EthereumIcon) matching token icon patterns - Extend PaymasterVault config to support all three chains with shared CREATE2 address - Thread sourceChainId through entire paymaster flow, transaction tracking, and UI - Implement localStorage migrations with backward compatibility for Base-only records - Add chain validation to filter unsupported chains from pending transactions and history - Update block explorers to support Arbitrum and Ethereum transaction links - Build token options dynamically from chain config with extensible icon mapping - Reset token selection and clear amount when user switches chains - Update UI labels to reflect multi-chain support in descriptions and success modals Resolves #30 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends bridge functionality to support USDC/USDT deposits from Base, Arbitrum, and Ethereum networks. Users can now select their preferred source chain when bridging stablecoins to receive ROSE on Sapphire.
Closes #30
Changes
New Components
Core Updates
sourceChainIdparameter throughout paymaster flow and transaction trackingROFL_PAYMASTER_TOKEN_CONFIGto support all three chains with shared CREATE2 vault addressCode Quality Improvements
DEFAULT_CHAIN_OPTIONSfromSUPPORTED_SOURCE_CHAINS(single source of truth)getTokenIcon()mapping for extensibilitytokenConfigandsourceChainIdTest Plan
🤖 Generated with Claude Code