Refactor useSignRequestHandler

This commit is contained in:
AdityaSalunkhe21 2025-04-11 18:10:00 +05:30
parent 3eedadafc3
commit feb86bd5f8
4 changed files with 96 additions and 122 deletions

3
src/global.d.ts vendored
View File

@ -21,9 +21,6 @@ declare global {
// Handles incoming signature requests from Android
receiveSignRequestFromAndroid?: (message: string) => void;
// Handles request to create or retrieve accounts
receiveCreateOrGetAccountsRequestFromAndroid?: () => void;
}
}

View File

@ -1,32 +1,32 @@
import { useEffect } from "react";
import { useEffect, useCallback } from "react";
import { createWallet } from "../utils/accounts";
import { sendMessage } from "../utils/misc";
import useAccountsData from "./useAccountsData";
import { useNetworks } from "../context/NetworksContext";
const useGetOrCreateAccounts = (onWalletCreated?: () => void) => {
const useGetOrCreateAccounts = () => {
const { networksData } = useNetworks();
const { getAccountsData } = useAccountsData();
// Wrap the function in useCallback to prevent recreation on each render
const getOrCreateAccountsForChain = useCallback(async (chainId: string) => {
let accountsData = await getAccountsData(chainId);
if (accountsData.length === 0) {
console.log("Accounts not found, creating wallet...");
await createWallet(networksData);
accountsData = await getAccountsData(chainId);
}
return accountsData;
}, [networksData, getAccountsData]);
useEffect(() => {
const handleCreateAccounts = async (event: MessageEvent) => {
if (event.data.type !== 'REQUEST_CREATE_OR_GET_ACCOUNTS') return;
let accountsData = await getAccountsData(event.data.chainId);
if (accountsData.length === 0) {
console.log("Accounts not found, creating wallet...");
await createWallet(networksData);
// Re-fetch newly created accounts
accountsData = await getAccountsData(event.data.chainId);
onWalletCreated?.();
}
// Notify Android that accounts are ready
if (window.Android?.onAccountsReady) {
window.Android.onAccountsReady();
}
const accountsData = await getOrCreateAccountsForChain(event.data.chainId);
sendMessage(
event.source as Window, 'WALLET_ACCOUNTS_DATA',
@ -35,12 +35,36 @@ const useGetOrCreateAccounts = (onWalletCreated?: () => void) => {
);
};
const autoCreateAccounts = async () => {
const defaultChainId = networksData[0]?.chainId;
if (!defaultChainId) {
console.log('useGetOrCreateAccounts: No default chainId found');
return;
}
await getOrCreateAccountsForChain(defaultChainId);
// Notify Android that accounts are ready
if (window.Android?.onAccountsReady) {
window.Android.onAccountsReady();
} else {
console.log('useGetOrCreateAccounts: Android bridge not available');
}
};
window.addEventListener('message', handleCreateAccounts);
const isAndroidWebView = !!(window.Android);
if (isAndroidWebView) {
autoCreateAccounts();
}
return () => {
window.removeEventListener('message', handleCreateAccounts);
};
}, [networksData, getAccountsData, onWalletCreated]);
}, [networksData, getAccountsData, getOrCreateAccountsForChain]);
};
export default useGetOrCreateAccounts;
export default useGetOrCreateAccounts;

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { useEffect, useRef, useCallback } from 'react';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
@ -7,82 +7,59 @@ import { useNetworks } from '../context/NetworksContext';
import { StackParamsList } from '../types';
import useGetOrCreateAccounts from './useGetOrCreateAccounts';
/**
* Hook to manage sign request data state and Android bridge notifications
*/
export const useSignRequestData = () => {
export const useSignRequestHandler = () => {
// Navigation and context hooks
const navigation = useNavigation<NativeStackNavigationProp<StackParamsList>>();
const { selectedNetwork } = useNetworks();
const { accounts, currentIndex } = useAccounts();
const [isDataReady, setIsDataReady] = useState(false);
useEffect(() => {
if (selectedNetwork && accounts && accounts.length > 0) {
setIsDataReady(true);
// Notify Android when accounts are ready for signing
window.Android?.onAccountsReady?.();
}
}, [selectedNetwork, accounts, currentIndex]);
return { isDataReady, selectedNetwork, accounts, currentIndex };
};
/**
* Hook to handle navigation for sign requests with validation
*/
export const useSignRequestNavigation = () => {
const navigation = useNavigation<NativeStackNavigationProp<StackParamsList>>();
const { isDataReady, selectedNetwork, accounts, currentIndex } = useSignRequestData();
// Initialize accounts
useGetOrCreateAccounts();
// Use a ref for pending messages instead of state to avoid re-renders
const pendingMessageRef = useRef<string | null>(null);
const navigateToSignRequest = useCallback(async (message: string) => {
// Queue message if data isn't ready yet
// Core navigation handler
const navigateToSignRequest = useCallback((message: string) => {
// Data readiness check
const isDataReady = !!(selectedNetwork && accounts && accounts.length > 0);
if (!isDataReady) {
pendingMessageRef.current = message;
return;
}
// Validate required data
if (!selectedNetwork) {
window.Android?.onSignatureError?.('No network selected');
return;
}
if (!accounts?.length) {
window.Android?.onSignatureError?.('No accounts available');
return;
}
const currentAccount = accounts[currentIndex];
if (!currentAccount) {
window.Android?.onSignatureError?.('Current account not found');
return;
}
// Validate network properties
if (!selectedNetwork.namespace || !selectedNetwork.chainId) {
window.Android?.onSignatureError?.('Network missing required properties');
return;
}
try {
// Build and validate signing path
const path = `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${currentAccount.address}/${encodeURIComponent(message)}`;
const pathRegex = /^\/sign\/(eip155|cosmos)\/(.+)\/(.+)\/(.+)$/;
if (!pathRegex.test(path)) {
window.Android?.onSignatureError?.('Invalid path format');
// Validation checks
if (!selectedNetwork?.namespace || !selectedNetwork?.chainId) {
window.Android?.onSignatureError?.('Invalid network configuration');
return;
}
if (!accounts?.length) {
window.Android?.onSignatureError?.('No accounts available');
return;
}
const currentAccount = accounts[currentIndex];
if (!currentAccount) {
window.Android?.onSignatureError?.('Current account not found');
return;
}
// Create the path and validate with regex
const path = `/sign/${selectedNetwork.namespace}/${selectedNetwork.chainId}/${currentAccount.address}/${encodeURIComponent(message)}`;
const pathRegex = /^\/sign\/(eip155|cosmos)\/(.+)\/(.+)\/(.+)$/;
const match = path.match(pathRegex);
if (!match) {
window.Android?.onSignatureError?.('Failed to parse path');
window.Android?.onSignatureError?.('Invalid signing path');
return;
}
const [, pathNamespace, pathChainId, pathAddress, pathMessage] = match;
// Navigate to sign request screen
// Reset navigation stack and navigate to sign request
navigation.reset({
index: 0,
routes: [
@ -102,55 +79,31 @@ export const useSignRequestNavigation = () => {
} catch (error) {
window.Android?.onSignatureError?.(`Navigation error: ${error}`);
}
}, [isDataReady, selectedNetwork, accounts, currentIndex, navigation]);
}, [selectedNetwork, accounts, currentIndex, navigation]);
// Process any pending message when data becomes ready
// Setup Android bridge and handle pending messages
useEffect(() => {
if (pendingMessageRef.current && isDataReady) {
// Setup global function to receive sign requests from Android
window.receiveSignRequestFromAndroid = navigateToSignRequest;
// Process any pending messages whenever dependencies change
if (pendingMessageRef.current && selectedNetwork && accounts?.length > 0) {
const message = pendingMessageRef.current;
pendingMessageRef.current = null;
navigateToSignRequest(message);
}
}, [isDataReady, navigateToSignRequest]);
return { navigateToSignRequest };
};
/**
* Hook to set up Android bridge communication
*/
export const useAndroidBridge = () => {
const { navigateToSignRequest } = useSignRequestNavigation();
useEffect(() => {
// Handle sign requests from Android
window.receiveSignRequestFromAndroid = (message: string) => {
navigateToSignRequest(message);
};
// Set up accounts request handler
window.receiveCreateOrGetAccountsRequestFromAndroid = () => {
// Handled by useGetOrCreateAccounts hook
};
// Initialize Android bridge
// Notify Android that JS bridge is ready
if (window.Android) {
setTimeout(() => window.Android?.onJsBridgeReady?.(), 100);
const timeoutId = setTimeout(() => window.Android?.onJsBridgeReady?.(), 100);
return () => {
clearTimeout(timeoutId);
window.receiveSignRequestFromAndroid = undefined;
};
}
return () => {
window.receiveSignRequestFromAndroid = undefined;
window.receiveCreateOrGetAccountsRequestFromAndroid = undefined;
};
}, [navigateToSignRequest]);
};
/**
* Main hook that combines all sign request handling functionality
*/
export const useSignRequestHandler = () => {
useGetOrCreateAccounts();
useSignRequestData();
useSignRequestNavigation();
useAndroidBridge();
};
}, [navigateToSignRequest, selectedNetwork, accounts]);
};

View File

@ -56,4 +56,4 @@ const SignMessage = ({ route }: SignProps) => {
);
};
export default SignMessage;
export default SignMessage;