Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/mobile-app/app/menu/debug/oreowallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ export default function MenuDebugOreowallet() {
onPress={async () => {
if (!account.data) return;

const result = await OreowalletServerApi.removeAccount(
Network.MAINNET,
await getAccountInfo(account.data.name),
);
console.log(JSON.stringify(result));
}}
title="Remove Account"
/>
<Button
onPress={async () => {
if (!account.data) return;

const result = await OreowalletServerApi.getTransactions(
Network.MAINNET,
await getAccountInfo(account.data.name),
Expand Down
168 changes: 137 additions & 31 deletions packages/mobile-app/app/menu/network/index.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,130 @@
import { StatusBar } from "expo-status-bar";
import { Button, Modal, StyleSheet, Text, View } from "react-native";
import { useRouter } from "expo-router";
import {
Button,
Modal,
StyleSheet,
Text,
View,
ActivityIndicator,
} from "react-native";
import { useState } from "react";
import { useFacade } from "@/data/facades";
import { SettingsKey } from "@/data/settings/db";
import { Network } from "@/data/constants";
import { AccountFormat } from "@ironfish/sdk";

export default function MenuNetwork() {
const router = useRouter();

const [modalVisible, setModalVisible] = useState(false);
const [isChangingNetwork, setIsChangingNetwork] = useState(false);

const facade = useFacade();

const setAppSetting = facade.setAppSetting.useMutation();
const getAccounts = facade.getAccounts.useQuery();
const exportAccount = facade.exportAccount.useMutation();
const importAccount = facade.importAccount.useMutation();
const networkSetting = facade.getAppSettings.useQuery();

const currentNetwork =
networkSetting.data?.[SettingsKey.Network] ?? Network.MAINNET;
const targetNetwork =
currentNetwork === Network.MAINNET ? Network.TESTNET : Network.MAINNET;

const handleNetworkChange = async (network: Network) => {
setIsChangingNetwork(true);
try {
// First update the network setting
await setAppSetting.mutateAsync({
key: SettingsKey.Network,
value: network,
});

// Re-import all accounts for the new network
const accounts = getAccounts.data ?? [];
for (const account of accounts) {
// Export the account first
const encodedAccount = await exportAccount.mutateAsync({
name: account.name,
format: AccountFormat.Base64Json,
});
// Then import it for the new network
try {
await importAccount.mutateAsync({
account: encodedAccount,
name: account.name,
});
} catch (error) {
console.error(error);
}
}
} finally {
setIsChangingNetwork(false);
setModalVisible(false);
}
};

if (getAccounts.isLoading || networkSetting.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator size="large" />
<Text style={styles.loadingText}>Loading...</Text>
</View>
);
}

return (
<View style={styles.container}>
<Modal animationType="slide" visible={modalVisible}>
<View style={styles.container}>
<Text>Switch to Testnet?</Text>
<Text>
Switching networks requires a blockchain rescan, which may take time
based on your last sync.
</Text>
<Button
title="Yes, Change Network"
onPress={() => {
setAppSetting.mutate({
key: SettingsKey.Network,
value: Network.TESTNET,
});
setModalVisible(false);
}}
/>
<Button
title="I changed my mind"
onPress={() => setModalVisible(false)}
/>
{isChangingNetwork ? (
<>
<ActivityIndicator size="large" />
<Text style={styles.loadingText}>
Changing network and re-importing accounts...
</Text>
</>
) : (
<>
<Text>Switch to {targetNetwork}?</Text>
<Text>
Switching networks will upload your accounts to the{" "}
{targetNetwork} server. It may take a few minutes for your
accounts to sync.
</Text>
<Button
title="Yes, Change Network"
onPress={() => handleNetworkChange(targetNetwork)}
/>
<Button
title="I changed my mind"
onPress={() => setModalVisible(false)}
/>
</>
)}
</View>
</Modal>
<Button title="Back" onPress={() => router.dismiss()} />
<Text>Mainnet</Text>
<Text>
The live blockchain network where real transactions with value occur.
</Text>
<Text>Testnet</Text>
<Text>A separate environment for testing without real asset risks.</Text>
<View style={styles.networkOption}>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Mainnet</Text>
<Text style={styles.networkDescription}>
The live blockchain network where real transactions with value
occur.
</Text>
{currentNetwork === Network.MAINNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>
</View>
<View style={styles.networkOption}>
<View style={styles.networkInfo}>
<Text style={styles.networkTitle}>Testnet</Text>
<Text style={styles.networkDescription}>
A separate environment for testing without real asset risks.
</Text>
{currentNetwork === Network.TESTNET && (
<Text style={styles.selectedText}>(Selected)</Text>
)}
</View>
</View>
<Button title="Change Network" onPress={() => setModalVisible(true)} />
<StatusBar style="auto" />
</View>
Expand All @@ -60,4 +138,32 @@ const styles = StyleSheet.create({
alignItems: "center",
justifyContent: "center",
},
networkOption: {
width: "100%",
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
networkInfo: {
alignItems: "center",
},
networkTitle: {
fontSize: 18,
fontWeight: "bold",
marginBottom: 8,
},
networkDescription: {
textAlign: "center",
color: "#666",
marginBottom: 8,
},
selectedText: {
color: "#007AFF",
fontWeight: "500",
},
loadingText: {
marginTop: 16,
fontSize: 16,
color: "#666",
},
});
3 changes: 0 additions & 3 deletions packages/mobile-app/data/facades/chain/demoHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ export const chainDemoHandlers = f.facade<ChainHandlers>({
};
},
),
getNetworkInfo: f.handler.query(async () => {
return { networkId: 0 };
}),
isValidPublicAddress: f.handler.query(
async ({ address }: { address: string }) => {
return isValidPublicAddress(address);
Expand Down
12 changes: 6 additions & 6 deletions packages/mobile-app/data/facades/chain/oreowalletHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { f } from "data-facade";
import { Asset, ChainHandlers } from "./types";

import { isValidPublicAddress } from "ironfish-native-module";
import { Network } from "../../constants";
import { oreoWallet } from "../../wallet/oreowalletWallet";
import { SettingsManager } from "@/data/settings/manager";
import { SettingsKey } from "@/data/settings/db";

export const chainHandlers = f.facade<ChainHandlers>({
getAsset: f.handler.query(
async ({ assetId }: { assetId: string }): Promise<Asset | null> => {
const asset = await oreoWallet.getAsset(Network.MAINNET, assetId);
const network = await SettingsManager.db().getOrDefault(
SettingsKey.Network,
);
const asset = await oreoWallet.getAsset(network, assetId);

if (!asset) {
return null;
Expand All @@ -35,10 +39,6 @@ export const chainHandlers = f.facade<ChainHandlers>({
};
},
),
getNetworkInfo: f.handler.query(async () => {
// TODO: Implement network switching
return { networkId: 0 };
}),
isValidPublicAddress: f.handler.query(({ address }: { address: string }) => {
return isValidPublicAddress(address);
}),
Expand Down
1 change: 0 additions & 1 deletion packages/mobile-app/data/facades/chain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export type Asset = {

export type ChainHandlers = {
getAsset: Query<(args: { assetId: string }) => Asset | null>;
getNetworkInfo: Query<() => { networkId: number }>;
isValidPublicAddress: Query<(args: { address: string }) => boolean>;
requestFaucetTokens: Mutation<
(args: { address: string; email: string }) => boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ export const chainHandlers = f.facade<ChainHandlers>({
};
},
),
getNetworkInfo: f.handler.query(async () => {
// TODO: Implement network switching
return { networkId: 0 };
}),
isValidPublicAddress: f.handler.query(({ address }: { address: string }) => {
return isValidPublicAddress(address);
}),
Expand Down
Loading
Loading