Skip to content

feat(expo-example): add export wallet on mobile#168

Merged
andrascodes merged 1 commit into
mainfrom
andras/feat-expo-example-add-export-wallet-on-mobile
May 15, 2026
Merged

feat(expo-example): add export wallet on mobile#168
andrascodes merged 1 commit into
mainfrom
andras/feat-expo-example-add-export-wallet-on-mobile

Conversation

@andrascodes

@andrascodes andrascodes commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Closes FS-1979

For the export wallet on mobile, I decided to go with the same approach as the iframe-stamper on Web. This is the ExportWebView file. It requests the bundle using the wallet-core export functions and passes the bundle to the export.turnkey.com website via an iframe. The iframe on mobile is rendered in a WebView. The ExportWebView component injects some JS into the WebView to enable passing the bundle to the iframe itself via a MessageChannel.
Other than this the rest of the files are to demo certain further security measures that app developers can take: Biometrics before revealing the key, blocking screen capture both for screenshots and for not showing the keys when switching between apps and protection against supply chain attacks (restricting package versions and network security config)

@vercel

vercel Bot commented May 11, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
zerodev-signer-demo Ready Ready Preview, Comment May 14, 2026 1:11pm

Request Review

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.

Pull request overview

Adds a mobile-only wallet export flow to the expo-example app using a hardened react-native-webview wrapper around Turnkey’s export.turnkey.com iframe, plus demo “defense-in-depth” measures (biometric gating, screenshot/recording protection, and dependency pinning).

Changes:

  • Add /export route group with consent screen + seed phrase/private key reveal screens, backed by a WebView-based Turnkey export bridge.
  • Add security utilities: biometric-only auth gate, screen-capture prevention hook, and app-state listener for resetting consent/reveal.
  • Pin sensitive dependencies (Turnkey packages + webview) and update Expo config/plugins/docs to reflect export behavior.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-lock.yaml Lockfile updates for newly added/pinned dependencies (webview, screen capture, local auth) and resolution changes.
apps/expo-example/src/lib/biometricAuth.ts Adds biometric-only authentication helper for reveal/export flows.
apps/expo-example/src/hooks/usePreventScreenCapture.ts Adds a hook to enable/restore screen-capture protection with fail-closed status.
apps/expo-example/src/hooks/useAppChangeListener.ts Adds AppState transition listener hook with “latest callback” ref pattern.
apps/expo-example/src/components/export/WarningCard.tsx Introduces reusable warning UI card for sensitive screens.
apps/expo-example/src/components/export/ExportWebView.tsx Implements Turnkey export wrapper HTML + message bridge + navigation allowlist hardening.
apps/expo-example/src/components/export/ExportBox.tsx Wraps export WebView with loading/error UI and mounts/unmounts for reveal lifecycle.
apps/expo-example/src/components/export/CaptureFailedScreen.tsx Full-screen fail-closed UI when screen-capture prevention can’t be enabled.
apps/expo-example/src/app/index.tsx Adds “Export wallet” link from home screen.
apps/expo-example/src/app/export/wallet.web.tsx Web shim redirect for wallet export route.
apps/expo-example/src/app/export/wallet.tsx Native seed phrase export screen with consent guard, biometrics, and capture protection.
apps/expo-example/src/app/export/private-key.web.tsx Web shim redirect for private key export route.
apps/expo-example/src/app/export/private-key.tsx Native private key export screen with consent guard, biometrics, and capture protection.
apps/expo-example/src/app/export/index.web.tsx Web-only “export disabled” screen.
apps/expo-example/src/app/export/index.tsx Consent screen with checkbox + navigation to reveal routes.
apps/expo-example/src/app/export/_layout.tsx Route-group layout providing consent context and reset-on-background behavior.
apps/expo-example/src/app/_layout.tsx Registers export route under authenticated stack.
apps/expo-example/README.md Documents new wallet export flow and links to the detailed export hardening doc.
apps/expo-example/package.json Adds/pins expo-local-authentication, expo-screen-capture, and react-native-webview; pins Turnkey deps.
apps/expo-example/docs/wallet-export.md Adds detailed design/security rationale and hardening guidance for the export flow.
apps/expo-example/app.json Adds expo-local-authentication plugin configuration (Face ID permission string).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +47
<View
style={[
styles.webViewWrapper,
stage !== 'ready' && styles.webViewHidden,
]}
pointerEvents={stage === 'ready' ? 'auto' : 'none'}
>
<ExportWebView
kind={kind}
onReady={() => setStage('ready')}
onError={(msg) => {
setStage('error')
setErrorMsg(msg)
}}
style={styles.webView}
/>
</View>
Comment on lines +38 to +46
<ExportWebView
kind={kind}
onReady={() => setStage('ready')}
onError={(msg) => {
setStage('error')
setErrorMsg(msg)
}}
style={styles.webView}
/>
| Replay / multi-invocation | same file — `handledPubkey` ref + `requestId` matched on `BUNDLE_INJECTED` | A misbehaving iframe can't drive multiple export calls or replay acks |
| Screenshot / recording (Android) | `src/hooks/usePreventScreenCapture.ts` | `FLAG_SECURE` via `expo-screen-capture`; fail-closed on reject |
| Biometric gate | `src/lib/biometricAuth.ts` | `disableDeviceFallback: true` — biometric only, no passcode |
| Consent + reveal reset | `src/app/export/_layout.tsx`, `wallet.native.tsx`, `private-key.native.tsx` | Consent resets on background; reveal resets on inactive |
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 07810cd to 0ab2397 Compare May 13, 2026 10:29
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 086b5cd to 0991a9d Compare May 13, 2026 10:29
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 0ab2397 to 592314d Compare May 13, 2026 10:45
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 0991a9d to f2de218 Compare May 13, 2026 10:45
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 592314d to fef2d5c Compare May 13, 2026 11:31
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from f2de218 to 6bfcd21 Compare May 13, 2026 11:31
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 6bfcd21 to fd2ecf9 Compare May 13, 2026 12:00
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from fef2d5c to 96c30fd Compare May 13, 2026 12:00
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 96c30fd to 01177b4 Compare May 13, 2026 14:38
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from fd2ecf9 to 4bb2387 Compare May 13, 2026 14:38
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 4bb2387 to b748b5e Compare May 13, 2026 16:07
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 01177b4 to 74b376c Compare May 13, 2026 16:07
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 74b376c to 01a54e6 Compare May 13, 2026 17:08
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from b748b5e to 0434ba0 Compare May 13, 2026 17:08
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 0434ba0 to 81c7db9 Compare May 14, 2026 05:50
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 01a54e6 to 8ba0ed9 Compare May 14, 2026 05:50
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 81c7db9 to d55dcb5 Compare May 14, 2026 06:09
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 8ba0ed9 to 554f6a8 Compare May 14, 2026 06:09
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from d55dcb5 to 7ecc93f Compare May 14, 2026 06:43
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 554f6a8 to 2e3927e Compare May 14, 2026 06:43
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-configure-and-add-magic-link-login branch from 7ecc93f to 67a3df9 Compare May 14, 2026 13:00
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 2e3927e to 8fe6f05 Compare May 14, 2026 13:00
@andrascodes
andrascodes changed the base branch from andras/feat-expo-example-configure-and-add-magic-link-login to main May 14, 2026 13:09
@andrascodes
andrascodes force-pushed the andras/feat-expo-example-add-export-wallet-on-mobile branch from 8fe6f05 to 6378d7d Compare May 14, 2026 13:09

@OmarBasem OmarBasem left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested on physical devices on iOS and Android, most auth flows are working except for dynamic links on both platforms, in addition to passkeys and universal links on iOS which needs extra setup (discussed on Slack, yet to be setup and tested out)

Export wallet looks good

Transactions looks good

A small comment on the email input keyboard, should not hide the email input

@andrascodes
andrascodes merged commit ca4b74d into main May 15, 2026
16 of 17 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.

3 participants