diff --git a/src/App.tsx b/src/App.tsx index 56845fa..80272a4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -44,7 +44,7 @@ import { useWebViewHandler } from "./hooks/useWebViewHandler"; import SignRequestEmbed from "./screens/SignRequestEmbed"; import useAddAccountEmbed from "./hooks/useAddAccountEmbed"; import useExportPKEmbed from "./hooks/useExportPrivateKeyEmbed"; -import { SendTxEmbed } from "./screens/SendTxEmbed"; +import { SignTxEmbed } from "./screens/SignTxEmbed"; const Stack = createStackNavigator(); @@ -390,8 +390,8 @@ const App = (): React.JSX.Element => { }} /> <>, }} diff --git a/src/hooks/useGetOrCreateAccounts.ts b/src/hooks/useGetOrCreateAccounts.ts index b00c55d..dc319f2 100644 --- a/src/hooks/useGetOrCreateAccounts.ts +++ b/src/hooks/useGetOrCreateAccounts.ts @@ -5,6 +5,7 @@ import { sendMessage } from "../utils/misc"; import useAccountsData from "./useAccountsData"; import { useNetworks } from "../context/NetworksContext"; import { useAccounts } from "../context/AccountsContext"; +import { WALLET_ACCOUNTS_DATA } from "../utils/constants"; const REACT_APP_ALLOWED_URLS = process.env.REACT_APP_ALLOWED_URLS; @@ -48,7 +49,7 @@ const useGetOrCreateAccounts = () => { const accountsData = await getOrCreateAccountsForChain(event.data.chainId); sendMessage( - event.source as Window, 'WALLET_ACCOUNTS_DATA', + event.source as Window, WALLET_ACCOUNTS_DATA, accountsData.map(account => account.address), event.origin ); diff --git a/src/screens/AutoSignIn.tsx b/src/screens/AutoSignIn.tsx index 0a16e00..1354534 100644 --- a/src/screens/AutoSignIn.tsx +++ b/src/screens/AutoSignIn.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from 'react'; import { useNetworks } from '../context/NetworksContext'; import { signMessage } from '../utils/sign-message'; -import { EIP155 } from '../utils/constants'; +import { AUTO_SIGN_IN, EIP155, SIGN_IN_RESPONSE } from '../utils/constants'; import { sendMessage } from '../utils/misc'; import useAccountsData from '../hooks/useAccountsData'; import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts'; @@ -16,7 +16,7 @@ export const AutoSignIn = () => { useEffect(() => { const handleSignIn = async (event: MessageEvent) => { - if (event.data.type !== 'AUTO_SIGN_IN') return; + if (event.data.type !== AUTO_SIGN_IN) return; if (!REACT_APP_ALLOWED_URLS) { console.log('Allowed URLs are not set'); @@ -38,7 +38,7 @@ export const AutoSignIn = () => { const signature = await signMessage({ message: event.data.message, accountId: accountsData[0].index, chainId: event.data.chainId, namespace: EIP155 }) - sendMessage(event.source as Window, 'SIGN_IN_RESPONSE', { message: event.data.message, signature }, event.origin); + sendMessage(event.source as Window, SIGN_IN_RESPONSE, { message: event.data.message, signature }, event.origin); }; window.addEventListener('message', handleSignIn); diff --git a/src/screens/SignRequestEmbed.tsx b/src/screens/SignRequestEmbed.tsx index 7a3fbfd..3cafa44 100644 --- a/src/screens/SignRequestEmbed.tsx +++ b/src/screens/SignRequestEmbed.tsx @@ -14,7 +14,8 @@ import AccountDetails from '../components/AccountDetails'; import styles from '../styles/stylesheet'; import { getCosmosAccounts, retrieveSingleAccount } from '../utils/accounts'; import { getMnemonic, getPathKey, sendMessage } from '../utils/misc'; -import { COSMOS } from '../utils/constants'; +import { COSMOS, SIGN_MESSAGE, SIGNED_MESSAGE } from '../utils/constants'; +import { useNetworks } from '../context/NetworksContext'; const REACT_APP_ALLOWED_URLS = process.env.REACT_APP_ALLOWED_URLS; @@ -31,6 +32,7 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { const [isLoading, setIsLoading] = useState(true); const [isApproving, setIsApproving] = useState(false); + const { networksData } = useNetworks(); const navigation = useNavigation>(); @@ -42,7 +44,13 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { const requestAccount = await retrieveSingleAccount(COSMOS, chainId, signerAddress); const path = (await getPathKey(`${COSMOS}:${chainId}`, requestAccount!.index)).path; const mnemonic = await getMnemonic(); - const cosmosAccount = await getCosmosAccounts(mnemonic, path, 'zenith'); + + const requestedNetworkData = networksData.find(networkData => networkData.chainId === chainId) + if (!requestedNetworkData) { + throw new Error("Requested network not found") + } + + const cosmosAccount = await getCosmosAccounts(mnemonic, path, requestedNetworkData?.addressPrefix); const cosmosAminoSignature = await cosmosAccount.cosmosWallet.signAmino( signerAddress, @@ -53,7 +61,7 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { sendMessage( sourceWindow, - 'ZENITH_SIGNED_MESSAGE', + SIGNED_MESSAGE, { signature }, origin, ); @@ -63,7 +71,7 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { console.error('Signing failed:', err); sendMessage( sourceWindow!, - 'ZENITH_SIGNED_MESSAGE', + SIGNED_MESSAGE, { error: err }, origin, ); @@ -76,7 +84,7 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { if (sourceWindow && origin) { sendMessage( sourceWindow, - 'ZENITH_SIGNED_MESSAGE', + SIGNED_MESSAGE, { error: 'User rejected the request' }, origin, ); @@ -85,7 +93,7 @@ const SignRequestEmbed = ({ route }: SignRequestProps) => { useEffect(() => { const handleCosmosSignMessage = async (event: MessageEvent) => { - if (event.data.type !== 'SIGN_ZENITH_MESSAGE') return; + if (event.data.type !== SIGN_MESSAGE) return; if (!REACT_APP_ALLOWED_URLS) { diff --git a/src/screens/SignTxEmbed.tsx b/src/screens/SignTxEmbed.tsx index 71cae25..3d7153d 100644 --- a/src/screens/SignTxEmbed.tsx +++ b/src/screens/SignTxEmbed.tsx @@ -19,9 +19,7 @@ import { getPathKey, sendMessage } from '../utils/misc'; import { useNetworks } from '../context/NetworksContext'; import TxErrorDialog from '../components/TxErrorDialog'; import { Account, NetworksDataState } from '../types'; - -const GET_ACCOUNTS_RESPONSE = "GET_ACCOUNTS_RESPONSE"; -const SIGN_ONBOARD_TX_RESPONSE = "SIGN_ONBOARD_TX_RESPONSE"; +import { REQUEST_SIGN_TX, REQUEST_COSMOS_ACCOUNTS_DATA, COSMOS_ACCOUNTS_RESPONSE, SIGN_TX_RESPONSE } from '../utils/constants'; // Type Definitions @@ -39,7 +37,7 @@ type IncomingMessageData = SignOnboardTxRequestData | GetAccountsRequestData; interface IncomingMessageEventData { id: string; - type: 'SIGN_ONBOARD_TX_REQUEST' | 'GET_ACCOUNTS_REQUEST'; + type: typeof REQUEST_SIGN_TX | typeof REQUEST_COSMOS_ACCOUNTS_DATA; data: IncomingMessageData; } @@ -64,7 +62,7 @@ interface GetAccountsResponse { }>; } -export const SendTxEmbed = () => { +export const SignTxEmbed = () => { const [isTxApprovalVisible, setIsTxApprovalVisible] = useState(false); const [transactionDetails, setTransactionDetails] = useState(null); const [isTxLoading, setIsTxLoading] = useState(false); @@ -74,26 +72,27 @@ export const SendTxEmbed = () => { // Message Handlers - const handleGetAccountsRequest = useCallback(async (event: MessageEvent) => { + const handleGetCosmosAccountsRequest = useCallback(async (event: MessageEvent) => { const { id, data } = event.data; const source = event.source as Window; const origin = event.origin; const requestData = data as GetAccountsRequestData; - console.log("Received GET_ACCOUNTS_REQUEST", id); + console.log(`Received ${REQUEST_COSMOS_ACCOUNTS_DATA}`, id); try { const requestedNetworkData = networksData.find(networkData => networkData.chainId === requestData.chainId) if(!requestedNetworkData) { - throw new Error("Zenith network data not found") + throw new Error("Network data not found") } - // Ensure retrieveAccounts exists and returns Account[] - const allAccounts = await retrieveAccounts(requestedNetworkData); // Use retrieveAccounts + + const allAccounts = await retrieveAccounts(requestedNetworkData); if (!allAccounts || allAccounts.length === 0) { - throw new Error("Accounts not found for zenithNetwork") + throw new Error("Accounts not found for network") } + // TODO: Refactor getCosmosAccounts functions to return all accounts const responseAccounts = await Promise.all( allAccounts.map(async (acc) => { const cosmosAccount = await getCosmosAccount(acc.hdPath, requestedNetworkData.addressPrefix!); @@ -105,13 +104,13 @@ export const SendTxEmbed = () => { ); const response: GetAccountsResponse = { accounts: responseAccounts }; - sendMessage(source, GET_ACCOUNTS_RESPONSE, {id, data: response}, origin); + sendMessage(source, COSMOS_ACCOUNTS_RESPONSE, {id, data: response}, origin); } catch (error: unknown) { - console.error("Error handling GET_ACCOUNTS_REQUEST:", error); + console.error(`Error handling ${REQUEST_COSMOS_ACCOUNTS_DATA}:`, error); const errorMsg = error instanceof Error ? error.message : String(error); // Check if source is a Window before sending message if (source instanceof Window) { - sendMessage(source, GET_ACCOUNTS_RESPONSE, { id, error: `Failed to get accounts: ${errorMsg}` }, origin); + sendMessage(source, COSMOS_ACCOUNTS_RESPONSE, { id, error: `Failed to get accounts: ${errorMsg}` }, origin); } else { console.error("Cannot send error message: source is not a Window"); } @@ -124,7 +123,7 @@ export const SendTxEmbed = () => { const origin = event.origin; const requestData = data as SignOnboardTxRequestData; - console.log("Received SIGN_ONBOARD_TX_REQUEST", id); + console.log(`Received ${REQUEST_SIGN_TX}`, id); setIsTxApprovalVisible(false); setTransactionDetails(null); setTxError(null); @@ -171,7 +170,7 @@ export const SendTxEmbed = () => { setIsTxApprovalVisible(true); } catch (error: unknown) { - console.error("Error handling SIGN_ONBOARD_TX_REQUEST:", error); + console.error(`Error handling ${REQUEST_SIGN_TX}:`, error); const errorMsg = error instanceof Error ? error.message : String(error); sendMessage(source, id, { error: `Failed to prepare transaction: ${errorMsg}` }, origin); @@ -187,16 +186,16 @@ export const SendTxEmbed = () => { const messageData = event.data as IncomingMessageEventData; switch (messageData.type) { - case 'GET_ACCOUNTS_REQUEST': - handleGetAccountsRequest(event as MessageEvent); + case REQUEST_COSMOS_ACCOUNTS_DATA: + handleGetCosmosAccountsRequest(event as MessageEvent); break; - case 'SIGN_ONBOARD_TX_REQUEST': + case REQUEST_SIGN_TX: handleSignOnboardTxRequest(event as MessageEvent); break; default: console.warn(`Received unknown message type: ${messageData.type}`); } - }, [handleGetAccountsRequest, handleSignOnboardTxRequest]); + }, [handleGetCosmosAccountsRequest, handleSignOnboardTxRequest]); useEffect(() => { window.addEventListener('message', handleIncomingMessage); @@ -228,7 +227,7 @@ export const SendTxEmbed = () => { // Perform the actual signing const signResponse = await wallet.signDirect(signerAddress, signDoc); - sendMessage(source as Window, SIGN_ONBOARD_TX_RESPONSE, {id: requestId, data: signResponse}, origin); + sendMessage(source as Window, SIGN_TX_RESPONSE, {id: requestId, data: signResponse}, origin); console.log("Sent signDirect response:", requestId); setIsTxApprovalVisible(false); @@ -239,7 +238,7 @@ export const SendTxEmbed = () => { const errorMsg = error instanceof Error ? error.message : String(error); setTxError(errorMsg); - sendMessage(source as Window, SIGN_ONBOARD_TX_RESPONSE, {id: requestId, error: `Failed to sign transaction: ${errorMsg}` }, origin); + sendMessage(source as Window, SIGN_TX_RESPONSE, {id: requestId, error: `Failed to sign transaction: ${errorMsg}` }, origin); } finally { setIsTxLoading(false); } @@ -250,7 +249,7 @@ export const SendTxEmbed = () => { const { requestId, source, origin } = transactionDetails; console.log("Rejecting request:", requestId); - sendMessage(source as Window, SIGN_ONBOARD_TX_RESPONSE, {id: requestId, error: "User rejected the signature request." }, origin); + sendMessage(source as Window, SIGN_TX_RESPONSE, {id: requestId, error: "User rejected the signature request." }, origin); setIsTxApprovalVisible(false); setTransactionDetails(null); setTxError(null); diff --git a/src/screens/WalletEmbed.tsx b/src/screens/WalletEmbed.tsx index 301c421..8471140 100644 --- a/src/screens/WalletEmbed.tsx +++ b/src/screens/WalletEmbed.tsx @@ -26,6 +26,7 @@ import { MEMO } from '../screens/ApproveTransfer'; import { Account, NetworksDataState } from '../types'; import useGetOrCreateAccounts from '../hooks/useGetOrCreateAccounts'; import useAccountsData from '../hooks/useAccountsData'; +import { REQUEST_TX, REQUEST_WALLET_ACCOUNTS, TRANSACTION_RESPONSE, WALLET_ACCOUNTS_DATA } from '../utils/constants'; type TransactionDetails = { chainId: string; @@ -51,8 +52,7 @@ export const WalletEmbed = () => { useEffect(() => { const handleGetAccounts = async (event: MessageEvent) => { - // TODO: Keep event data types in constant file - if (event.data.type !== 'REQUEST_WALLET_ACCOUNTS') return; + if (event.data.type !== REQUEST_WALLET_ACCOUNTS) return; const accountsData = await getAccountsData(event.data.chainId); @@ -63,7 +63,7 @@ export const WalletEmbed = () => { sendMessage( event.source as Window, - 'WALLET_ACCOUNTS_DATA', + WALLET_ACCOUNTS_DATA, accountsData.map(account => account.address), event.origin ); @@ -82,7 +82,7 @@ export const WalletEmbed = () => { const handleTxRequested = useCallback( async (event: MessageEvent) => { try { - if (event.data.type !== 'REQUEST_TX') return; + if (event.data.type !== REQUEST_TX) return; txEventRef.current = event; @@ -208,7 +208,7 @@ export const WalletEmbed = () => { const event = txEventRef.current; if (event?.source) { - sendMessage(event.source as Window, 'TRANSACTION_RESPONSE', txResult.transactionHash, event.origin); + sendMessage(event.source as Window, TRANSACTION_RESPONSE, txResult.transactionHash, event.origin); } else { console.error('No event source available to send message'); } @@ -228,7 +228,7 @@ export const WalletEmbed = () => { setIsTxRequested(false); setTransactionDetails(null); if (event?.source) { - sendMessage(event.source as Window, 'TRANSACTION_RESPONSE', null, event.origin); + sendMessage(event.source as Window, TRANSACTION_RESPONSE, null, event.origin); } else { console.error('No event source available to send message'); } @@ -308,7 +308,7 @@ export const WalletEmbed = () => { hideDialog={() => { setTxError(null) if (window.parent) { - sendMessage(window.parent, 'TRANSACTION_RESPONSE', null, '*'); + sendMessage(window.parent, TRANSACTION_RESPONSE, null, '*'); sendMessage(window.parent, 'closeIframe', null, '*'); } }} diff --git a/src/types.ts b/src/types.ts index 6d34515..5c5317c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,7 +41,7 @@ export type StackParamsList = { "wallet-embed": undefined; "auto-sign-in": undefined; "sign-request-embed": undefined; - "send-tx-embed": undefined; + "sign-tx-embed": undefined; }; export type Account = { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 5549b7c..404dd53 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -74,3 +74,19 @@ export const INVALID_URL_ERROR = 'Invalid URL'; export const IS_NUMBER_REGEX = /^\d+$/; export const IS_IMPORT_WALLET_ENABLED = false; + +// iframe request types +export const REQUEST_COSMOS_ACCOUNTS_DATA = 'REQUEST_COSMOS_ACCOUNTS_DATA'; +export const REQUEST_SIGN_TX = 'REQUEST_SIGN_TX'; +export const SIGN_MESSAGE = 'SIGN_MESSAGE'; +export const REQUEST_WALLET_ACCOUNTS = 'REQUEST_WALLET_ACCOUNTS'; +export const REQUEST_TX = 'REQUEST_TX'; +export const AUTO_SIGN_IN = 'AUTO_SIGN_IN'; + +// iframe response types +export const COSMOS_ACCOUNTS_RESPONSE = 'COSMOS_ACCOUNTS_RESPONSE'; +export const SIGN_TX_RESPONSE = 'SIGN_TX_RESPONSE'; +export const SIGNED_MESSAGE = 'SIGNED_MESSAGE'; +export const WALLET_ACCOUNTS_DATA = 'WALLET_ACCOUNTS_DATA'; +export const TRANSACTION_RESPONSE = 'TRANSACTION_RESPONSE'; +export const SIGN_IN_RESPONSE = 'SIGN_IN_RESPONSE';