diff --git a/package.json b/package.json
index 52b1d6a61..a378bf5a1 100644
--- a/package.json
+++ b/package.json
@@ -78,6 +78,7 @@
"qrcode.react": "^4.2.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "react-error-boundary": "^6.0.0",
"react-i18next": "^16.4.0",
"react-inspector": "^9.0.0",
"tailwind-merge": "^3.4.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d67c4438f..69a28b941 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -107,6 +107,9 @@ importers:
react-dom:
specifier: ^19.0.0
version: 19.2.1(react@19.2.1)
+ react-error-boundary:
+ specifier: ^6.0.0
+ version: 6.0.0(react@19.2.1)
react-i18next:
specifier: ^16.4.0
version: 16.4.0(i18next@25.7.1(typescript@5.9.3))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3)
@@ -3752,6 +3755,11 @@ packages:
peerDependencies:
react: ^19.2.1
+ react-error-boundary@6.0.0:
+ resolution: {integrity: sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==}
+ peerDependencies:
+ react: '>=16.13.1'
+
react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
@@ -8042,6 +8050,11 @@ snapshots:
react: 19.2.1
scheduler: 0.27.0
+ react-error-boundary@6.0.0(react@19.2.1):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ react: 19.2.1
+
react-fast-compare@3.2.2: {}
react-i18next@16.4.0(i18next@25.7.1(typescript@5.9.3))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3):
diff --git a/src/components/common/error-boundary.tsx b/src/components/common/error-boundary.tsx
new file mode 100644
index 000000000..4b0a7e6a8
--- /dev/null
+++ b/src/components/common/error-boundary.tsx
@@ -0,0 +1,46 @@
+import { ErrorBoundary as BaseErrorBoundary, useErrorBoundary } from 'react-error-boundary'
+import type { ReactNode } from 'react'
+import { Button } from '@/components/ui/button'
+
+interface ErrorFallbackProps {
+ error: Error
+ resetErrorBoundary: () => void
+}
+
+function ErrorFallback({ error, resetErrorBoundary }: ErrorFallbackProps) {
+ return (
+
+
+
Something went wrong
+
+ {error.message || 'An unexpected error occurred'}
+
+
+
+
+ )
+}
+
+interface ErrorBoundaryProps {
+ children: ReactNode
+ fallback?: ReactNode
+ onError?: (error: Error, info: React.ErrorInfo) => void
+}
+
+export function ErrorBoundary({ children, fallback, onError }: ErrorBoundaryProps) {
+ return (
+ <>{fallback}> : ErrorFallback}
+ onError={(error, info) => {
+ console.error('ErrorBoundary caught an error:', error, info)
+ onError?.(error, info)
+ }}
+ >
+ {children}
+
+ )
+}
+
+export { useErrorBoundary }
diff --git a/src/components/common/index.ts b/src/components/common/index.ts
index dfabfea9a..a184ef9ee 100644
--- a/src/components/common/index.ts
+++ b/src/components/common/index.ts
@@ -10,3 +10,4 @@ export { IconCircle } from './icon-circle'
export { FormField } from './form-field'
export { Alert } from './alert'
export { StepIndicator, ProgressSteps } from './step-indicator'
+export { ErrorBoundary } from './error-boundary'
diff --git a/src/stackflow/activities/SendActivity.tsx b/src/stackflow/activities/SendActivity.tsx
index 60e7b7fd7..32f8b8434 100644
--- a/src/stackflow/activities/SendActivity.tsx
+++ b/src/stackflow/activities/SendActivity.tsx
@@ -1,6 +1,7 @@
import type { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { ActivityParamsProvider } from "../hooks";
+import { ErrorBoundary } from "@/components/common/error-boundary";
import { SendPage } from "@/pages/send";
type SendParams = {
@@ -13,7 +14,9 @@ export const SendActivity: ActivityComponentType = ({ params }) => {
return (
-
+
+
+
);
diff --git a/src/stackflow/stackflow.ts b/src/stackflow/stackflow.ts
index 87777bbe4..9490d5bc4 100644
--- a/src/stackflow/stackflow.ts
+++ b/src/stackflow/stackflow.ts
@@ -112,7 +112,9 @@ export const { Stack, useFlow, useStepFlow, activities } = stackflow({
WalletAddSheetActivity,
SecurityWarningSheetActivity,
},
- initialActivity: () => "MainTabsActivity",
+ // Note: Don't set initialActivity when using historySyncPlugin
+ // The plugin will determine the initial activity based on the URL
+ // and use fallbackActivity when no route matches
});
export type ActivityName = keyof typeof activities;
diff --git a/src/stores/wallet.ts b/src/stores/wallet.ts
index 9ec22c769..f06cb0b0d 100644
--- a/src/stores/wallet.ts
+++ b/src/stores/wallet.ts
@@ -439,7 +439,11 @@ export const walletActions = {
const adapter = registry.getAdapter(chain)
if (!adapter) {
- console.warn(`[refreshBalance] No adapter for chain: ${chain}`)
+ // This is expected during initialization or for unsupported chains
+ // Only log in development to avoid console noise
+ if (import.meta.env.DEV) {
+ console.debug(`[refreshBalance] Skipping chain without adapter: ${chain}`)
+ }
return
}