Add confirmation models

This commit is contained in:
Yana
2023-11-15 15:53:37 +00:00
parent abbcfbb6c2
commit 8ca7c48094
5 changed files with 183 additions and 126 deletions
@@ -1,29 +1,25 @@
import React, { useCallback, useContext, useState, useEffect, ChangeEvent } from 'react';
import React, { useState, useEffect, ChangeEvent } from 'react';
import { Box, Typography, SxProps, TextField } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { CurrencyDenom, FeeDetails, DecCoin, decimalToFloatApproximation, Coin } from '@nymproject/types';
import { CurrencyDenom, DecCoin } from '@nymproject/types';
import { SimpleModal } from './SimpleModal';
import { ModalListItem } from './ModalListItem';
import { TPoolOption, validateAmount } from '../utils';
import { Console, urls, validateAmount } from '../utils';
import { useChain } from '@cosmos-kit/react';
import { StdFee } from '@cosmjs/amino';
import { ExecuteResult } from '@cosmjs/cosmwasm-stargate';
import { uNYMtoNYM } from '../utils';
import { ErrorModal } from './ErrorModal';
import { DelegationModalProps } from './DelegationModal';
const MIN_AMOUNT_TO_DELEGATE = 10;
const MIXNET_CONTRACT_ADDRESS = 'n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr';
const sandboxContractAddress = 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav';
// const sandboxContractAddress = 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav';
export const DelegateModal: FCWithChildren<{
open: boolean;
onClose: () => void;
onOk?: () => void;
onOk?: (delegationModalProps: DelegationModalProps) => void;
identityKey?: string;
onIdentityKeyChanged?: (identityKey: string) => void;
onAmountChanged?: (amount: string) => void;
@@ -61,8 +57,10 @@ export const DelegateModal: FCWithChildren<{
const [errorIdentityKey, setErrorIdentityKey] = useState<string>();
const [mixIdError, setMixIdError] = useState<string>();
const [cosmWasmSignerClient, setCosmWasmSignerClient] = useState<any>();
// const { fee, getFee, resetFeeState, feeError } = useGetFee();
const [balance, setBalance] = useState<{
status: 'loading' | 'success';
data?: string;
}>({ status: 'loading', data: undefined });
const {
username,
@@ -77,11 +75,6 @@ export const DelegateModal: FCWithChildren<{
estimateFee,
} = useChain('nyx');
const [balance, setBalance] = useState<{
status: 'loading' | 'success';
data?: string;
}>({ status: 'loading', data: undefined });
useEffect(() => {
const getClient = async () => {
await getSigningCosmWasmClient()
@@ -95,15 +88,14 @@ export const DelegateModal: FCWithChildren<{
isWalletConnected && getClient();
}, [isWalletConnected]);
const getBalance = async (walletAddress: string) => {
const account = await getCosmWasmClient();
const uNYMBalance = await account.getBalance(walletAddress, 'unym');
const NYMBalance = uNYMtoNYM(uNYMBalance.amount).asString();
setBalance({ status: 'success', data: NYMBalance });
};
useEffect(() => {
const getBalance = async (walletAddress: string) => {
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);
}
@@ -182,14 +174,32 @@ export const DelegateModal: FCWithChildren<{
const fee = { gas: '1000000', amount: [{ amount: '25000', denom: 'unym' }] };
if (mixId && amount && onOk && cosmWasmSignerClient) {
console.log('trying to delegate :>> ');
console.log('balance.data :>> ', balance.data);
onOk();
console.log('amount :>> ', amount);
console.log('fee :>> ', fee);
await delegateToMixnode({ mixId }, fee, memo, [amount])
.then((res) => console.log('res :>> ', res))
.catch((err) => console.log('err :>> ', err));
onOk({
status: 'loading',
action: 'delegate',
});
try {
await delegateToMixnode({ mixId }, fee, memo, [amount]).then((res) => {
console.log('res :>> ', res);
});
const tx = await delegateToMixnode({ mixId }, fee, memo, [amount]);
onOk({
status: 'success',
action: 'delegate',
message: 'This operation can take up to one hour to process',
transactions: [
{ url: `${urls('MAINNET').blockExplorer}/transaction/${tx.transactionHash}`, hash: tx.transactionHash },
],
});
} catch (e) {
Console.error('Failed to addDelegation', e);
onOk({
status: 'error',
action: 'delegate',
message: (e as Error).message,
});
}
}
};
@@ -218,39 +228,6 @@ export const DelegateModal: FCWithChildren<{
validate();
}, [amount, identityKey, mixId]);
// if (fee) {
// return (
// <ConfirmTx
// open
// header="Delegation details"
// fee={fee}
// onClose={onClose}
// onPrev={resetFeeState}
// onConfirm={handleOk}
// >
// {balance.data && fee?.amount?.amount && (
// <Box sx={{ my: 2 }}>
// <BalanceWarning fee={fee?.amount?.amount} tx={amount} />
// </Box>
// )}
// <ModalListItem label="Node identity key" value={identityKey} divider />
// <ModalListItem label="Amount" value={`${amount} ${denom.toUpperCase()}`} divider />
// </ConfirmTx>
// );
// }
// if (feeError) {
// return (
// <ErrorModal
// title="Something went wrong while calculating fee. Are you sure you entered a valid node address?"
// message={feeError}
// sx={sx}
// open={open}
// onClose={onClose}
// />
// );
// }
return (
<SimpleModal
open={open}
@@ -316,26 +293,6 @@ export const DelegateModal: FCWithChildren<{
<ModalListItem label="Account balance" value={`${balance.data} NYM`} divider fontWeight={600} />
</Box>
{/* <ModalListItem label="Rewards payout interval" value={rewardInterval} hidden divider /> */}
{/* <ModalListItem
label="Node profit margin"
value={`${profitMarginPercentage ? `${profitMarginPercentage}%` : '-'}`}
hidden={profitMarginPercentage === undefined}
divider
/>
<ModalListItem
label="Node avg. uptime"
value={`${nodeUptimePercentage ? `${nodeUptimePercentage}%` : '-'}`}
hidden={nodeUptimePercentage === undefined}
divider
/> */}
{/* <ModalListItem
label="Node est. reward per epoch"
value={`${estimatedReward} ${denom.toUpperCase()}`}
hidden
divider
/> */}
<ModalListItem label="Est. fee for this transaction will be calculated in the next page" />
</SimpleModal>
);
@@ -0,0 +1,80 @@
import React from 'react';
import { Typography, SxProps, Stack } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
import { LoadingModal } from './LoadingModal';
import { ConfirmationModal } from './ConfirmationModal';
import { ErrorModal } from './ErrorModal';
export type ActionType = 'delegate' | 'undelegate' | 'redeem' | 'redeem-all' | 'compound';
const actionToHeader = (action: ActionType): string => {
// eslint-disable-next-line default-case
switch (action) {
case 'redeem':
return 'Rewards redeemed successfully';
case 'redeem-all':
return 'All rewards redeemed successfully';
case 'delegate':
return 'Delegation successful';
case 'undelegate':
return 'Undelegation successful';
case 'compound':
return 'Rewards compounded successfully';
default:
throw new Error('Unknown type');
}
};
export type DelegationModalProps = {
status: 'loading' | 'success' | 'error';
action: ActionType;
message?: string;
transactions?: {
url: string;
hash: string;
}[];
};
export const DelegationModal: FCWithChildren<
DelegationModalProps & {
open: boolean;
onClose: () => void;
sx?: SxProps;
backdropProps?: object;
children?: React.ReactNode;
}
> = ({ status, action, message, transactions, open, onClose, children, sx, backdropProps }) => {
if (status === 'loading') return <LoadingModal sx={sx} backdropProps={backdropProps} />;
if (status === 'error') {
return (
<ErrorModal message={message} sx={sx} open={open} onClose={onClose}>
{children}
</ErrorModal>
);
}
return (
<ConfirmationModal
open={open}
onConfirm={onClose || (() => {})}
title={actionToHeader(action)}
confirmButton="Done"
>
<Stack alignItems="center" spacing={2} mb={0}>
{message && <Typography>{message}</Typography>}
{transactions?.length === 1 && (
<Link href={transactions[0].url} target="_blank" sx={{ ml: 1 }} text="View on blockchain" noIcon />
)}
{transactions && transactions.length > 1 && (
<Stack alignItems="center" spacing={1}>
<Typography>View the transactions on blockchain:</Typography>
{transactions.map(({ url, hash }) => (
<Link href={url} target="_blank" sx={{ ml: 1 }} text={hash.slice(0, 6)} key={hash} noIcon />
))}
</Stack>
)}
</Stack>
</ConfirmationModal>
);
};
@@ -0,0 +1,29 @@
import React from 'react';
import { Box, CircularProgress, Modal, Stack, Typography, SxProps } from '@mui/material';
const modalStyle: SxProps = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
bgcolor: 'background.paper',
boxShadow: 24,
borderRadius: '16px',
p: 4,
};
export const LoadingModal: FCWithChildren<{
text?: string;
sx?: SxProps;
backdropProps?: object;
}> = ({ sx, backdropProps, text = 'Please wait...' }) => (
<Modal open BackdropProps={backdropProps}>
<Box sx={{ border: (t) => `1px solid grey`, ...modalStyle, ...sx }} textAlign="center">
<Stack spacing={4} direction="row" alignItems="center">
<CircularProgress />
<Typography sx={{ color: 'text.primary' }}>{text}</Typography>
</Stack>
</Box>
</Modal>
);
@@ -6,6 +6,7 @@ import { add, format, fromUnixTime } from 'date-fns';
import { DecCoin, isValidRawCoin, MixNodeCostParams } from '@nymproject/types';
import { getCurrentInterval, getDefaultMixnodeCostParams, getLockedCoins, getSpendableCoins } from '../requests';
import { Console } from './console';
import { Network } from '../types';
export type TPoolOption = 'balance' | 'locked';
@@ -253,3 +254,15 @@ export const getIntervalAsDate = async () => {
return { nextEpoch, nextInterval };
};
export const urls = (networkName?: Network) =>
networkName === 'MAINNET'
? {
mixnetExplorer: 'https://mixnet.explorers.guru/',
blockExplorer: 'https://blocks.nymtech.net',
networkExplorer: 'https://explorer.nymtech.net',
}
: {
blockExplorer: `https://${networkName}-blocks.nymtech.net`,
networkExplorer: `https://${networkName}-explorer.nymtech.net`,
};
+18 -40
View File
@@ -7,7 +7,7 @@ import { DelegateModal } from './Delegations/components/DelegateModal';
import { ChainProvider } from '@cosmos-kit/react';
import { assets, chains } from 'chain-registry';
import { wallets as keplr } from '@cosmos-kit/keplr';
import { CurrencyDenom, FeeDetails, DecCoin, decimalToFloatApproximation, Coin } from '@nymproject/types';
import { DelegationModal } from './Delegations/components/DelegationModal';
const fieldsHeight = '42.25px';
@@ -45,9 +45,9 @@ export const TableToolbar: FCWithChildren<TableToolBarProps> = ({
const [confirmationModalProps, setConfirmationModalProps] = useState<DelegationModalProps | undefined>();
const assetsFixedUp = useMemo(() => {
const nyx = assets.find((a) => a.chain_name === 'sandbox');
const nyx = assets.find((a) => a.chain_name === 'nyx');
if (nyx) {
const nyxCoin = nyx.assets.find((a) => a.name === 'sandbox');
const nyxCoin = nyx.assets.find((a) => a.name === 'nyx');
if (nyxCoin) {
nyxCoin.coingecko_id = 'nyx';
}
@@ -72,42 +72,10 @@ export const TableToolbar: FCWithChildren<TableToolBarProps> = ({
return chains;
}, [chains]);
const handleNewDelegation = () => {
// setConfirmationModalProps({
// status: 'loading',
// action: 'delegate',
// });
const handleNewDelegation = (delegationModalProps: DelegationModalProps) => {
setShowNewDelegationModal(false);
// setCurrentDelegationListActionItem(undefined);
// try {
// const tx = await addDelegation(
// {
// mix_id,
// amount,
// },
// tokenPool,
// fee,
// );
// const balances = await getAllBalances();
// setConfirmationModalProps({
// status: 'success',
// action: 'delegate',
// message: 'This operation can take up to one hour to process',
// ...balances,
// transactions: [
// { url: `${urls(network).blockExplorer}/transaction/${tx.transaction_hash}`, hash: tx.transaction_hash },
// ],
// });
// } catch (e) {
// Console.error('Failed to addDelegation', e);
// setConfirmationModalProps({
// status: 'error',
// action: 'delegate',
// message: (e as Error).message,
// });
// }
console.log('res In Toolbar:>> ', delegationModalProps);
setConfirmationModalProps(delegationModalProps);
};
const isMobile = useIsMobile();
@@ -200,12 +168,22 @@ export const TableToolbar: FCWithChildren<TableToolBarProps> = ({
header="Delegate"
buttonText="Delegate stake"
denom={'nym'} // clientDetails?.display_mix_denom || 'nym'}
onOk={handleNewDelegation}
onOk={(delegationModalProps: DelegationModalProps) => handleNewDelegation(delegationModalProps)}
// accountBalance={balance?.printable_balance}
{...confirmationModalProps}
/>
</ChainProvider>
)}
{confirmationModalProps && (
<DelegationModal
{...confirmationModalProps}
open={Boolean(confirmationModalProps)}
onClose={async () => {
setConfirmationModalProps(undefined);
// await fetchBalance();
}}
/>
)}
</Box>
);
};