Sign message from app

This commit is contained in:
pranavjadhav007 2025-04-04 17:11:45 +05:30
parent 3a0a321c6f
commit d9011dbdb2
4 changed files with 141 additions and 8 deletions

View File

@ -0,0 +1,75 @@
import React, { useState, useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useAccounts } from '../context/AccountsContext';
import { useNetworks } from '../context/NetworksContext';
import { StackParamsList } from '../types';
import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts';
declare global {
interface Window {
receiveSignRequestFromAndroid?: (message: string) => void;
}
}
export const SignRequestHandler: React.FC = () => {
const navigation = useNavigation<NativeStackNavigationProp<StackParamsList>>();
const { accounts, currentIndex } = useAccounts();
const { selectedNetwork } = useNetworks();
const [pendingMessage, setPendingMessage] = useState<string | null>(null);
useGetOrCreateAccounts();
useEffect(() => {
if (pendingMessage && selectedNetwork && accounts && accounts.length > 0) {
navigation.reset({
index: 0,
routes: [
{
name: 'SignRequest',
params: {
address: accounts[currentIndex].address,
message: pendingMessage,
requestEvent: null,
path: `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${accounts[currentIndex].address}/${encodeURIComponent(pendingMessage)}`
}
}
]
});
setPendingMessage(null);
}
}, [pendingMessage, selectedNetwork, accounts, currentIndex, navigation]);
useEffect(() => {
window.receiveSignRequestFromAndroid = (message: string) => {
if (!selectedNetwork || !accounts || accounts.length === 0) {
// Store the message and wait for wallet creation
setPendingMessage(message);
return;
}
navigation.reset({
index: 0,
routes: [
{
name: 'SignRequest',
params: {
address: accounts[currentIndex].address,
message: message,
requestEvent: null,
path: `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${accounts[currentIndex].address}/${encodeURIComponent(message)}`
}
}
]
});
};
return () => {
if ('receiveSignRequestFromAndroid' in window) {
window.receiveSignRequestFromAndroid = undefined;
}
};
}, [navigation, accounts, currentIndex, selectedNetwork]);
return null;
};

View File

@ -1,11 +1,20 @@
import { useEffect } from "react";
import { createWallet } from "../utils/accounts";
import { sendMessage } from "../utils/misc";
import useAccountsData from "./useAccountsData";
import { useNetworks } from "../context/NetworksContext";
const useGetOrCreateAccounts = () => {
declare global {
interface Window {
Android?: {
onSignatureComplete?: (signature: string) => void;
onSignatureError?: (error: string) => void;
onSignatureCancelled?: () => void;
};
}
}
const useGetOrCreateAccounts = (onWalletCreated?: () => void) => {
const { networksData } = useNetworks();
const { getAccountsData } = useAccountsData();
@ -21,6 +30,8 @@ const useGetOrCreateAccounts = () => {
// Re-fetch newly created accounts
accountsData = await getAccountsData(event.data.chainId);
onWalletCreated?.();
}
sendMessage(
@ -30,12 +41,33 @@ const useGetOrCreateAccounts = () => {
);
};
const autoCreateAccounts = async () => {
const defaultChainId = networksData[0]?.chainId;
if (!defaultChainId) return;
let accountsData = await getAccountsData(defaultChainId);
if (accountsData.length === 0) {
console.log("Auto-creating wallet...");
await createWallet(networksData);
accountsData = await getAccountsData(defaultChainId);
onWalletCreated?.();
}
};
window.addEventListener('message', handleCreateAccounts);
const isAndroidWebView = !!(window.Android);
if (isAndroidWebView) {
autoCreateAccounts();
}
return () => {
window.removeEventListener('message', handleCreateAccounts);
};
}, [networksData, getAccountsData]);
}, [networksData, getAccountsData, onWalletCreated]);
};
export default useGetOrCreateAccounts;
export default useGetOrCreateAccounts;

View File

@ -18,6 +18,8 @@ import { useNetworks } from "../context/NetworksContext";
import ImportWalletDialog from "../components/ImportWalletDialog";
import { MnemonicDialog } from "../components/MnemonicDialog";
import { Container } from "../components/Container";
import { SignRequestHandler } from '../components/SignRequestHandler';
import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts';
import { IS_IMPORT_WALLET_ENABLED } from "../utils/constants";
const HomeScreen = () => {
@ -64,8 +66,34 @@ const HomeScreen = () => {
setPhrase(mnemonic);
setSelectedNetwork(networksData[0]);
}
setIsWalletCreating(false);
};
const handleWalletCreated = useCallback(() => {
setIsWalletCreated(true);
fetchAccounts();
}, [fetchAccounts]);
useGetOrCreateAccounts(handleWalletCreated);
useEffect(() => {
fetchAccounts();
}, [networksData, setAccounts, selectedNetwork, fetchAccounts]);
useEffect(() => {
const initializeWallet = async () => {
if (!isWalletCreated && networksData.length > 0) {
const mnemonic = await createWallet(networksData);
if (mnemonic) {
await fetchAccounts();
setSelectedNetwork(networksData[0]);
}
}
};
initializeWallet();
}, [networksData, isWalletCreated, fetchAccounts, setSelectedNetwork]);
const importWalletHandler = async (recoveryPhrase: string) => {
try {
const mnemonic = await createWallet(networksData, recoveryPhrase);
@ -114,10 +142,6 @@ const HomeScreen = () => {
setCurrentIndex(0);
};
useEffect(() => {
fetchAccounts();
}, [networksData, setAccounts, selectedNetwork, fetchAccounts]);
return (
<View style={styles.appContainer}>
<Container>
@ -161,6 +185,7 @@ const HomeScreen = () => {
)}
</>
)}
<SignRequestHandler />
<ImportWalletDialog
visible={importWalletDialog}
hideDialog={() => setImportWalletDialog(false)}

View File

@ -10,6 +10,7 @@ export type StackParamsList = {
selectedNamespace: string;
selectedChainId: string;
accountInfo: Account;
prefillMessage?: string;
};
SignRequest: {
namespace: string;