diff --git a/src/App.tsx b/src/App.tsx index 024d183..a14e2f7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,8 @@ import { TxBody, AuthInfo } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { SignClientTypes } from "@walletconnect/types"; import { useNavigation } from "@react-navigation/native"; +import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"; +import { SigningStargateClient } from "@cosmjs/stargate"; import { createStackNavigator, StackNavigationProp, @@ -36,6 +38,8 @@ import styles from "./styles/stylesheet"; import { Header } from "./components/Header"; import { WalletEmbed } from "./screens/WalletEmbed"; import { AutoSignIn } from "./screens/AutoSignIn"; +import { checkSufficientFunds, getPathKey, sendMessage } from "./utils/misc"; +import { retrieveSingleAccount } from "./utils/accounts"; const Stack = createStackNavigator(); @@ -219,6 +223,51 @@ const App = (): React.JSX.Element => { }; }); + useEffect(() => { + const handleCheckBalance = async (event: MessageEvent) => { + if (event.data.type !== 'CHECK_BALANCE') return; + + const { chainId, address, amount } = event.data; + const network = networksData.find(net => net.chainId === chainId); + + if (!network) { + console.error('Network not found'); + throw new Error('Requested network not supported.'); + } + + const account = await retrieveSingleAccount(network.namespace, network.chainId, address); + if (!account) { + throw new Error('Account not found for the requested address.'); + } + + const cosmosPrivKey = ( + await getPathKey(`${network.namespace}:${chainId}`, account.index) + ).privKey; + + const sender = await DirectSecp256k1Wallet.fromKey( + Buffer.from(cosmosPrivKey.split('0x')[1], 'hex'), + network.addressPrefix + ); + + const client = await SigningStargateClient.connectWithSigner(network.rpcUrl!, sender); + + const balance = await client.getBalance( + account.address, + network.nativeDenom!.toLowerCase() + ); + + const areFundsSufficient = !checkSufficientFunds(amount, balance.amount); + + sendMessage(event.source as Window, 'IS_SUFFICIENT', areFundsSufficient, event.origin); + }; + + window.addEventListener('message', handleCheckBalance); + + return () => { + window.removeEventListener('message', handleCheckBalance); + }; + }, [networksData]); + const showWalletConnect = useMemo(() => accounts.length > 0, [accounts]); return ( diff --git a/src/screens/WalletEmbed.tsx b/src/screens/WalletEmbed.tsx index dd0a47f..df4da33 100644 --- a/src/screens/WalletEmbed.tsx +++ b/src/screens/WalletEmbed.tsx @@ -19,7 +19,7 @@ import { createWallet, retrieveAccounts, retrieveSingleAccount } from '../utils/ import AccountDetails from '../components/AccountDetails'; import styles from '../styles/stylesheet'; import DataBox from '../components/DataBox'; -import { getPathKey } from '../utils/misc'; +import { checkSufficientFunds, getPathKey, sendMessage } from '../utils/misc'; import { useNetworks } from '../context/NetworksContext'; import TxErrorDialog from '../components/TxErrorDialog'; import { MEMO } from '../screens/ApproveTransfer'; @@ -62,22 +62,6 @@ export const WalletEmbed = () => { return accounts.map(account => account.address); }, [networksData]); - const sendMessage = ( - source: Window | null, - type: string, - data: any, - origin: string - ): void => { - source?.postMessage({ type, data }, origin); - }; - - const checkSufficientFunds = (amount: string, balance: string) => { - const amountBigNum = BigNumber.from(String(amount)); - const balanceBigNum = BigNumber.from(balance); - - return balanceBigNum.gt(amountBigNum); - }; - useEffect(() => { const handleGetAccounts = async (event: MessageEvent) => { if (event.data.type !== 'REQUEST_WALLET_ACCOUNTS') return; @@ -184,7 +168,8 @@ export const WalletEmbed = () => { }); if (!checkSufficientFunds(amount, balance.amount)) { - console.log("Insufficient funds detected. Throwing error."); + console.log("Insufficient funds detected"); + sendMessage(event.source as Window, 'INSUFFICIENT_FUNDS', null, event.origin); throw new Error('Insufficient funds'); } @@ -342,7 +327,7 @@ export const WalletEmbed = () => { ) : ( - + )} diff --git a/src/utils/misc.ts b/src/utils/misc.ts index 5306b84..afbd824 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -1,7 +1,11 @@ /* Importing this library provides react native with a secure random source. For more information, "visit https://docs.ethers.org/v5/cookbook/react-native/#cookbook-reactnative-security" */ import 'react-native-get-random-values'; +import { BigNumber } from 'ethers'; +import { AccountData } from '@cosmjs/amino'; +import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; +import { stringToPath } from '@cosmjs/crypto'; import '@ethersproject/shims'; import { @@ -9,10 +13,6 @@ import { resetInternetCredentials, setInternetCredentials, } from './key-store'; - -import { AccountData } from '@cosmjs/amino'; -import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; -import { stringToPath } from '@cosmjs/crypto'; import { EIP155 } from './constants'; import { NetworksDataState } from '../types'; @@ -149,10 +149,28 @@ const resetKeyServers = async (namespace: string) => { }); }; +const sendMessage = ( + source: Window | null, + type: string, + data: any, + origin: string +): void => { + source?.postMessage({ type, data }, origin); +}; + +const checkSufficientFunds = (amount: string, balance: string) => { + const amountBigNum = BigNumber.from(String(amount)); + const balanceBigNum = BigNumber.from(balance); + + return balanceBigNum.gt(amountBigNum); +}; + export { getMnemonic, getPathKey, updateAccountIndices, getHDPath, resetKeyServers, + sendMessage, + checkSufficientFunds, };