diff --git a/apps/daimo-mobile/src/logic/daimoContacts.ts b/apps/daimo-mobile/src/logic/daimoContacts.ts
index b20c63869..f2a95751a 100644
--- a/apps/daimo-mobile/src/logic/daimoContacts.ts
+++ b/apps/daimo-mobile/src/logic/daimoContacts.ts
@@ -246,7 +246,7 @@ function eAccAddrToContact(addr: Address): EAccountContact {
return eAccToContact(eAcc);
}
-export function landlineAccountToContact(
+function landlineAccountToContact(
landlineAccount: LandlineAccount
): LandlineBankAccountContact {
return {
diff --git a/apps/daimo-mobile/src/view/TabNav.tsx b/apps/daimo-mobile/src/view/TabNav.tsx
index 00f52f4a0..4248fe3ea 100644
--- a/apps/daimo-mobile/src/view/TabNav.tsx
+++ b/apps/daimo-mobile/src/view/TabNav.tsx
@@ -29,7 +29,7 @@ import { QRScreen } from "./screen/QRScreen";
import { SeedPhraseScreen } from "./screen/SeedPhraseScreen";
import { SettingsScreen } from "./screen/SettingsScreen";
import { YourInvitesScreen } from "./screen/YourInvitesScreen";
-import { BitrefillWebView } from "./screen/deposit/BitrefillWebview";
+import { BitrefillWebView } from "./screen/deposit/BitrefillWebView";
import DepositScreen from "./screen/deposit/DepositScreen";
import { ErrorScreen } from "./screen/errorScreens";
import { AddDeviceScreen } from "./screen/keyRotation/AddDeviceScreen";
diff --git a/apps/daimo-mobile/src/view/screen/deposit/BitrefillWebview.tsx b/apps/daimo-mobile/src/view/screen/deposit/BitrefillWebView.tsx
similarity index 100%
rename from apps/daimo-mobile/src/view/screen/deposit/BitrefillWebview.tsx
rename to apps/daimo-mobile/src/view/screen/deposit/BitrefillWebView.tsx
diff --git a/apps/daimo-mobile/src/view/screen/deposit/DaimoPayWebView.tsx b/apps/daimo-mobile/src/view/screen/deposit/DaimoPayWebView.tsx
new file mode 100644
index 000000000..bd5c76f95
--- /dev/null
+++ b/apps/daimo-mobile/src/view/screen/deposit/DaimoPayWebView.tsx
@@ -0,0 +1,93 @@
+import { debugJson } from "@daimo/common";
+import React, { useMemo, useCallback } from "react";
+import { View, StyleSheet } from "react-native";
+import { WebView, WebViewMessageEvent } from "react-native-webview";
+
+import { Account } from "../../../storage/account";
+
+type DaimoPayWebViewProps = {
+ account: Account;
+ visible: boolean;
+ onClose: () => void;
+};
+
+export function DaimoPayWebView({
+ account,
+ visible,
+ onClose,
+}: DaimoPayWebViewProps) {
+ const styles = useMemo(() => getStyles(), []);
+
+ // The /embed webpage emits a message when the user closes the modal.
+ // When this happens, close the webview.
+ const handleMessage = useCallback(
+ (event: WebViewMessageEvent) => {
+ try {
+ const data = JSON.parse(event.nativeEvent.data);
+ console.log(`[DAIMO PAY] Received message: ${debugJson(data)}`);
+ if (data?.source !== "daimo-pay") return;
+ if (data.type === "modalClosed") {
+ onClose();
+ }
+ } catch (err) {
+ console.error("[DAIMO PAY] Unable to parse postMessage payload", err);
+ }
+ },
+ [onClose]
+ );
+
+ if (!visible) return null;
+
+ const url = buildDaimoPayUrl(account);
+
+ return (
+
+ console.error("[DAIMO PAY] WebView error", e)}
+ />
+
+ );
+}
+
+function buildDaimoPayUrl(account: Account) {
+ const baseUrl = "https://miniapp.daimo.com/embed";
+ const params = new URLSearchParams({
+ toAddress: account.address,
+ refundAddress: "0xDa130a3573e1a5F54f1B7C2F324bf5d4F89b3c27",
+ toChain: account.homeChainId.toString(),
+ toToken: account.homeCoinAddress,
+ intent: "Deposit to Daimo",
+ paymentOptions: "Coinbase,Solana",
+ });
+
+ return `${baseUrl}?${params.toString()}`;
+}
+
+const getStyles = () =>
+ StyleSheet.create({
+ overlay: {
+ position: "absolute",
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ backgroundColor: "transparent",
+ zIndex: 1000,
+ },
+ header: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "flex-end",
+ padding: 16,
+ zIndex: 1001,
+ },
+ closeButton: {
+ padding: 8,
+ borderRadius: 8,
+ },
+ });
diff --git a/apps/daimo-mobile/src/view/screen/deposit/DepositScreen.tsx b/apps/daimo-mobile/src/view/screen/deposit/DepositScreen.tsx
index e673871ab..449679edd 100644
--- a/apps/daimo-mobile/src/view/screen/deposit/DepositScreen.tsx
+++ b/apps/daimo-mobile/src/view/screen/deposit/DepositScreen.tsx
@@ -1,19 +1,11 @@
-import {
- LandlineAccount,
- PlatformType,
- daimoDomainAddress,
- timeAgo,
-} from "@daimo/common";
+import { daimoDomainAddress } from "@daimo/common";
import { daimoChainFromId } from "@daimo/contract";
import Octicons from "@expo/vector-icons/Octicons";
import { Image } from "expo-image";
-import React, { useCallback, useContext, useMemo, useState } from "react";
+import React, { useContext, useMemo, useState, useEffect } from "react";
import {
ActivityIndicator,
ImageSourcePropType,
- Linking,
- Platform,
- Pressable,
ScrollView,
StyleSheet,
TouchableHighlight,
@@ -21,23 +13,14 @@ import {
useWindowDimensions,
} from "react-native";
+import { DaimoPayWebView } from "./DaimoPayWebView";
import IconDepositWallet from "../../../../assets/icon-deposit-wallet.png";
import IconWithdrawWallet from "../../../../assets/icon-withdraw-wallet.png";
-import LandlineLogo from "../../../../assets/logos/landline-logo.png";
import { DispatcherContext } from "../../../action/dispatch";
import { useNav } from "../../../common/nav";
import { env } from "../../../env";
-import { i18NLocale, i18n } from "../../../i18n";
-import { useAccount } from "../../../logic/accountManager";
-import {
- DaimoContact,
- getContactProfilePicture,
- landlineAccountToContact,
-} from "../../../logic/daimoContacts";
-import { useTime } from "../../../logic/time";
-import { getRpcFunc } from "../../../logic/trpc";
+import { i18n } from "../../../i18n";
import { Account } from "../../../storage/account";
-import { InfoBox } from "../../shared/InfoBox";
import { ScreenHeader } from "../../shared/ScreenHeader";
import Spacer from "../../shared/Spacer";
import { TextBody, TextMeta } from "../../shared/text";
@@ -55,162 +38,50 @@ export default function DepositScreen() {
// maybe is in here is the problem?
function DepositScreenInner({ account }: { account: Account }) {
const { ss } = useTheme();
+ const [showDaimoPay, setShowDaimoPay] = useState(false);
+ const nav = useNav();
+
+ // Automatically close Daimo Pay webview when the user navigates away.
+ useEffect(() => {
+ const unsubscribe = nav.addListener("blur", () => setShowDaimoPay(false));
+ return unsubscribe;
+ }, [nav]);
+
return (
-
-
+
-
- );
-}
-
-function LandlineList() {
- const account = useAccount();
- if (account == null) return null;
- const showLandline = !!account.landlineSessionURL;
- if (!showLandline) return null;
-
- const isLandlineConnected = account.landlineAccounts.length > 0;
-
- return isLandlineConnected ? : ;
-}
-
-function LandlineConnect() {
- const account = useAccount();
-
- const openLandline = useCallback(() => {
- if (!account) return;
- Linking.openURL(account.landlineSessionURL);
- }, [account?.landlineSessionURL]);
-
- if (account == null) return null;
-
- return (
-
- );
-}
-function LandlineAccountList() {
- const account = useAccount();
- const nav = useNav();
- const nowS = useTime();
-
- if (account == null) return null;
-
- const landlineAccounts = account.landlineAccounts;
-
- const goToSendTransfer = (landlineAccount: LandlineAccount) => {
- const recipient = landlineAccountToContact(landlineAccount);
- nav.navigate("DepositTab", {
- screen: "LandlineTransfer",
- params: { recipient },
- });
- };
-
- return (
- <>
- {landlineAccounts.map((acc, idx) => {
- const accCreatedAtS = new Date(acc.createdAt).getTime() / 1000;
- const recipient = landlineAccountToContact(acc) as DaimoContact;
- return (
- goToSendTransfer(acc)}
- />
- );
- })}
- >
+ setShowDaimoPay(false)}
+ />
+
);
}
-// An on-demand exchange is one that requires fetching a URL at the time of
-// user's interaction, rather than have it pre-fetched. These exchanges are
-// first fetched with a loading spinner, then the URL is opened.
-// Binance is the only on-demand exchange for now because generated links
-// expire quickly and 301 redirects don't work for opening universal links
-// in Binance app, so we can't include it in the recommendedExchanges API-side.
-function getOnDemandExchanges(
- account: Account,
- setProgress: (progress: Progress) => void
-) {
- const rpcFunc = getRpcFunc(daimoChainFromId(account.homeChainId));
-
- const platform = ["ios", "android"].includes(Platform.OS)
- ? (Platform.OS as PlatformType)
- : "other";
-
- if (platform === "other") {
- return [];
- }
-
- const progressId = "loading-binance-deposit";
-
- const onClick = async () => {
- setProgress(progressId);
- const url = await rpcFunc.getExchangeURL.query({
- addr: account.address,
- platform,
- exchange: "binance",
- direction: "depositFromExchange",
- });
-
- if (url == null) {
- console.error(`[DEPOSIT] no binance url for ${account.name}`);
- setProgress("idle");
- } else {
- Linking.openURL(url);
- setProgress("started");
- }
- };
-
- return [
- {
- cta: i18.binance.cta(),
- title: i18.binance.title(),
- logo: {
- uri: `${daimoDomainAddress}/assets/deposit/binance.png`,
- },
- loadingId: progressId,
- isExternal: true,
- sortId: 2,
- onClick,
- },
- ];
-}
-
type Progress = "idle" | "loading-binance-deposit" | "started";
-function DepositList({ account }: { account: Account }) {
+function DepositList({
+ account,
+ setShowDaimoPay,
+}: {
+ account: Account;
+ setShowDaimoPay: React.Dispatch>;
+}) {
const { color, ss } = useTheme();
const styles = useMemo(() => getStyles(color, ss), [color, ss]);
const { chainConfig } = env(daimoChainFromId(account.homeChainId));
const isTestnet = chainConfig.chainL2.testnet;
- const [progress, setProgress] = useState