diff --git a/explorer/src/components/ConnectKeplrWallet.tsx b/explorer/src/components/ConnectKeplrWallet.tsx index 4fab8b8712..766f96059a 100644 --- a/explorer/src/components/ConnectKeplrWallet.tsx +++ b/explorer/src/components/ConnectKeplrWallet.tsx @@ -39,8 +39,17 @@ export const trimAddress = (address = '', trimBy = 6) => { }; export default function ConnectKeplrWallet() { - const { username, connect, disconnect, wallet, openView, address, getCosmWasmClient, isWalletConnected } = - useChain('nyx'); + const { + username, + connect, + disconnect, + wallet, + openView, + address, + getCosmWasmClient, + isWalletConnected, + isWalletConnecting, + } = useChain('nyx'); const isClient = useIsClient(); const theme = useTheme(); @@ -70,9 +79,9 @@ export default function ConnectKeplrWallet() { if (!isClient) return null; const getGlobalbutton = () => { - // if (globalStatus === 'Connecting') { - // return ; - // } + if (isWalletConnecting) { + return ; + } if (isWalletConnected) { return ( diff --git a/explorer/src/components/Delegations/components/ConfirmTX.tsx b/explorer/src/components/Delegations/components/ConfirmTX.tsx new file mode 100644 index 0000000000..e62a86a23c --- /dev/null +++ b/explorer/src/components/Delegations/components/ConfirmTX.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { FeeDetails } from '@nymproject/types'; +import { Box } from '@mui/material'; +import { useTheme, Theme } from '@mui/material/styles'; +import { SimpleModal } from './SimpleModal'; +import { ModalFee } from './ModalFee'; +import { ModalDivider } from './ModalDivider'; +import { backDropStyles, modalStyles } from './styles'; + +const storybookStyles = (theme: Theme, isStorybook?: boolean, backdropProps?: object) => + isStorybook + ? { + backdropProps: { ...backDropStyles(theme), ...backdropProps }, + sx: modalStyles(theme), + } + : {}; + +export const ConfirmTx: FCWithChildren<{ + open: boolean; + header: string; + subheader?: string; + fee: FeeDetails; + onConfirm: () => Promise; + onClose?: () => void; + onPrev: () => void; + isStorybook?: boolean; + children?: React.ReactNode; +}> = ({ open, fee, onConfirm, onClose, header, subheader, onPrev, children, isStorybook }) => { + const theme = useTheme(); + return ( + + + {children} + + + + + ); +}; diff --git a/explorer/src/components/Delegations/ConfirmationModal.tsx b/explorer/src/components/Delegations/components/ConfirmationModal.tsx similarity index 100% rename from explorer/src/components/Delegations/ConfirmationModal.tsx rename to explorer/src/components/Delegations/components/ConfirmationModal.tsx diff --git a/explorer/src/components/Delegations/DelegateModal.tsx b/explorer/src/components/Delegations/components/DelegateModal.tsx similarity index 61% rename from explorer/src/components/Delegations/DelegateModal.tsx rename to explorer/src/components/Delegations/components/DelegateModal.tsx index 50b7276aa5..8f36deda0e 100644 --- a/explorer/src/components/Delegations/DelegateModal.tsx +++ b/explorer/src/components/Delegations/components/DelegateModal.tsx @@ -1,24 +1,22 @@ -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useContext, useState, useEffect } from 'react'; import { Box, Typography, SxProps } from '@mui/material'; import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'; import { CurrencyDenom, FeeDetails, DecCoin, decimalToFloatApproximation } from '@nymproject/types'; -// import { Console } from 'src/utils/console'; -// import { useGetFee } from 'src/hooks/useGetFee'; -// import { simulateDelegateToMixnode, simulateVestingDelegateToMixnode, tryConvertIdentityToMixId } from 'src/requests'; +import { Console } from '../utils/console'; +import { useGetFee } from '../hooks/useGetFee'; import { debounce } from 'lodash'; import { SimpleModal } from './SimpleModal'; import { ModalListItem } from './ModalListItem'; -// import { AppContext } from 'src/context'; -// import { SimpleModal } from '../Modals/SimpleModal'; -// import { ModalListItem } from '../Modals/ModalListItem'; -// import { checkTokenBalance, validateAmount, validateKey } from '../../utils'; -// import { TokenPoolSelector, TPoolOption } from '../TokenPoolSelector'; -// import { ConfirmTx } from '../ConfirmTX'; -// import { getMixnodeStakeSaturation } from '../../requests'; -// import { ErrorModal } from '../Modals/ErrorModal'; -// import { BalanceWarning } from '../FeeWarning'; +import { TPoolOption, checkTokenBalance, validateAmount, validateKey } from '../utils'; + +import { useChain } from '@cosmos-kit/react'; +import { uNYMtoNYM } from '../utils'; +import { ErrorModal } from './ErrorModal'; +import { ConfirmTx } from './ConfirmTX'; +import { BalanceWarning } from './FeeWarning'; +import { getMixnodeStakeSaturation, simulateDelegateToMixnode, tryConvertIdentityToMixId } from '../requests'; const MIN_AMOUNT_TO_DELEGATE = 10; @@ -29,8 +27,8 @@ export const DelegateModal: FCWithChildren<{ mixId: number, identityKey: string, amount: DecCoin, - // tokenPool: TPoolOption, - // fee?: FeeDetails, + tokenPool: TPoolOption, + fee?: FeeDetails, ) => Promise; identityKey?: string; onIdentityKeyChanged?: (identityKey: string) => void; @@ -38,7 +36,7 @@ export const DelegateModal: FCWithChildren<{ header?: string; buttonText?: string; rewardInterval: string; - accountBalance?: string; + // accountBalance?: string; estimatedReward?: number; profitMarginPercentage?: string | null; nodeUptimePercentage?: number | null; @@ -57,7 +55,7 @@ export const DelegateModal: FCWithChildren<{ buttonText, identityKey: initialIdentityKey, rewardInterval, - accountBalance, + // accountBalance, estimatedReward, denom, profitMarginPercentage, @@ -76,47 +74,45 @@ export const DelegateModal: FCWithChildren<{ const [errorIdentityKey, setErrorIdentityKey] = useState(); const [mixIdError, setMixIdError] = useState(); - // const { fee, getFee, resetFeeState, feeError } = useGetFee(); - // const { userBalance } = useContext(AppContext); + const { fee, getFee, resetFeeState, feeError } = useGetFee(); - // const handleCheckStakeSaturation = async (newMixId: number) => { - // try { - // const newSaturation = decimalToFloatApproximation( - // (await getMixnodeStakeSaturation(newMixId)).uncapped_saturation, - // ); - // if (newSaturation && newSaturation > 1) { - // const saturationPercentage = Math.round(newSaturation * 100); - // return { isOverSaturated: true, saturationPercentage }; - // } - // return { isOverSaturated: false, saturationPercentage: undefined }; - // } catch (e) { - // Console.error('Error fetching the saturation, error:', e); - // return { isOverSaturated: false, saturationPercentage: undefined }; - // } - // }; + const { username, connect, disconnect, wallet, openView, address, getCosmWasmClient, isWalletConnected } = + useChain('nyx'); + const [balance, setBalance] = useState<{ + status: 'loading' | 'success'; + data?: string; + }>({ status: 'loading', data: undefined }); + + useEffect(() => { + const getBalance = async (walletAddress: string) => { + setBalance({ status: 'loading', data: undefined }); + + const account = await getCosmWasmClient(); + const uNYMBalance = await account.getBalance(walletAddress, 'unym'); + const NYMBalance = uNYMtoNYM(uNYMBalance.amount).asString(); + + setBalance({ status: 'success', data: NYMBalance }); + }; + + if (address) { + getBalance(address); + } + }, [address, getCosmWasmClient]); const validate = async () => { let newValidatedValue = true; let errorAmountMessage; let errorIdentityKeyMessage; - // if (!identityKey || !validateKey(identityKey, 32)) { - // newValidatedValue = false; - // errorIdentityKeyMessage = undefined; - // } + if (!identityKey) { + newValidatedValue = false; + errorIdentityKeyMessage = 'Please enter a valid identity key'; + } - // if (identityKey && mixId && validateKey(identityKey, 32)) { - // const { isOverSaturated, saturationPercentage } = await handleCheckStakeSaturation(mixId); - // if (isOverSaturated) { - // newValidatedValue = false; - // errorIdentityKeyMessage = `This node is over saturated (${saturationPercentage}%), please select another node`; - // } - // } - - // if (amount && !(await validateAmount(amount, '0'))) { - // newValidatedValue = false; - // errorAmountMessage = 'Please enter a valid amount'; - // } + if (amount && !(await validateAmount(amount, '0'))) { + newValidatedValue = false; + errorAmountMessage = 'Please enter a valid amount'; + } if (amount && Number(amount) < MIN_AMOUNT_TO_DELEGATE) { errorAmountMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${denom.toUpperCase()}`; @@ -127,9 +123,9 @@ export const DelegateModal: FCWithChildren<{ newValidatedValue = false; } - if (!mixId) { - newValidatedValue = false; - } + // if (!mixId) { + // newValidatedValue = false; + // } setErrorIdentityKey(errorIdentityKeyMessage); if (mixIdError && !errorIdentityKeyMessage) { @@ -141,21 +137,22 @@ export const DelegateModal: FCWithChildren<{ const handleOk = async () => { if (onOk && amount && identityKey && mixId) { - onOk(mixId, identityKey, { amount, denom }); //tokenPool, fee); + onOk(mixId, identityKey, { amount, denom }, 'balance', fee); } }; const handleConfirm = async ({ mixId: id, value }: { mixId: number; value: DecCoin }) => { - const hasEnoughTokens = true; // await checkTokenBalance(tokenPool, value.amount); + const tokenPool = 'balance'; + const hasEnoughTokens = checkTokenBalance(tokenPool, value.amount, balance.data || '0'); if (!hasEnoughTokens) { setErrorAmount('Not enough funds'); return; } - // if (tokenPool === 'balance') { - // getFee(simulateDelegateToMixnode, { mixId: id, amount: value }); - // } + if (tokenPool === 'balance') { + getFee(simulateDelegateToMixnode, { mixId: id, amount: value }); + } // if (tokenPool === 'locked') { // getFee(simulateVestingDelegateToMixnode, { mixId: id, amount: value }); @@ -184,15 +181,14 @@ export const DelegateModal: FCWithChildren<{ const resolveMixId = useCallback( debounce(async (idKey) => { - if (!idKey) { - //|| !validateKey(idKey, 32)) + if (!idKey || !validateKey(idKey, 32)) { return; } let res; try { - // res = await tryConvertIdentityToMixId(idKey); + res = await tryConvertIdentityToMixId(idKey); } catch (e) { - // Console.warn(`failed to resolve mix_id for "${idKey}": ${e}`); + Console.warn(`failed to resolve mix_id for "${idKey}": ${e}`); return; } if (res) { @@ -209,38 +205,38 @@ export const DelegateModal: FCWithChildren<{ resolveMixId(identityKey); }, [identityKey]); - // if (fee) { - // return ( - // - // {userBalance.balance?.amount.amount && fee?.amount?.amount && ( - // - // - // - // )} - // - // - // - // ); - // } + if (fee) { + return ( + + {balance.data && fee?.amount?.amount && ( + + + + )} + + + + ); + } - // if (feeError) { - // return ( - // - // ); - // } + if (feeError) { + return ( + + ); + } return ( - +