summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-07-16 07:55:57 +0700
committerpolwex <polwex@sortug.com>2025-07-16 07:55:57 +0700
commite2e14e414de25904d791b503d2852c68b3ac9415 (patch)
tree051b3b0dbaa6252d9a1687d29b401d079dbafb6b
parenta528bd94a6e8e25010ae26a305550b211df0ddc6 (diff)
-rw-r--r--.env4
-rw-r--r--actions/passkey.ts8
-rw-r--r--actions/render-info.tsx8
-rw-r--r--app.json5
-rw-r--r--app/(tabs)/login.tsx136
-rw-r--r--assets/UrbitWalletIcon.pngbin0 -> 1053 bytes
-rw-r--r--assets/adaptive-icon.pngbin0 -> 17547 bytes
-rw-r--r--assets/clock-icon-active-dark.pngbin0 -> 721 bytes
-rw-r--r--assets/clock-icon-active-light.pngbin0 -> 707 bytes
-rw-r--r--assets/clock-icon-inactive-dark.pngbin0 -> 1016 bytes
-rw-r--r--assets/clock-icon-inactive-light.pngbin0 -> 994 bytes
-rw-r--r--assets/eth-logo.pngbin0 -> 338608 bytes
-rw-r--r--assets/favicon.pngbin0 -> 1466 bytes
-rw-r--r--assets/icon.pngbin0 -> 22380 bytes
-rw-r--r--assets/link-logo.pngbin0 -> 167995 bytes
-rw-r--r--assets/splash-icon.pngbin0 -> 17547 bytes
-rw-r--r--assets/urbit-logo-dark.pngbin0 -> 4634 bytes
-rw-r--r--assets/urbit-logo-light.pngbin0 -> 4711 bytes
-rw-r--r--assets/usdc-logo.pngbin0 -> 221850 bytes
-rw-r--r--assets/wallet-icon-active-dark.pngbin0 -> 756 bytes
-rw-r--r--assets/wallet-icon-active-light.pngbin0 -> 695 bytes
-rw-r--r--assets/wallet-icon-inactive-dark.pngbin0 -> 800 bytes
-rw-r--r--assets/wallet-icon-inactive-light.pngbin0 -> 837 bytes
-rw-r--r--bun.lock162
-rw-r--r--components/PrimaryButton.tsx102
-rw-r--r--components/ScreenWrapper.tsx31
-rw-r--r--components/auth/Auth.tsx149
-rw-r--r--constants/colors.ts51
-rw-r--r--constants/config.ts67
-rw-r--r--constants/constants.ts24
-rw-r--r--constants/contracts.ts109
-rw-r--r--constants/index.ts5
-rw-r--r--constants/routes.ts11
-rw-r--r--lib/passkey.ts131
-rw-r--r--package.json4
35 files changed, 1000 insertions, 7 deletions
diff --git a/.env b/.env
new file mode 100644
index 0000000..cb41bef
--- /dev/null
+++ b/.env
@@ -0,0 +1,4 @@
+EXPO_PUBLIC_NETWORK="mainnet"
+EXPO_PUBLIC_INFURA_API="mainnet"
+EXPO_PUBLIC_INFURA_API_SECRET_KEY="mainnet"
+EXPO_PUBLIC_ETHERSCAN_API_KEY="mainnet"
diff --git a/actions/passkey.ts b/actions/passkey.ts
new file mode 100644
index 0000000..1428337
--- /dev/null
+++ b/actions/passkey.ts
@@ -0,0 +1,8 @@
+"use server";
+
+import { Text } from "react-native";
+
+export default async function renderInfo({ name }) {
+ // Securely fetch data from an API, and read environment variables...
+ return <Text>Hello, {name}!</Text>;
+}
diff --git a/actions/render-info.tsx b/actions/render-info.tsx
new file mode 100644
index 0000000..1428337
--- /dev/null
+++ b/actions/render-info.tsx
@@ -0,0 +1,8 @@
+"use server";
+
+import { Text } from "react-native";
+
+export default async function renderInfo({ name }) {
+ // Securely fetch data from an API, and read environment variables...
+ return <Text>Hello, {name}!</Text>;
+}
diff --git a/app.json b/app.json
index bbbd9fe..b4c63ed 100644
--- a/app.json
+++ b/app.json
@@ -20,7 +20,7 @@
},
"web": {
"bundler": "metro",
- "output": "static",
+ "output": "single",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
@@ -36,7 +36,8 @@
]
],
"experiments": {
- "typedRoutes": true
+ "typedRoutes": true,
+ "reactServerFunctions": true
}
}
}
diff --git a/app/(tabs)/login.tsx b/app/(tabs)/login.tsx
new file mode 100644
index 0000000..d09e613
--- /dev/null
+++ b/app/(tabs)/login.tsx
@@ -0,0 +1,136 @@
+import React, { useState } from "react";
+import {
+ View,
+ Text,
+ StyleSheet,
+ Image,
+ KeyboardAvoidingView,
+ Platform,
+ Alert,
+} from "react-native";
+import PrimaryButton from "../../components/PrimaryButton";
+import ScreenWrapper from "../../components/ScreenWrapper";
+import { useThemeColors, ColorScheme } from "../../constants";
+import { ROUTES } from "../../constants/routes";
+import { Passkee } from "@/components/auth/Auth";
+
+// import { useSettingsStore } from "../store/useSettingsStore";
+// import useAuthStore from "../store/useAuthStore";
+// import { createPasskey, isPasskeySupported } from "../lib/passkey";
+// import { navigationRef } from "../lib/navigationRef";
+
+const PasskeySetupScreen = () => {
+ const [isLoading, setIsLoading] = useState(false);
+ // const isDarkMode = useSettingsStore((s) => s.isDarkMode);
+ const isDarkMode = false;
+ const colors = useThemeColors();
+ const styles = getStyles(colors);
+ // const { setHasPasskey, setHasSeenPasskeyPrompt } = useAuthStore();
+
+ const logoSource = isDarkMode
+ ? require("../../assets/urbit-logo-dark.png")
+ : require("../../assets/urbit-logo-light.png");
+
+ const handleCreatePasskey = async () => {
+ console.log("creaing psskey");
+ setIsLoading(true);
+
+ try {
+ // const res = await startRegistration({})
+ } catch (error) {
+ console.error("Passkey creation error:", error);
+ Alert.alert("Error", "An error occurred while creating the passkey.");
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleSkip = () => {
+ // setHasSeenPasskeyPrompt(true);
+ // navigationRef.current?.navigate(ROUTES.LOGIN as never);
+ };
+
+ return (
+ <KeyboardAvoidingView
+ style={styles.container}
+ behavior={Platform.OS === "ios" ? "padding" : undefined}
+ >
+ <ScreenWrapper>
+ <View style={styles.topSection}>
+ <Image
+ source={logoSource}
+ style={styles.walletIcon}
+ resizeMode="contain"
+ />
+ <Text style={styles.title}>Secure Your Wallet</Text>
+ <Text style={styles.subtitle}>
+ Create a passkey for easy and secure access to your Urbit wallet
+ </Text>
+ </View>
+
+ <View style={styles.bottomSection}>
+ <Passkee />
+ <PrimaryButton
+ label="Skip for Now"
+ onPress={handleSkip}
+ style={{
+ backgroundColor: colors.card,
+ borderWidth: 1,
+ borderColor: colors.border,
+ }}
+ textStyle={{ color: colors.text }}
+ />
+
+ <Text style={styles.infoText}>
+ You can always set up a passkey later in settings
+ </Text>
+ </View>
+ </ScreenWrapper>
+ </KeyboardAvoidingView>
+ );
+};
+
+export const getStyles = (colors: ColorScheme) =>
+ StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: colors.background,
+ justifyContent: "space-between",
+ padding: 20,
+ },
+ topSection: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ walletIcon: {
+ width: 64,
+ height: 64,
+ marginBottom: 24,
+ },
+ title: {
+ fontSize: 24,
+ color: colors.text,
+ fontWeight: "600",
+ marginBottom: 12,
+ textAlign: "center",
+ },
+ subtitle: {
+ fontSize: 16,
+ color: colors.secondary,
+ textAlign: "center",
+ paddingHorizontal: 20,
+ lineHeight: 24,
+ },
+ bottomSection: {
+ marginBottom: 40,
+ },
+ infoText: {
+ color: colors.secondary,
+ fontSize: 14,
+ textAlign: "center",
+ marginTop: 16,
+ },
+ });
+
+export default PasskeySetupScreen;
diff --git a/assets/UrbitWalletIcon.png b/assets/UrbitWalletIcon.png
new file mode 100644
index 0000000..1f34694
--- /dev/null
+++ b/assets/UrbitWalletIcon.png
Binary files differ
diff --git a/assets/adaptive-icon.png b/assets/adaptive-icon.png
new file mode 100644
index 0000000..03d6f6b
--- /dev/null
+++ b/assets/adaptive-icon.png
Binary files differ
diff --git a/assets/clock-icon-active-dark.png b/assets/clock-icon-active-dark.png
new file mode 100644
index 0000000..c9de50c
--- /dev/null
+++ b/assets/clock-icon-active-dark.png
Binary files differ
diff --git a/assets/clock-icon-active-light.png b/assets/clock-icon-active-light.png
new file mode 100644
index 0000000..c8b7230
--- /dev/null
+++ b/assets/clock-icon-active-light.png
Binary files differ
diff --git a/assets/clock-icon-inactive-dark.png b/assets/clock-icon-inactive-dark.png
new file mode 100644
index 0000000..4f00950
--- /dev/null
+++ b/assets/clock-icon-inactive-dark.png
Binary files differ
diff --git a/assets/clock-icon-inactive-light.png b/assets/clock-icon-inactive-light.png
new file mode 100644
index 0000000..6407c4a
--- /dev/null
+++ b/assets/clock-icon-inactive-light.png
Binary files differ
diff --git a/assets/eth-logo.png b/assets/eth-logo.png
new file mode 100644
index 0000000..9ba012c
--- /dev/null
+++ b/assets/eth-logo.png
Binary files differ
diff --git a/assets/favicon.png b/assets/favicon.png
new file mode 100644
index 0000000..e75f697
--- /dev/null
+++ b/assets/favicon.png
Binary files differ
diff --git a/assets/icon.png b/assets/icon.png
new file mode 100644
index 0000000..a0b1526
--- /dev/null
+++ b/assets/icon.png
Binary files differ
diff --git a/assets/link-logo.png b/assets/link-logo.png
new file mode 100644
index 0000000..ac1dea7
--- /dev/null
+++ b/assets/link-logo.png
Binary files differ
diff --git a/assets/splash-icon.png b/assets/splash-icon.png
new file mode 100644
index 0000000..03d6f6b
--- /dev/null
+++ b/assets/splash-icon.png
Binary files differ
diff --git a/assets/urbit-logo-dark.png b/assets/urbit-logo-dark.png
new file mode 100644
index 0000000..8f198ae
--- /dev/null
+++ b/assets/urbit-logo-dark.png
Binary files differ
diff --git a/assets/urbit-logo-light.png b/assets/urbit-logo-light.png
new file mode 100644
index 0000000..771aab9
--- /dev/null
+++ b/assets/urbit-logo-light.png
Binary files differ
diff --git a/assets/usdc-logo.png b/assets/usdc-logo.png
new file mode 100644
index 0000000..36a9f90
--- /dev/null
+++ b/assets/usdc-logo.png
Binary files differ
diff --git a/assets/wallet-icon-active-dark.png b/assets/wallet-icon-active-dark.png
new file mode 100644
index 0000000..dbda9a6
--- /dev/null
+++ b/assets/wallet-icon-active-dark.png
Binary files differ
diff --git a/assets/wallet-icon-active-light.png b/assets/wallet-icon-active-light.png
new file mode 100644
index 0000000..dcef651
--- /dev/null
+++ b/assets/wallet-icon-active-light.png
Binary files differ
diff --git a/assets/wallet-icon-inactive-dark.png b/assets/wallet-icon-inactive-dark.png
new file mode 100644
index 0000000..4baba74
--- /dev/null
+++ b/assets/wallet-icon-inactive-dark.png
Binary files differ
diff --git a/assets/wallet-icon-inactive-light.png b/assets/wallet-icon-inactive-light.png
new file mode 100644
index 0000000..8523a39
--- /dev/null
+++ b/assets/wallet-icon-inactive-light.png
Binary files differ
diff --git a/bun.lock b/bun.lock
index b984a45..b2dd270 100644
--- a/bun.lock
+++ b/bun.lock
@@ -8,6 +8,7 @@
"@react-navigation/bottom-tabs": "^7.3.10",
"@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6",
+ "ethers": "^6.15.0",
"expo": "~53.0.17",
"expo-blur": "~14.1.5",
"expo-constants": "~17.1.7",
@@ -30,6 +31,7 @@
"react-native-screens": "~4.11.1",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5",
+ "react-server-dom-webpack": "^19.1.0",
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -43,6 +45,8 @@
"packages": {
"@0no-co/graphql.web": ["@0no-co/graphql.web@1.1.2", "", { "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" }, "optionalPeers": ["graphql"] }, "sha512-N2NGsU5FLBhT8NZ+3l2YrzZSHITjNXNuDhC4iDiikv0IujaJ0Xc6xIxQZ/Ek3Cb+rgPjnLHYyJm11tInuJn+cw=="],
+ "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.10.1", "", {}, "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw=="],
+
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
@@ -345,6 +349,10 @@
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
+ "@noble/curves": ["@noble/curves@1.2.0", "", { "dependencies": { "@noble/hashes": "1.3.2" } }, "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw=="],
+
+ "@noble/hashes": ["@noble/hashes@1.3.2", "", {}, "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ=="],
+
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
@@ -411,6 +419,10 @@
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
+ "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="],
+
+ "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="],
+
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="],
@@ -427,7 +439,7 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
- "@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+ "@types/node": ["@types/node@22.7.5", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ=="],
"@types/react": ["@types/react@19.0.14", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw=="],
@@ -499,16 +511,56 @@
"@urql/exchange-retry": ["@urql/exchange-retry@1.3.2", "", { "dependencies": { "@urql/core": "^5.1.2", "wonka": "^6.3.2" } }, "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg=="],
+ "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="],
+
+ "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="],
+
+ "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.13.2", "", {}, "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ=="],
+
+ "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.14.1", "", {}, "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA=="],
+
+ "@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.13.2", "", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA=="],
+
+ "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.13.2", "", {}, "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA=="],
+
+ "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/wasm-gen": "1.14.1" } }, "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw=="],
+
+ "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.13.2", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw=="],
+
+ "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.13.2", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw=="],
+
+ "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.13.2", "", {}, "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ=="],
+
+ "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/helper-wasm-section": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-opt": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1", "@webassemblyjs/wast-printer": "1.14.1" } }, "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ=="],
+
+ "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg=="],
+
+ "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1" } }, "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw=="],
+
+ "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ=="],
+
+ "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw=="],
+
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.10", "", {}, "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="],
+ "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="],
+
+ "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="],
+
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
+ "acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="],
+
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
+ "acorn-loose": ["acorn-loose@8.5.2", "", { "dependencies": { "acorn": "^8.15.0" } }, "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A=="],
+
+ "aes-js": ["aes-js@4.0.0-beta.5", "", {}, "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="],
+
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
@@ -629,6 +681,8 @@
"chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="],
+ "chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="],
+
"chromium-edge-launcher": ["chromium-edge-launcher@0.2.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg=="],
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
@@ -725,6 +779,8 @@
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
+ "enhanced-resolve": ["enhanced-resolve@5.18.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ=="],
+
"env-editor": ["env-editor@0.4.2", "", {}, "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA=="],
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
@@ -739,6 +795,8 @@
"es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="],
+ "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
@@ -789,8 +847,12 @@
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
+ "ethers": ["ethers@6.15.0", "", { "dependencies": { "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "22.7.5", "aes-js": "4.0.0-beta.5", "tslib": "2.7.0", "ws": "8.17.1" } }, "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ=="],
+
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
+ "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
+
"exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="],
"expo": ["expo@53.0.19", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "0.24.20", "@expo/config": "~11.0.13", "@expo/config-plugins": "~10.1.2", "@expo/fingerprint": "0.13.4", "@expo/metro-config": "0.20.17", "@expo/vector-icons": "^14.0.0", "babel-preset-expo": "~13.2.3", "expo-asset": "~11.1.7", "expo-constants": "~17.1.7", "expo-file-system": "~18.1.11", "expo-font": "~13.3.2", "expo-keep-awake": "~14.1.4", "expo-modules-autolinking": "2.1.14", "expo-modules-core": "2.4.2", "react-native-edge-to-edge": "1.6.0", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-hZWEKw6h5dlfKy6+c3f2exx5x3Loio8p0b2s/Pk1eQfTffqpkQRVVlOzcTWU1RSuMfc47ZMpr97pUJWQczOGsQ=="],
@@ -907,6 +969,8 @@
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
+ "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
+
"globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
@@ -1073,6 +1137,8 @@
"json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="],
+ "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
+
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
@@ -1117,6 +1183,8 @@
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
+ "loader-runner": ["loader-runner@4.3.0", "", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="],
+
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="],
@@ -1203,6 +1271,8 @@
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+ "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
+
"nested-error-stacks": ["nested-error-stacks@2.0.1", "", {}, "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A=="],
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
@@ -1321,6 +1391,8 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
+ "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
@@ -1357,6 +1429,8 @@
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
+ "react-server-dom-webpack": ["react-server-dom-webpack@19.1.0", "", { "dependencies": { "acorn-loose": "^8.3.0", "neo-async": "^2.6.1", "webpack-sources": "^3.2.0" }, "peerDependencies": { "react": "^19.1.0", "react-dom": "^19.1.0", "webpack": "^5.59.0" } }, "sha512-GUbawkNSN0oj8GnuNhMzsvyIHpXqqpAmyOY5NRqNNQ/M8wvUUN8YBoGjDUj9lbmBrmAHS65BByp6325CcWA0eg=="],
+
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
"regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="],
@@ -1417,6 +1491,8 @@
"serialize-error": ["serialize-error@2.1.0", "", {}, "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="],
+ "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
+
"serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
"server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="],
@@ -1521,6 +1597,8 @@
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
+ "tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
+
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
"temp-dir": ["temp-dir@2.0.0", "", {}, "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg=="],
@@ -1529,6 +1607,8 @@
"terser": ["terser@5.43.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="],
+ "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="],
+
"test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="],
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
@@ -1553,7 +1633,7 @@
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
- "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+ "tslib": ["tslib@2.7.0", "", {}, "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
@@ -1577,7 +1657,7 @@
"undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
- "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+ "undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
"unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="],
@@ -1615,10 +1695,16 @@
"warn-once": ["warn-once@0.1.1", "", {}, "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q=="],
+ "watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="],
+
"wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
"webidl-conversions": ["webidl-conversions@5.0.0", "", {}, "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="],
+ "webpack": ["webpack@5.100.2", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw=="],
+
+ "webpack-sources": ["webpack-sources@3.3.3", "", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="],
+
"whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="],
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
@@ -1647,7 +1733,7 @@
"write-file-atomic": ["write-file-atomic@4.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" } }, "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg=="],
- "ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="],
+ "ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
"xcode": ["xcode@3.0.1", "", { "dependencies": { "simple-plist": "^1.1.0", "uuid": "^7.0.3" } }, "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA=="],
@@ -1669,6 +1755,12 @@
"@babel/highlight/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
+ "@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
@@ -1729,12 +1821,24 @@
"@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
+ "@jest/environment/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "@jest/fake-timers/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "@jest/types/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
"@react-native/community-cli-plugin/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"@react-native/community-cli-plugin/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
"@react-native/dev-middleware/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
+ "@react-native/dev-middleware/ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="],
+
+ "@tybys/wasm-util/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "@types/graceful-fs/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@@ -1753,6 +1857,10 @@
"caller-callsite/callsites": ["callsites@2.0.0", "", {}, "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ=="],
+ "chrome-launcher/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "chromium-edge-launcher/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
"chromium-edge-launcher/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -1803,8 +1911,18 @@
"is-bun-module/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
+ "jest-environment-node/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "jest-haste-map/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "jest-mock/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "jest-util/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
"jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+ "jest-worker/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
"jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
@@ -1839,6 +1957,8 @@
"react-native/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+ "react-native/ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="],
+
"react-native-reanimated/react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.1.7", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w=="],
"react-native-web/@react-native/normalize-colors": ["@react-native/normalize-colors@0.74.89", "", {}, "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg=="],
@@ -1877,10 +1997,14 @@
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
+ "terser-webpack-plugin/jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="],
+
"tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
+ "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
+
"whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -1919,16 +2043,28 @@
"@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
+ "@jest/environment/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "@jest/fake-timers/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
"@react-native/community-cli-plugin/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"@react-native/dev-middleware/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "@types/graceful-fs/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "chrome-launcher/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "chromium-edge-launcher/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
@@ -1941,6 +2077,16 @@
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "jest-environment-node/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "jest-mock/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "jest-util/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
+ "jest-worker/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
"lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"log-symbols/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
@@ -1969,6 +2115,12 @@
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "terser-webpack-plugin/jest-worker/@types/node": ["@types/node@24.0.14", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw=="],
+
+ "terser-webpack-plugin/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
+
+ "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
+
"@babel/highlight/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"@babel/highlight/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
@@ -1995,6 +2147,8 @@
"sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
+ "terser-webpack-plugin/jest-worker/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
+
"@babel/highlight/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
diff --git a/components/PrimaryButton.tsx b/components/PrimaryButton.tsx
new file mode 100644
index 0000000..94bd8ce
--- /dev/null
+++ b/components/PrimaryButton.tsx
@@ -0,0 +1,102 @@
+import React from "react";
+import {
+ TouchableOpacity,
+ Text,
+ StyleSheet,
+ ActivityIndicator,
+ ViewStyle,
+ View,
+ TextStyle,
+} from "react-native";
+import { Feather } from "@expo/vector-icons";
+import { useThemeColors, ColorScheme } from "../constants";
+
+interface SendButtonProps {
+ onPress: () => void;
+ isLoading?: boolean;
+ disabled?: boolean;
+ label?: string;
+ style?: ViewStyle;
+ textStyle?: TextStyle;
+}
+
+const SendButton: React.FC<SendButtonProps> = ({
+ onPress,
+ isLoading = false,
+ disabled = false,
+ label = "Send",
+ style,
+}) => {
+ const isButtonDisabled = isLoading || disabled;
+ const colors = useThemeColors();
+
+ return (
+ <TouchableOpacity
+ style={[
+ styles.sendButton,
+ { backgroundColor: colors.button },
+ isButtonDisabled && styles.disabledButton,
+ style,
+ ]}
+ onPress={onPress}
+ disabled={isButtonDisabled}
+ >
+ {isLoading ? (
+ <View
+ style={{
+ flexDirection: "row",
+ alignItems: "center",
+ width: "100%",
+ flex: 1,
+ justifyContent: "center",
+ }}
+ >
+ <ActivityIndicator color="#fff" />
+ </View>
+ ) : (
+ <>
+ <Text
+ style={[
+ styles.sendText,
+ isButtonDisabled && styles.disabledText,
+ { color: colors.buttonText },
+ ]}
+ >
+ {label}
+ </Text>
+ <Feather
+ name="arrow-right"
+ size={16}
+ color={isButtonDisabled ? colors.border : colors.buttonText}
+ />
+ </>
+ )}
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ sendButton: {
+ // paddingVertical: 10,
+ paddingHorizontal: 16,
+ borderRadius: 8,
+ flexDirection: "row",
+ justifyContent: "flex-start",
+ alignItems: "center",
+ gap: 8,
+ height: 48,
+ },
+ sendText: {
+ fontSize: 16,
+ fontWeight: 600,
+ flex: 1,
+ },
+ disabledButton: {
+ backgroundColor: "#4B5563",
+ },
+ disabledText: {
+ color: "#eee",
+ },
+});
+
+export default SendButton;
diff --git a/components/ScreenWrapper.tsx b/components/ScreenWrapper.tsx
new file mode 100644
index 0000000..49c698f
--- /dev/null
+++ b/components/ScreenWrapper.tsx
@@ -0,0 +1,31 @@
+import React from "react";
+import { View, StyleSheet, Platform } from "react-native";
+
+type Props = {
+ children: React.ReactNode;
+ style?: object;
+};
+
+const ScreenWrapper = ({ children, style }: Props) => {
+ return (
+ <View style={styles.outer}>
+ <View style={[styles.inner, style]}>{children}</View>
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ outer: {
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "flex-start",
+ },
+ inner: {
+ width: "100%",
+
+ maxWidth: Platform.OS === "web" ? 420 : "100%",
+ flexGrow: 1,
+ },
+});
+
+export default ScreenWrapper;
diff --git a/components/auth/Auth.tsx b/components/auth/Auth.tsx
new file mode 100644
index 0000000..40512ca
--- /dev/null
+++ b/components/auth/Auth.tsx
@@ -0,0 +1,149 @@
+"use client";
+
+import PrimaryButton from "../PrimaryButton";
+import { SymbolView, SymbolViewProps, SymbolWeight } from "expo-symbols";
+import { useState } from "react";
+import { Platform, StyleProp, ViewStyle } from "react-native";
+
+const PASSKEY_CREDENTIAL_ID_KEY = "urbit_wallet_passkey_id";
+const RELYING_PARTY_ID = "wallet.urbit.org"; // Change this to your domain
+const RELYING_PARTY_NAME = "Urbit Wallet";
+
+export function Passkee() {
+ const [isLoading, setIsLoading] = useState(false);
+ async function handleCreatePasskey() {
+ const pkok =
+ await window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
+ console.log({ pkok });
+
+ // if (Platform.OS !== "web") {
+ // return false;
+ // }
+ console.log("creating passkey");
+
+ try {
+ // Generate a random user ID
+ const userId = new Uint8Array(16);
+ crypto.getRandomValues(userId);
+
+ // Generate a random challenge
+ const challenge = new Uint8Array(32);
+ crypto.getRandomValues(challenge);
+
+ const createCredentialOptions: CredentialCreationOptions = {
+ publicKey: {
+ // REQUIRED: Random challenge to prevent replay attacks
+ // Must be at least 16 bytes, we use 32 for extra security
+ challenge,
+
+ // REQUIRED: Relying Party (your website/app)
+ rp: {
+ // REQUIRED: Human-readable name shown in UI prompts
+ name: RELYING_PARTY_NAME,
+
+ // OPTIONAL: Domain that owns this credential
+ // If omitted, defaults to current domain
+ // Must match or be a registrable suffix of the current domain
+ id:
+ window.location.hostname === "localhost"
+ ? "localhost"
+ : RELYING_PARTY_ID,
+ },
+
+ // REQUIRED: User information
+ user: {
+ // REQUIRED: Unique user ID (must not contain PII)
+ // Used by authenticator to distinguish between accounts
+ id: userId,
+
+ // REQUIRED: Unique username/identifier for this RP
+ // Shown in some UI contexts, should be recognizable to user
+ name: "urbit-user",
+
+ // REQUIRED: Human-readable name for display
+ // Shown in account selectors and prompts
+ displayName: "Urbit Wallet User",
+ },
+
+ // REQUIRED: List of acceptable public key algorithms
+ // Order matters - authenticator will use first supported algorithm
+ pubKeyCredParams: [
+ { alg: -7, type: "public-key" }, // ES256 (ECDSA with SHA-256) - most common
+ { alg: -257, type: "public-key" }, // RS256 (RSASSA-PKCS1-v1_5) - fallback
+ ],
+
+ // OPTIONAL: Criteria for authenticator selection
+ authenticatorSelection: {
+ // OPTIONAL: "platform" (built-in like Touch ID) or "cross-platform" (USB key)
+ // Omitting allows both types
+ // authenticatorAttachment: "platform",
+
+ // OPTIONAL: User verification requirement
+ // "required" - must verify user (biometric/PIN)
+ // "preferred" - verify if possible, continue if not (default)
+ // "discouraged" - don't verify unless required by RP
+ userVerification: "preferred",
+
+ // OPTIONAL: Whether to create a discoverable credential (passkey)
+ // "required" - must create discoverable credential
+ // "preferred" - create if possible (default)
+ // "discouraged" - don't create discoverable credential
+ residentKey: "preferred",
+
+ // DEPRECATED: Use residentKey instead
+ // Kept for backwards compatibility with older authenticators
+ requireResidentKey: false,
+ },
+
+ // OPTIONAL: Time limit in milliseconds (default varies by browser)
+ // 60 seconds is reasonable for user interaction
+ timeout: 60000,
+
+ // OPTIONAL: Attestation preference (proof of authenticator legitimacy)
+ // "none" - no attestation needed (default, best for privacy)
+ // "indirect" - RP prefers attestation but allows anonymization
+ // "direct" - RP needs attestation from authenticator
+ // "enterprise" - RP needs attestation and device info (requires permission)
+ attestation: "none",
+
+ // OPTIONAL: List of credentials to exclude (prevent duplicates)
+ // excludeCredentials: [
+ // { id: existingCredentialId, type: "public-key" }
+ // ],
+
+ // OPTIONAL: Extensions for additional features
+ // extensions: {
+ // credProps: true, // Request additional credential properties
+ // hmacCreateSecret: true, // For symmetric key operations
+ // },
+ },
+ };
+
+ const credential = (await navigator.credentials.create(
+ createCredentialOptions,
+ )) as PublicKeyCredential;
+ console.log({ credential });
+
+ if (credential) {
+ // Store the credential ID for later use
+ // await SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, credential.id);
+
+ console.log("Passkey created successfully", credential.id);
+ return true;
+ }
+
+ return false;
+ } catch (error) {
+ console.error("Error creating passkey:", error);
+ return false;
+ }
+ }
+ return (
+ <PrimaryButton
+ label="Create Passkey"
+ onPress={handleCreatePasskey}
+ isLoading={isLoading}
+ style={{ marginBottom: 16 }}
+ />
+ );
+}
diff --git a/constants/colors.ts b/constants/colors.ts
new file mode 100644
index 0000000..6f07a2c
--- /dev/null
+++ b/constants/colors.ts
@@ -0,0 +1,51 @@
+// import { useSettingsStore } from "../store/useSettingsStore";
+
+export type ColorScheme = typeof lightColors;
+
+export const useThemeColors = (): ColorScheme => {
+ // const isDarkMode = useSettingsStore((s) => s.isDarkMode);
+ // return isDarkMode ? darkColors : lightColors;
+ return lightColors;
+};
+
+export const lightColors = {
+ background: "#F7F7F7",
+ text: "#171717",
+ card: "#FFFFFF",
+ border: "#E5E5E5",
+ primary: "#1997FC",
+ secondary: "#737373", //"#4B5563",
+ toastBackground: "#171717",
+ toastText: "#FFFFFF",
+ toastSuccess: "#12BA03",
+ toastError: "#EF4444",
+ skeletonBase: "#ebebeb",
+ skeletonHighlight: "#f5f5f5",
+ button: "#171717",
+ buttonText: "#F7F7F7",
+ iconBorder: "#D4D4D4",
+ navBorder: "#D4D4D4",
+ switchBackground: "#E5E5E5",
+ switchThumb: "#FFFFFF",
+};
+
+export const darkColors = {
+ background: "#121212",
+ text: "#F3F3F3",
+ card: "#1F1F1F",
+ border: "#323232", //"#2A2A2A",
+ primary: "#1997FC",
+ secondary: "#9CA3AF",
+ toastBackground: "#F3F3F3",
+ toastText: "#121212",
+ toastSuccess: "#22C55E",
+ toastError: "#EF4444",
+ skeletonBase: "#374151",
+ skeletonHighlight: "#4B5563",
+ button: "#F7F7F7",
+ buttonText: "#171717",
+ iconBorder: "#FAFAFA",
+ navBorder: "#323232",
+ switchBackground: "#E5E5E5",
+ switchThumb: "#1F1F1F",
+};
diff --git a/constants/config.ts b/constants/config.ts
new file mode 100644
index 0000000..6fa09b6
--- /dev/null
+++ b/constants/config.ts
@@ -0,0 +1,67 @@
+import { JsonRpcProvider, WebSocketProvider } from "ethers";
+import { ETHEREUM_NETWORK } from "../constants";
+
+const isLocal = false;
+
+const INFURA_API = process.env.EXPO_PUBLIC_INFURA_API!;
+const INFURA_API_SECRET_KEY = process.env.EXPO_PUBLIC_INFURA_API_SECRET_KEY!;
+const NETWORK = process.env.EXPO_PUBLIC_NETWORK!;
+const ETHERSCAN_API_KEY = process.env.EXPO_PUBLIC_ETHERSCAN_API_KEY!;
+const requiredVars = [
+ INFURA_API,
+ INFURA_API_SECRET_KEY,
+ NETWORK,
+ ETHERSCAN_API_KEY,
+];
+
+const missingVar = requiredVars.find((v) => !v);
+
+if (missingVar) {
+ throw new Error(
+ "Missing required environment variables. Check your .env file.",
+ );
+}
+
+export const WEBSOCKET_URL = `wss://${NETWORK}.infura.io/ws/v3/${INFURA_API}`;
+
+export const PROVIDER_URL = isLocal
+ ? "http://localhost:8545"
+ : `https://${NETWORK}.infura.io/v3/${INFURA_API}`;
+
+export const MAINNET_PROVIDER_URL = `https://mainnet.infura.io/v3/${INFURA_API}`;
+
+export const getEtherscanBaseUrl = () => {
+ console.log("NETWORK", NETWORK);
+ return NETWORK === ETHEREUM_NETWORK.MAINNET
+ ? "https://api.etherscan.io/api"
+ : `https://api-${NETWORK}.etherscan.io/api`;
+};
+
+export const httpProvider = new JsonRpcProvider(
+ `https://${NETWORK}.infura.io/v3/${INFURA_API}`,
+);
+export const wsProvider = new WebSocketProvider(WEBSOCKET_URL);
+
+export const getEthTxUrl = (
+ walletAddress: string,
+ page: number = 1,
+ pageSize: number = 20,
+) =>
+ `${getEtherscanBaseUrl()}?module=account&action=txlist&address=${walletAddress}&startblock=0&endblock=99999999&page=${page}&offset=${pageSize}&sort=desc&apikey=${ETHERSCAN_API_KEY}`;
+
+export const getTokenTxUrl = (
+ walletAddress: string,
+ page: number = 1,
+ pageSize: number = 20,
+) =>
+ `${getEtherscanBaseUrl()}?module=account&action=tokentx&address=${walletAddress}&startblock=0&endblock=99999999&page=${page}&offset=${pageSize}&sort=desc&apikey=${ETHERSCAN_API_KEY}`;
+
+export const getTokenIcon = (address: string) =>
+ `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${address}/logo.png`;
+
+export const getInternalTxUrl = (
+ walletAddress: string,
+ page: number = 1,
+ pageSize: number = 20,
+) =>
+ `${getEtherscanBaseUrl()}?module=account&action=txlistinternal&address=${walletAddress}&startblock=0&endblock=99999999&page=${page}&offset=${pageSize}&sort=desc&apikey=${ETHERSCAN_API_KEY}`;
diff --git a/constants/constants.ts b/constants/constants.ts
new file mode 100644
index 0000000..477a2e7
--- /dev/null
+++ b/constants/constants.ts
@@ -0,0 +1,24 @@
+import { ImageSourcePropType } from "react-native";
+import EthLogo from "../assets/eth-logo.png";
+import UsdcLogo from "../assets/usdc-logo.png";
+import linkLogo from "../assets/link-logo.png";
+
+export const ETHEREUM_NETWORK = {
+ MAINNET: "mainnet",
+ SEPOLIA: "sepolia",
+ LOCAL: "local",
+} as const;
+
+export const DEFAULT_HD_PATH = "m/44'/60'/0'/0/0";
+
+export const ETH_PRICE_URL =
+ "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd";
+
+export const TOKEN_ICONS: Record<string, ImageSourcePropType> = {
+ ETH: EthLogo,
+ USDC: UsdcLogo,
+ // USDT: "https://assets.coingecko.com/coins/images/325/thumb/Tether.png?1696501661",
+ // DAI: "https://assets.coingecko.com/coins/images/9956/thumb/Badge_Dai.png?1696509996", //"https://cryptologos.cc/logos/multi-collateral-dai-dai-logo.png",
+ LINK: linkLogo, //"https://assets.coingecko.com/coins/images/877/thumb/chainlink-new-logo.png?1696502009", //"https://cryptologos.cc/logos/chainlink-link-logo.png",
+ // default: "https://via.placeholder.com/36",
+};
diff --git a/constants/contracts.ts b/constants/contracts.ts
new file mode 100644
index 0000000..9c02a4a
--- /dev/null
+++ b/constants/contracts.ts
@@ -0,0 +1,109 @@
+import { ETHEREUM_NETWORK } from "../constants";
+
+type ContractAddresses = Record<string, string>;
+type NetworkKey = keyof typeof ETHEREUM_NETWORK;
+
+export const ERC20_ABI = [
+ {
+ type: "function",
+ name: "balanceOf",
+ inputs: [{ name: "owner", type: "address" }],
+ outputs: [{ name: "", type: "uint256" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ name: "decimals",
+ inputs: [],
+ outputs: [{ name: "", type: "uint8" }],
+ stateMutability: "view",
+ },
+ {
+ type: "function",
+ name: "transfer",
+ inputs: [
+ { name: "to", type: "address" },
+ { name: "value", type: "uint256" },
+ ],
+ outputs: [{ name: "", type: "bool" }],
+ stateMutability: "nonpayable",
+ },
+ {
+ type: "event",
+ name: "Transfer",
+ inputs: [
+ { name: "from", type: "address", indexed: true },
+ { name: "to", type: "address", indexed: true },
+ { name: "value", type: "uint256", indexed: false },
+ ],
+ anonymous: false,
+ },
+];
+
+export const AZIMUTH_ABI = [
+ "function getOwner(uint32 _point) view returns (address)",
+ "function getOwnedPoints(address _whose) view returns (uint32[])",
+];
+
+const CONTRACT_ADDRESSES: Record<NetworkKey, ContractAddresses> = {
+ MAINNET: {
+ azimuth: "0x223c067f8cf28ae173ee5cafea60ca44c335fecb",
+ ecliptic: "0x33EeCbf908478C10614626A9D304bfe18B78DD73",
+ polls: "0x0",
+ claims: "0x0",
+ linearStarRelease: "0x86cd9cd0992f04231751e3761de45cecea5d1801",
+ conditionalStarRelease: "0x8c241098c3d3498fe1261421633fd57986d74aea",
+ urbit_L2: "0x1111111111111111111111111111111111111111",
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606EB48",
+ usdt: "0xdac17f958d2ee523a2206206994597c13d831ec7",
+ dai: "0x6b175474e89094c44da98b954eedeac495271d0f",
+ link: "0x514910771af9ca656af840dff83e8264ecf986ca", // ?
+ },
+ SEPOLIA: {
+ azimuth: "0xF07cD672D61453c29138c8db5b44fC9FA84811B5",
+ ecliptic: "0x2E35a61198C383212CeF06C22f1E81B6b097135C",
+ polls: "0x3A3a06199Dc537FB56A6975A8B12A8eD7fCbf897",
+ claims: "0xdB164DBEF321e7DE938809fE35A5A8A928c4F4df",
+ linearStarRelease: "0x0",
+ conditionalStarRelease: "0x0",
+ urbit_L2: "0x0",
+ usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
+ usdt: "0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0",
+ dai: "0x776b6fc2ed15d6bb5fc32e0c89de68683118c62a",
+ link: "0x779877A7B0D9E8603169DdbD7836e478b4624789",
+ },
+ LOCAL: {
+ azimuth: "0x0",
+ ecliptic: "0x0",
+ polls: "0x0",
+ claims: "0x0",
+ linearStarRelease: "0x0",
+ conditionalStarRelease: "0x0",
+ urbit_L2: "0x0",
+ usdc: "0x0",
+ usdt: "0x0",
+ dai: "0x0",
+ link: "0x0",
+ },
+};
+
+const mapNetworkStringToKey = (network: string): NetworkKey => {
+ switch (network) {
+ case "mainnet":
+ return "MAINNET";
+ case "sepolia":
+ return "SEPOLIA";
+ case "local":
+ return "LOCAL";
+ default:
+ return "SEPOLIA";
+ }
+};
+
+const currentNetworkKey = mapNetworkStringToKey(
+ process.env.EXPO_PUBLIC_NETWORK!,
+);
+
+console.log("currentNetworkKey", currentNetworkKey);
+
+export const CONTRACT = CONTRACT_ADDRESSES[currentNetworkKey];
diff --git a/constants/index.ts b/constants/index.ts
new file mode 100644
index 0000000..ad2c758
--- /dev/null
+++ b/constants/index.ts
@@ -0,0 +1,5 @@
+export * from "./contracts";
+export * from "./constants";
+export * from "./colors";
+export * from "./config";
+export * from "./routes";
diff --git a/constants/routes.ts b/constants/routes.ts
new file mode 100644
index 0000000..697f4fc
--- /dev/null
+++ b/constants/routes.ts
@@ -0,0 +1,11 @@
+export const ROUTES = {
+ PASSKEY_SETUP: "PasskeySetup",
+ LOGIN: "Login",
+ HOME: "Home",
+ SEND: "Send",
+ RECEIVE: "Receive",
+ HISTORY: "TransactionHistory",
+ MAIN_TABS: "MainTabs",
+ AUTH: "Auth",
+ APP: "App",
+} as const;
diff --git a/lib/passkey.ts b/lib/passkey.ts
new file mode 100644
index 0000000..573c62b
--- /dev/null
+++ b/lib/passkey.ts
@@ -0,0 +1,131 @@
+const PASSKEY_CREDENTIAL_ID_KEY = "urbit_wallet_passkey_id";
+const RELYING_PARTY_ID = "wallet.urbit.org"; // Change this to your domain
+const RELYING_PARTY_NAME = "Urbit Wallet";
+
+async function createPasskey() {
+ const pkok =
+ await window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
+ console.log({ pkok });
+
+ // if (Platform.OS !== "web") {
+ // return false;
+ // }
+ console.log("creating passkey");
+
+ try {
+ // Generate a random user ID
+ const userId = new Uint8Array(16);
+ crypto.getRandomValues(userId);
+
+ // Generate a random challenge
+ const challenge = new Uint8Array(32);
+ crypto.getRandomValues(challenge);
+
+ const createCredentialOptions: CredentialCreationOptions = {
+ publicKey: {
+ // REQUIRED: Random challenge to prevent replay attacks
+ // Must be at least 16 bytes, we use 32 for extra security
+ challenge,
+
+ // REQUIRED: Relying Party (your website/app)
+ rp: {
+ // REQUIRED: Human-readable name shown in UI prompts
+ name: RELYING_PARTY_NAME,
+
+ // OPTIONAL: Domain that owns this credential
+ // If omitted, defaults to current domain
+ // Must match or be a registrable suffix of the current domain
+ id:
+ window.location.hostname === "localhost"
+ ? "localhost"
+ : RELYING_PARTY_ID,
+ },
+
+ // REQUIRED: User information
+ user: {
+ // REQUIRED: Unique user ID (must not contain PII)
+ // Used by authenticator to distinguish between accounts
+ id: userId,
+
+ // REQUIRED: Unique username/identifier for this RP
+ // Shown in some UI contexts, should be recognizable to user
+ name: "urbit-user",
+
+ // REQUIRED: Human-readable name for display
+ // Shown in account selectors and prompts
+ displayName: "Urbit Wallet User",
+ },
+
+ // REQUIRED: List of acceptable public key algorithms
+ // Order matters - authenticator will use first supported algorithm
+ pubKeyCredParams: [
+ { alg: -7, type: "public-key" }, // ES256 (ECDSA with SHA-256) - most common
+ { alg: -257, type: "public-key" }, // RS256 (RSASSA-PKCS1-v1_5) - fallback
+ ],
+
+ // OPTIONAL: Criteria for authenticator selection
+ authenticatorSelection: {
+ // OPTIONAL: "platform" (built-in like Touch ID) or "cross-platform" (USB key)
+ // Omitting allows both types
+ // authenticatorAttachment: "platform",
+
+ // OPTIONAL: User verification requirement
+ // "required" - must verify user (biometric/PIN)
+ // "preferred" - verify if possible, continue if not (default)
+ // "discouraged" - don't verify unless required by RP
+ userVerification: "preferred",
+
+ // OPTIONAL: Whether to create a discoverable credential (passkey)
+ // "required" - must create discoverable credential
+ // "preferred" - create if possible (default)
+ // "discouraged" - don't create discoverable credential
+ residentKey: "preferred",
+
+ // DEPRECATED: Use residentKey instead
+ // Kept for backwards compatibility with older authenticators
+ requireResidentKey: false,
+ },
+
+ // OPTIONAL: Time limit in milliseconds (default varies by browser)
+ // 60 seconds is reasonable for user interaction
+ timeout: 60000,
+
+ // OPTIONAL: Attestation preference (proof of authenticator legitimacy)
+ // "none" - no attestation needed (default, best for privacy)
+ // "indirect" - RP prefers attestation but allows anonymization
+ // "direct" - RP needs attestation from authenticator
+ // "enterprise" - RP needs attestation and device info (requires permission)
+ attestation: "none",
+
+ // OPTIONAL: List of credentials to exclude (prevent duplicates)
+ // excludeCredentials: [
+ // { id: existingCredentialId, type: "public-key" }
+ // ],
+
+ // OPTIONAL: Extensions for additional features
+ // extensions: {
+ // credProps: true, // Request additional credential properties
+ // hmacCreateSecret: true, // For symmetric key operations
+ // },
+ },
+ };
+
+ const credential = (await navigator.credentials.create(
+ createCredentialOptions,
+ )) as PublicKeyCredential;
+ console.log({ credential });
+
+ if (credential) {
+ // Store the credential ID for later use
+ // await SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, credential.id);
+
+ console.log("Passkey created successfully", credential.id);
+ return true;
+ }
+
+ return false;
+ } catch (error) {
+ console.error("Error creating passkey:", error);
+ return false;
+ }
+}
diff --git a/package.json b/package.json
index 48f24aa..5fed9f5 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@react-navigation/bottom-tabs": "^7.3.10",
"@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6",
+ "ethers": "^6.15.0",
"expo": "~53.0.17",
"expo-blur": "~14.1.5",
"expo-constants": "~17.1.7",
@@ -36,7 +37,8 @@
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-web": "~0.20.0",
- "react-native-webview": "13.13.5"
+ "react-native-webview": "13.13.5",
+ "react-server-dom-webpack": "^19.1.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",