Skip to content

feat(appkit-wagmi): Omen deposit-flow demo in WebView#571

Open
tomiir wants to merge 9 commits into
mainfrom
feat/appkit-omen-deposit-webview
Open

feat(appkit-wagmi): Omen deposit-flow demo in WebView#571
tomiir wants to merge 9 commits into
mainfrom
feat/appkit-omen-deposit-webview

Conversation

@tomiir

@tomiir tomiir commented Jul 15, 2026

Copy link
Copy Markdown

What

POC demo of the WalletConnect Pay deposit flow inside an in-app WebView — the "mobile app + WebView, no context switch" experience. Adds an Omen mock funded-account screen to the appkit-wagmi dApp that opens the buyer-experience /deposit page in a WebView and credits a mock balance from the result posted back over the RN bridge. No redirect.

Built on the WebView scaffolding from #570 (merged): reuses the wc: deeplink hand-off (onShouldStartLoadWithRequest / onOpenWindowLinking.openURL) and the returnUrl + preferUniversalLinks URL params.

Changes

  • stores/OmenStore.ts — valtio store: mock balance + activity, credit({amount, source, txHash}) (falls back to a nominal amount when the wallet doesn't report one).
  • screens/Omen/index.tsx — funded-account screen: balance, + Deposit crypto, activity list with explorer links.
  • screens/Omen/depositUrl.ts — builds the BX /deposit URL with to / app=Omen / returnUrl (getMetadata().redirect.native) / preferUniversalLinks=1.
  • screens/Omen/OmenDepositWebView.tsx — the WebView. Reuses feat(appkit-wagmi): pay-flow WebView PoC — paste URL & open in WebView #570's deeplink interception but with a deposit-specific onMessage for DEPOSIT_COMPLETE / DEPOSIT_CANCELLED → credits OmenStore, then shows the reused PaySuccessView.
  • screens/Connections/components/OmenDemoButton.tsx + wiring in Connections/index.tsx, navigators/RootStackNavigator.tsx, utils/TypesUtil.ts.

The deposit page currently points at a BX branch preview Worker (tomiir-bx-deposit-flow-poc-…workers.dev); swap the base URL in depositUrl.ts when the route ships to a stable env.

Test

  • cd dapps/appkit-wagmi && yarn install && yarn prebuild
  • Run the app → Connections tab → Open Omen deposit demo+ Deposit crypto → the deposit flow loads in the WebView; on completion the balance/activity update without leaving the app.
  • Verified: tsc --noEmit and eslint clean on the new/edited files. Not yet run on a device/simulator.

Open item

returnUrl on the Wallet tab: the BX /deposit wallet path drives AppKit directly (bypasses the payment-machine returnUrl wiring from buyer-experience#967), so the wallet round-trip back to the app needs a device test and likely a small BX-side change. The Address/QR and Exchange paths don't depend on it.

🤖 Generated with Claude Code

Adds an "Omen" mock funded-account screen that opens the WalletConnect Pay
deposit flow (buyer-experience /deposit) in an in-app WebView — no context
switch, no redirect. Reuses the #570 WebView scaffolding (wc: deeplink
hand-off, returnUrl + preferUniversalLinks) with a deposit-specific onMessage
that credits a mock balance from DEPOSIT_COMPLETE/DEPOSIT_CANCELLED.

- OmenStore (valtio): mock balance + activity + credit()
- Omen screen: balance, "Deposit crypto", activity list
- OmenDepositWebView: WebView + deeplink interception + DEPOSIT_* bridge
- Entry button on the Connections screen + navigation wiring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 15, 2026 16:51
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
deposit-app-demo Error Error Jul 16, 2026 2:52pm
pos-demo Ready Ready Preview, Comment Jul 16, 2026 2:52pm

Request Review

@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown

Claude finished @tomiir's task in 2m 39s —— View job


Found 5 issue(s)

Issue 1: Hardcoded branch-preview Worker URL will silently break when the branch is deleted

ID: depositurl-hardcoded-preview-url-a3f1
File: dapps/appkit-wagmi/src/screens/Omen/depositUrl.ts:8
Severity: HIGH
Category: code_quality

Context:

  • Pattern: BX_DEPOSIT_URL is set to a Cloudflare branch-preview Worker URL (tomiir-bx-deposit-flow-poc-…workers.dev)
  • Risk: Branch-preview Workers are ephemeral — the URL disappears when the branch/deployment is cleaned up; the WebView will silently fail to load and users see onLoadError
  • Impact: The entire deposit flow becomes unreachable in any build that ships before the URL is swapped
  • Trigger: The branch-preview deployment is deleted or expired (common in preview environments)

Recommendation: Gate behind an env var or at minimum an explicit __DEV__ guard:

const BX_DEPOSIT_URL = process.env.OMEN_DEPOSIT_URL
  ?? 'https://tomiir-bx-deposit-flow-poc-wc-pay-buyer-experience-dev.walletconnect-v1-bridge.workers.dev/deposit';

Issue 2: onShouldStartLoadWithRequest allows arbitrary custom URL schemes through the WebView

ID: omendeposit-custom-scheme-bypass-c2e8
File: dapps/appkit-wagmi/src/screens/Omen/OmenDepositWebView.tsx:54
Severity: HIGH
Category: security

Context:

  • Pattern: onShouldStartLoadWithRequest only intercepts WC deeplinks (isWalletDeeplink); all other URLs (including tel:, sms:, market:, intent:) return true (allow). new URL('tel:+1234') throws, so the catch block returns false, meaning isWalletDeeplink returns false and the scheme is allowed to load.
  • Risk: A malicious injection into the hosted BX page could navigate the WebView to a custom native scheme (tel:, sms:), triggering OS-level app launches or dialogs without user consent
  • Impact: Unexpected native app invocations, social engineering vectors (e.g. pre-filled phone calls or SMS)
  • Trigger: Any XSS or page-level injection in the hosted BX deposit page

Recommendation: Explicitly allow only http/https and known WC deeplinks:

const onShouldStartLoadWithRequest = useCallback((request: ShouldStartLoadRequest): boolean => {
  if (isWalletDeeplink(request.url)) {
    openWallet(request.url);
    return false;
  }
  // Block non-http(s) schemes — don't let the page drive native scheme handlers
  if (!/^https?:\/\//i.test(request.url)) {
    return false;
  }
  return true;
}, [openWallet]);

Fix this →


Issue 3: External domain URL — branch-preview workers.dev

ID: depositurl-external-domain-workers-dev-b5c4
File: dapps/appkit-wagmi/src/screens/Omen/depositUrl.ts:8
Severity: MEDIUM
Category: security

🔒 External Domain URL (Non-blocking)
URL: https://tomiir-bx-deposit-flow-poc-wc-pay-buyer-experience-dev.walletconnect-v1-bridge.workers.dev/deposit
File: dapps/appkit-wagmi/src/screens/Omen/depositUrl.ts:8 — Domain workers.dev is not reown.com, walletconnect.com, or walletconnect.org. Confirm this is intentional (it is a WalletConnect-controlled Cloudflare Worker account) and that the URL will be replaced before merging to a stable environment.


Issue 4: External domain URL — basescan.org hardcoded explorer link

ID: omenscreen-external-domain-basescan-d9a2
File: dapps/appkit-wagmi/src/screens/Omen/index.tsx:78
Severity: LOW
Category: security

🔒 External Domain URL (Non-blocking)
URL: `https://basescan.org/tx/${tx.txHash}`
File: dapps/appkit-wagmi/src/screens/Omen/index.tsx:78 — Hardcoded to Base chain. If the deposit is on a different chain, this produces a broken explorer link for the txHash. Verify the deposit flow is Base-only in the PoC or guard with a chain check.


Issue 5: formatUsd duplicated across two files

ID: omenscreen-formatusd-duplication-e1f3
File: dapps/appkit-wagmi/src/screens/Omen/index.tsx:14
Severity: LOW
Category: code_quality

Context:

  • Pattern: formatUsd is defined in both Omen/index.tsx (lines 14-19, handles negatives) and OmenDepositWebView.tsx (lines 35-37, positive-only). The two implementations are subtly different, creating a divergence risk.
  • Risk: Future edits fix a formatting bug in one but not the other
  • Impact: Inconsistent display (e.g. a negative credited amount in one view vs the other)
  • Trigger: Any formatting edge case (very large amounts, negative credits, rounding)

Recommendation: Extract to src/utils/formatUsd.ts with a single implementation handling both positive and negative values, then import in both screens.

Breaking changes: None — all changes are purely additive (new screens, new store, new nav routes). No existing exports or navigation contracts were modified.

* posts DEPOSIT_COMPLETE / DEPOSIT_CANCELLED back over the RN WebView bridge — never a redirect.
*/
const BX_DEPOSIT_URL =
'https://tomiir-bx-deposit-flow-poc-wc-pay-buyer-experience-dev.walletconnect-v1-bridge.workers.dev/deposit';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: Hardcoded branch-preview Worker URL will silently break when the branch is deleted

Severity: HIGH
Category: code_quality
Tool: Claude Auto Review

Context:

  • Pattern: BX_DEPOSIT_URL is set to a Cloudflare branch-preview Worker URL (tomiir-bx-deposit-flow-poc-…workers.dev)
  • Risk: Branch-preview Workers are ephemeral — the URL disappears when the branch/deployment is cleaned up; the WebView will silently fail to load and users see onLoadError
  • Impact: The entire deposit flow becomes unreachable in any build that ships before the URL is swapped
  • Trigger: The branch-preview deployment is deleted or expired (common in preview environments)

Recommendation: Gate behind an env var or at minimum an explicit __DEV__ guard:

const BX_DEPOSIT_URL = process.env.OMEN_DEPOSIT_URL
  ?? 'https://tomiir-bx-deposit-flow-poc-wc-pay-buyer-experience-dev.walletconnect-v1-bridge.workers.dev/deposit';


// In-frame navigations to a wallet deeplink are handed to the OS (opens the wallet); everything
// else loads in the WebView.
const onShouldStartLoadWithRequest = useCallback(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: onShouldStartLoadWithRequest allows arbitrary custom URL schemes through the WebView

Severity: HIGH
Category: security
Tool: Claude Auto Review

Context:

  • Pattern: onShouldStartLoadWithRequest only intercepts WC deeplinks (isWalletDeeplink); all other URLs (including tel:, sms:, market:, intent:) return true (allow). new URL('tel:+1234') throws, so the catch block returns false, meaning isWalletDeeplink returns false and the scheme is allowed to load.
  • Risk: A malicious injection into the hosted BX page could navigate the WebView to a custom native scheme (tel:, sms:), triggering OS-level app launches or dialogs without user consent
  • Impact: Unexpected native app invocations, social engineering vectors (e.g. pre-filled phone calls or SMS)
  • Trigger: Any XSS or page-level injection in the hosted BX deposit page

Recommendation: Explicitly allow only http/https and known WC deeplinks:

const onShouldStartLoadWithRequest = useCallback((request: ShouldStartLoadRequest): boolean => {
  if (isWalletDeeplink(request.url)) {
    openWallet(request.url);
    return false;
  }
  // Block non-http(s) schemes — don't let the page drive native scheme handlers
  if (!/^https?:\/\//i.test(request.url)) {
    return false;
  }
  return true;
}, [openWallet]);

Fix this →

* posts DEPOSIT_COMPLETE / DEPOSIT_CANCELLED back over the RN WebView bridge — never a redirect.
*/
const BX_DEPOSIT_URL =
'https://tomiir-bx-deposit-flow-poc-wc-pay-buyer-experience-dev.walletconnect-v1-bridge.workers.dev/deposit';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: External domain URL — branch-preview workers.dev

Severity: MEDIUM
Category: security
Tool: Claude Auto Review

</Text>
{tx.txHash ? (
<TouchableOpacity
onPress={() => Linking.openURL(`https://basescan.org/tx/${tx.txHash}`)}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: External domain URL — basescan.org hardcoded explorer link

Severity: LOW
Category: security
Tool: Claude Auto Review


import {buildOmenDepositUrl} from './depositUrl';

function formatUsd(n: number): string {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: formatUsd duplicated across two files

Severity: LOW
Category: code_quality
Tool: Claude Auto Review

Context:

  • Pattern: formatUsd is defined in both Omen/index.tsx (lines 14-19, handles negatives) and OmenDepositWebView.tsx (lines 35-37, positive-only). The two implementations are subtly different, creating a divergence risk.
  • Risk: Future edits fix a formatting bug in one but not the other
  • Impact: Inconsistent display (e.g. a negative credited amount in one view vs the other)
  • Trigger: Any formatting edge case (very large amounts, negative credits, rounding)

Recommendation: Extract to src/utils/formatUsd.ts with a single implementation handling both positive and negative values, then import in both screens.

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 an Omen deposit-flow demo to the dapps/appkit-wagmi sample app, showcasing completing the WalletConnect Pay /deposit flow inside an in-app WebView and crediting a local mock “funded account” via the RN WebView bridge (no redirect/context switch).

Changes:

  • Introduces a Valtio-backed OmenStore for mock balance/activity and deposit crediting.
  • Adds new Omen screens: a funded-account UI and a dedicated deposit WebView that handles DEPOSIT_COMPLETE / DEPOSIT_CANCELLED messages.
  • Wires the demo entrypoint into Connections and navigation (new routes + button).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
dapps/appkit-wagmi/src/utils/TypesUtil.ts Adds new stack route types for Omen and OmenDepositWebView.
dapps/appkit-wagmi/src/stores/OmenStore.ts New Valtio store for mock balance/activity + credit() helper.
dapps/appkit-wagmi/src/screens/Omen/OmenDepositWebView.tsx New WebView screen for deposit flow + RN bridge handling + deeplink interception.
dapps/appkit-wagmi/src/screens/Omen/index.tsx New funded-account screen: balance, deposit CTA, activity list with explorer link.
dapps/appkit-wagmi/src/screens/Omen/depositUrl.ts Builds the BX /deposit URL with destination + returnUrl + preferUniversalLinks.
dapps/appkit-wagmi/src/screens/Connections/index.tsx Adds OmenDemoButton to the Connections screen.
dapps/appkit-wagmi/src/screens/Connections/components/OmenDemoButton.tsx New button to open the Omen demo screen.
dapps/appkit-wagmi/src/navigators/RootStackNavigator.tsx Registers the new Omen routes in the root stack navigator.

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

Comment on lines +35 to +37
function formatUsd(n: number): string {
return `$${n.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/, ',')}`;
}
Comment on lines +14 to +19
function formatUsd(n: number): string {
const sign = n < 0 ? '-' : '';
return `${sign}$${Math.abs(n)
.toFixed(2)
.replace(/\B(?=(\d{3})+(?!\d))/, ',')}`;
}
Comment on lines +26 to +33
function isWalletDeeplink(url: string): boolean {
try {
const wcUri = new URL(url).searchParams.get('uri');
return !!wcUri && wcUri.startsWith('wc:');
} catch {
return false;
}
}
Comment on lines +76 to +82
{tx.txHash ? (
<TouchableOpacity
onPress={() => Linking.openURL(`https://basescan.org/tx/${tx.txHash}`)}>
<Text variant="small-400" style={{color: Theme['accent-100']}}>
View on explorer
</Text>
</TouchableOpacity>
Restyle the native Omen screen to match the web host (apps/deposit-demo):
dark zinc surfaces, violet accent, code-drawn logo + wordmark header with
Sign out, purple welcome-offer banner, styled balance/deposit pill/activity.
Hide the stack header for Omen so the in-content header is the only one.
No image assets added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
We have no JS console on-device, so tapping a wallet failing silently was
un-diagnosable. Add a floating debug overlay that captures every navigation
request + isWalletDeeplink verdict, window.open targets, the Linking
canOpenURL/openURL handoff result, load/HTTP errors, and BX's own
console/window-error/unhandledrejection lines (forwarded via injected JS over
the RN bridge, marked __omenDebug so the DEPOSIT_* contract is untouched).
Copy/Clear + capped ring buffer. Gated behind a DEBUG const.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Open BX with ?theme=dark, paint the WebView + a dark loading cover in the Omen
bg until onLoadEnd (kills the white flash on open), wrap in a dark SafeAreaView,
and hide the redundant native header so BX's own "Add money" chrome is the only
one — the deposit reads as part of the app.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deposit to 0x13302Eb0aD9Af2F847119dC4Ac632fFe196d0B0f, and after a successful
deposit show the confirmation briefly then close the webview and return to the
Omen home (now showing the credited balance + new activity row).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Intercept the gooddeposit:// handoff from the BX deposit page in
OmenDepositWebView and open a full-screen "GoodWallet" modal (its own light
skin + brand, slid up so it reads as a separate wallet). The screen lists mock
token holdings, lets you pick a token + amount, shows the requesting app +
destination, and on Confirm mock-sends, credits OmenStore, and returns to Omen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Handle the DEPOSIT_OPEN_WALLET postMessage in onMessage → navigate to the
GoodDepositConfirm modal. Drop the gooddeposit:// scheme interception: iOS
WKWebView never surfaced the custom-scheme navigation, so the deeplink path was
dead. The postMessage bridge is the reliable channel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Carry network + token through the DEPOSIT_OPEN_WALLET bridge message into the
GoodWallet screen: preselect the matching token (still changeable) and show the
chosen network on the request card — the "ideal wallet: preselected but
changeable" behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Redesign the screen: app-avatar request card, horizontal network chips (with
  logos), a token list showing balances + USD value, a cleaner amount card and
  a "Deposit $X" CTA.
- Add an in-wallet network + token selector (mirrors the BX concept); the
  BX pre-selection still preselects both, and they stay changeable.
- Model mock holdings per network with realistic prices for non-stables
  (ETH 3550, POL 0.52; stables ~1) and show per-token USD value.
- Fix the close control not being tappable on iOS: drop the modal SafeAreaView
  for useSafeAreaInsets + a padded Pressable close button below the status bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants