From 081fec72e52dce54f08e06ceb8d34e68f33f40a1 Mon Sep 17 00:00:00 2001 From: Yana Date: Tue, 7 Nov 2023 13:02:00 +0000 Subject: [PATCH] Connect delegate modal to keplr balance WIP WIP WIP WIP --- .../src/components/ConnectKeplrWallet.tsx | 19 +- .../Delegations/components/ConfirmTX.tsx | 48 +++ .../{ => components}/ConfirmationModal.tsx | 0 .../{ => components}/DelegateModal.tsx | 184 +++++---- .../{ => components}/ErrorModal.tsx | 2 +- .../Delegations/components/FeeWarning.tsx | 35 ++ .../Delegations/components/ModalDivider.tsx | 6 + .../Delegations/components/ModalFee.tsx | 35 ++ .../{ => components}/ModalListItem.tsx | 2 +- .../{ => components}/SimpleModal.tsx | 2 +- .../Delegations/components/styles.ts | 21 + explorer/src/components/Delegations/config.ts | 4 + .../Delegations/context/accounts.tsx | 170 ++++++++ .../components/Delegations/context/buy.tsx | 59 +++ .../components/Delegations/context/index.tsx | 3 + .../components/Delegations/context/main.tsx | 366 ++++++++++++++++++ .../Delegations/hooks/useCheckOwnership.ts | 59 +++ .../Delegations/hooks/useGetBalance.ts | 147 +++++++ .../components/Delegations/hooks/useGetFee.ts | 49 +++ .../Delegations/hooks/useKeyPress.ts | 29 ++ .../Delegations/requests/account.ts | 67 ++++ .../Delegations/requests/actions.ts | 54 +++ .../components/Delegations/requests/app.ts | 14 + .../Delegations/requests/contract.ts | 7 + .../Delegations/requests/delegation.ts | 33 ++ .../components/Delegations/requests/index.ts | 14 + .../Delegations/requests/logging.ts | 3 + .../Delegations/requests/network.ts | 16 + .../Delegations/requests/pendingEvents.ts | 4 + .../Delegations/requests/queries.ts | 63 +++ .../Delegations/requests/rewards.ts | 14 + .../Delegations/requests/signature.ts | 9 + .../Delegations/requests/simulate.ts | 87 +++++ .../components/Delegations/requests/utils.ts | 11 + .../Delegations/requests/vesting.ts | 125 ++++++ .../Delegations/requests/wrapper.ts | 20 + .../components/Delegations/types/global.ts | 97 +++++ .../src/components/Delegations/types/index.ts | 7 + .../Delegations/types/rust/AppEnv.ts | 5 + .../Delegations/types/rust/AppVersion.ts | 7 + .../Delegations/types/rust/Epoch.ts | 8 + .../Delegations/types/rust/Interval.ts | 8 + .../Delegations/types/rust/Network.ts | 3 + .../Delegations/types/rust/StateParams.ts | 8 + .../Delegations/types/rust/ValidatorUrl.ts | 6 + .../Delegations/types/rust/ValidatorUrls.ts | 6 + .../components/Delegations/typings/FC.d.ts | 1 + .../components/Delegations/typings/jpeg.d.ts | 9 + .../components/Delegations/typings/json.d.ts | 4 + .../components/Delegations/typings/png.d.ts | 4 + .../components/Delegations/typings/svg.d.ts | 4 + .../components/Delegations/utils/common.ts | 255 ++++++++++++ .../components/Delegations/utils/console.ts | 10 + .../Delegations/utils/fireRequests.ts | 22 ++ .../src/components/Delegations/utils/index.ts | 4 + .../src/components/Delegations/utils/sleep.ts | 3 + explorer/src/components/TableToolbar.tsx | 67 +++- 57 files changed, 2202 insertions(+), 117 deletions(-) create mode 100644 explorer/src/components/Delegations/components/ConfirmTX.tsx rename explorer/src/components/Delegations/{ => components}/ConfirmationModal.tsx (100%) rename explorer/src/components/Delegations/{ => components}/DelegateModal.tsx (61%) rename explorer/src/components/Delegations/{ => components}/ErrorModal.tsx (91%) create mode 100644 explorer/src/components/Delegations/components/FeeWarning.tsx create mode 100644 explorer/src/components/Delegations/components/ModalDivider.tsx create mode 100644 explorer/src/components/Delegations/components/ModalFee.tsx rename explorer/src/components/Delegations/{ => components}/ModalListItem.tsx (91%) rename explorer/src/components/Delegations/{ => components}/SimpleModal.tsx (97%) create mode 100644 explorer/src/components/Delegations/components/styles.ts create mode 100644 explorer/src/components/Delegations/config.ts create mode 100644 explorer/src/components/Delegations/context/accounts.tsx create mode 100644 explorer/src/components/Delegations/context/buy.tsx create mode 100644 explorer/src/components/Delegations/context/index.tsx create mode 100644 explorer/src/components/Delegations/context/main.tsx create mode 100644 explorer/src/components/Delegations/hooks/useCheckOwnership.ts create mode 100644 explorer/src/components/Delegations/hooks/useGetBalance.ts create mode 100644 explorer/src/components/Delegations/hooks/useGetFee.ts create mode 100644 explorer/src/components/Delegations/hooks/useKeyPress.ts create mode 100644 explorer/src/components/Delegations/requests/account.ts create mode 100644 explorer/src/components/Delegations/requests/actions.ts create mode 100644 explorer/src/components/Delegations/requests/app.ts create mode 100644 explorer/src/components/Delegations/requests/contract.ts create mode 100644 explorer/src/components/Delegations/requests/delegation.ts create mode 100644 explorer/src/components/Delegations/requests/index.ts create mode 100644 explorer/src/components/Delegations/requests/logging.ts create mode 100644 explorer/src/components/Delegations/requests/network.ts create mode 100644 explorer/src/components/Delegations/requests/pendingEvents.ts create mode 100644 explorer/src/components/Delegations/requests/queries.ts create mode 100644 explorer/src/components/Delegations/requests/rewards.ts create mode 100644 explorer/src/components/Delegations/requests/signature.ts create mode 100644 explorer/src/components/Delegations/requests/simulate.ts create mode 100644 explorer/src/components/Delegations/requests/utils.ts create mode 100644 explorer/src/components/Delegations/requests/vesting.ts create mode 100644 explorer/src/components/Delegations/requests/wrapper.ts create mode 100644 explorer/src/components/Delegations/types/global.ts create mode 100644 explorer/src/components/Delegations/types/index.ts create mode 100644 explorer/src/components/Delegations/types/rust/AppEnv.ts create mode 100644 explorer/src/components/Delegations/types/rust/AppVersion.ts create mode 100644 explorer/src/components/Delegations/types/rust/Epoch.ts create mode 100644 explorer/src/components/Delegations/types/rust/Interval.ts create mode 100644 explorer/src/components/Delegations/types/rust/Network.ts create mode 100644 explorer/src/components/Delegations/types/rust/StateParams.ts create mode 100644 explorer/src/components/Delegations/types/rust/ValidatorUrl.ts create mode 100644 explorer/src/components/Delegations/types/rust/ValidatorUrls.ts create mode 100644 explorer/src/components/Delegations/typings/FC.d.ts create mode 100644 explorer/src/components/Delegations/typings/jpeg.d.ts create mode 100644 explorer/src/components/Delegations/typings/json.d.ts create mode 100644 explorer/src/components/Delegations/typings/png.d.ts create mode 100644 explorer/src/components/Delegations/typings/svg.d.ts create mode 100644 explorer/src/components/Delegations/utils/common.ts create mode 100644 explorer/src/components/Delegations/utils/console.ts create mode 100644 explorer/src/components/Delegations/utils/fireRequests.ts create mode 100644 explorer/src/components/Delegations/utils/index.ts create mode 100644 explorer/src/components/Delegations/utils/sleep.ts 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 ( - +