diff --git a/package.json b/package.json index 14e9b0e0..d01af7da 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "@ar.io/sdk": "2.5.0-alpha.8", "@fontsource/rubik": "^5.0.19", - "@headlessui/react": "^1.7.19", + "@headlessui/react": "^2.2.0", "@radix-ui/react-tooltip": "^1.0.7", "@sentry/browser": "^7.101.1", "@sentry/react": "^7.101.1", diff --git a/src/components/AssessmentDetailsPanel.tsx b/src/components/AssessmentDetailsPanel.tsx index 901c04a1..6b9c35f9 100644 --- a/src/components/AssessmentDetailsPanel.tsx +++ b/src/components/AssessmentDetailsPanel.tsx @@ -1,4 +1,4 @@ -import { Dialog } from '@headlessui/react'; +import { Dialog, DialogPanel } from '@headlessui/react'; import { CaretDoubleRightIcon, CheckSquareIcon, @@ -177,7 +177,7 @@ const AssessmentDetailsPanel = ({ />
- )}
- + ); diff --git a/src/components/Profile.tsx b/src/components/Profile.tsx index 69d31ce3..b42d11fe 100644 --- a/src/components/Profile.tsx +++ b/src/components/Profile.tsx @@ -1,5 +1,5 @@ /* eslint-disable tailwindcss/migration-from-tailwind-2 */ -import { Popover } from '@headlessui/react'; +import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'; import { useGlobalState } from '@src/store'; import { formatBalance, formatWalletAddress } from '@src/utils'; import { forwardRef, useState } from 'react'; @@ -45,9 +45,9 @@ const Profile = () => { return walletAddress ? ( - + - +
@@ -110,7 +110,7 @@ const Profile = () => { Logout
-
+
) : walletStateInitialized ? (
diff --git a/src/components/forms/validation.ts b/src/components/forms/validation.ts index 220ccc98..a2352d40 100644 --- a/src/components/forms/validation.ts +++ b/src/components/forms/validation.ts @@ -86,7 +86,7 @@ export const validateNumberRange = ( }; }; -export const validateUnstakeAmount = ( +export const validateWithdrawAmount = ( propertyName: string, ticker: string, currentStake: number, diff --git a/src/components/icons/circle.svg b/src/components/icons/circle.svg new file mode 100644 index 00000000..4d5133ef --- /dev/null +++ b/src/components/icons/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/icons/circle_check.svg b/src/components/icons/circle_check.svg new file mode 100644 index 00000000..f130c0d1 --- /dev/null +++ b/src/components/icons/circle_check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index 8db3fa1c..4c9af254 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -8,6 +8,8 @@ import CancelButtonXIcon from './cancel_button_x.svg?react'; import CaretDoubleRightIcon from './caret_double_right.svg?react'; import CheckSquareIcon from './check_square.svg?react'; import ChevronDownIcon from './chevron_down.svg?react'; +import CircleCheckIcon from './circle_check.svg?react'; +import CircleIcon from './circle.svg?react'; import ClockRewindIcon from './clock_rewind.svg?react'; import CloseIcon from './close.svg?react'; import CloseDrawerIcon from './close_drawer.svg?react'; @@ -60,6 +62,8 @@ export { CancelButtonXIcon, CheckSquareIcon, ChevronDownIcon, + CircleCheckIcon, + CircleIcon, ClockRewindIcon, CloseDrawerIcon, CloseIcon, diff --git a/src/components/modals/BaseModal.tsx b/src/components/modals/BaseModal.tsx index 1f56e0a8..55fe3389 100644 --- a/src/components/modals/BaseModal.tsx +++ b/src/components/modals/BaseModal.tsx @@ -1,4 +1,4 @@ -import { Dialog } from '@headlessui/react'; +import { Dialog, DialogPanel } from '@headlessui/react'; import { ReactElement } from 'react'; import { CloseIcon } from '../icons'; @@ -21,18 +21,18 @@ const BaseModal = ({ />
- {showCloseButton && ( )} -
+
{children}
- +
); diff --git a/src/components/modals/CancelWithdrawalModal.tsx b/src/components/modals/CancelWithdrawalModal.tsx index 79f6886f..7a6789f2 100644 --- a/src/components/modals/CancelWithdrawalModal.tsx +++ b/src/components/modals/CancelWithdrawalModal.tsx @@ -76,7 +76,7 @@ const CancelWithdrawalModal = ({
-
+
Please type "CONFIRM" in the text box to proceed. @@ -85,7 +85,7 @@ const CancelWithdrawalModal = ({ type="text" onChange={(e) => setConfirmText(e.target.value)} className={ - 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-3 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' + 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-4 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' } value={confirmText} /> diff --git a/src/components/modals/InstantWithdrawalModal.tsx b/src/components/modals/InstantWithdrawalModal.tsx index 4c1479fe..a104a25e 100644 --- a/src/components/modals/InstantWithdrawalModal.tsx +++ b/src/components/modals/InstantWithdrawalModal.tsx @@ -142,7 +142,7 @@ const InstantWithdrawalModal = ({
-
+
-
+
Please type "WITHDRAW" in the text box to proceed. @@ -189,7 +189,7 @@ const InstantWithdrawalModal = ({ type="text" onChange={(e) => setConfirmText(e.target.value)} className={ - 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-3 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' + 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-4 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' } value={confirmText} /> diff --git a/src/components/modals/LeaveNetworkModal.tsx b/src/components/modals/LeaveNetworkModal.tsx index 5605a9e1..557d07a2 100644 --- a/src/components/modals/LeaveNetworkModal.tsx +++ b/src/components/modals/LeaveNetworkModal.tsx @@ -94,14 +94,14 @@ const LeaveNetworkModal = ({ onClose }: { onClose: () => void }) => {
-
+
Please type "LEAVE NETWORK" in the text box to proceed.
setLeaveNetworkText(e.target.value)} className={ - 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-3 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' + 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-4 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' } value={leaveNetworkText} /> diff --git a/src/components/modals/ReviewStakeModal.tsx b/src/components/modals/ReviewStakeModal.tsx new file mode 100644 index 00000000..bdea002c --- /dev/null +++ b/src/components/modals/ReviewStakeModal.tsx @@ -0,0 +1,176 @@ +import { AoGatewayWithAddress, IOToken } from '@ar.io/sdk/web'; +import { log, WRITE_OPTIONS } from '@src/constants'; +import { useGlobalState } from '@src/store'; +import { formatAddress, formatWithCommas } from '@src/utils'; +import { ArweaveTransactionID } from '@src/utils/ArweaveTransactionId'; +import { showErrorToast } from '@src/utils/toast'; +import { useQueryClient } from '@tanstack/react-query'; +import { useState } from 'react'; +import Button, { ButtonType } from '../Button'; +import { LinkArrowIcon } from '../icons'; +import LabelValueRow from '../LabelValueRow'; +import BaseModal from './BaseModal'; +import BlockingMessageModal from './BlockingMessageModal'; +import SuccessModal from './SuccessModal'; +import WithdrawWarning from './WithdrawWarning'; + +const ReviewStakeModal = ({ + gateway, + amountToStake, + onSuccess, + onClose, + walletAddress, + ticker, +}: { + gateway: AoGatewayWithAddress; + amountToStake: number; + walletAddress: ArweaveTransactionID; + onClose: () => void; + onSuccess: () => void; + ticker: string; +}) => { + const queryClient = useQueryClient(); + const arIOWriteableSDK = useGlobalState((state) => state.arIOWriteableSDK); + + const [txid, setTxid] = useState(); + + const [showBlockingMessageModal, setShowBlockingMessageModal] = + useState(false); + const [showSuccessModal, setShowSuccessModal] = useState(false); + + const submitForm = async () => { + if (arIOWriteableSDK) { + setShowBlockingMessageModal(true); + + try { + const { id: txID } = await arIOWriteableSDK.delegateStake( + { + target: gateway.gatewayAddress, + stakeQty: new IOToken(amountToStake).toMIO(), + }, + WRITE_OPTIONS, + ); + setTxid(txID); + + log.info(`Increase Delegate Stake txID: ${txID}`); + + queryClient.invalidateQueries({ + queryKey: ['gateway', walletAddress.toString()], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['gateways'], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['balances'], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['delegateStakes'], + refetchType: 'all', + }); + + setShowSuccessModal(true); + } catch (e: any) { + showErrorToast(`${e}`); + } finally { + setShowBlockingMessageModal(false); + } + } + }; + + return ( + <> + +
+
+ Review +
+
+ + + + + + + +
+ +
+ +
+ +
+ +
+
+
+ + + {showBlockingMessageModal && ( + setShowBlockingMessageModal(false)} + message="Sign the following data with your wallet to proceed." + > + )} + {showSuccessModal && ( + { + setShowSuccessModal(false); + onClose(); + onSuccess(); + }} + title="Congratulations" + bodyText={ +
+
You have successfully updated your stake.
+
+
Transaction ID:
+ +
+
+ } + /> + )} + + ); +}; + +export default ReviewStakeModal; diff --git a/src/components/modals/ReviewWithdrawalModal.tsx b/src/components/modals/ReviewWithdrawalModal.tsx new file mode 100644 index 00000000..62666754 --- /dev/null +++ b/src/components/modals/ReviewWithdrawalModal.tsx @@ -0,0 +1,239 @@ +import { AoGatewayWithAddress, IOToken } from '@ar.io/sdk/web'; +import { log, WRITE_OPTIONS } from '@src/constants'; +import { useGlobalState } from '@src/store'; +import { WithdrawalType } from '@src/types'; +import { formatAddress, formatDateTime, formatWithCommas } from '@src/utils'; +import { ArweaveTransactionID } from '@src/utils/ArweaveTransactionId'; +import { showErrorToast } from '@src/utils/toast'; +import { useQueryClient } from '@tanstack/react-query'; +import dayjs from 'dayjs'; +import { useEffect, useState } from 'react'; +import Button, { ButtonType } from '../Button'; +import { LinkArrowIcon } from '../icons'; +import LabelValueRow from '../LabelValueRow'; +import BaseModal from './BaseModal'; +import BlockingMessageModal from './BlockingMessageModal'; +import SuccessModal from './SuccessModal'; + +const ReviewWithdrawalModal = ({ + gateway, + amountToWithdraw, + withdrawalType, + onSuccess, + onClose, + walletAddress, + ticker, + withdrawalFee, + returningAmount, +}: { + gateway: AoGatewayWithAddress; + amountToWithdraw: number; + withdrawalType: WithdrawalType; + walletAddress: ArweaveTransactionID; + onClose: () => void; + onSuccess: () => void; + ticker: string; + withdrawalFee: number; + returningAmount?: number | string; +}) => { + const queryClient = useQueryClient(); + const arIOWriteableSDK = useGlobalState((state) => state.arIOWriteableSDK); + + const [txid, setTxid] = useState(); + + const [showBlockingMessageModal, setShowBlockingMessageModal] = + useState(false); + const [showSuccessModal, setShowSuccessModal] = useState(false); + + const [dateOfReturn, setDateOfReturn] = useState(''); + + const [confirmText, setConfirmText] = useState(''); + + const termsAccepted = confirmText === 'WITHDRAW'; + + useEffect(() => { + setDateOfReturn( + withdrawalType === 'expedited' + ? 'Instant' + : formatDateTime(dayjs(new Date()).add(30, 'day').toDate()), + ); + }, [withdrawalType]); + + const submitForm = async () => { + if (arIOWriteableSDK) { + setShowBlockingMessageModal(true); + + try { + const instant = withdrawalType === 'expedited'; + + const { id: txID } = await arIOWriteableSDK.decreaseDelegateStake( + { + target: gateway.gatewayAddress, + decreaseQty: new IOToken(amountToWithdraw).toMIO(), + instant, + }, + WRITE_OPTIONS, + ); + setTxid(txID); + + log.info(`Decrease Delegate Stake txID: ${txID}`); + + queryClient.invalidateQueries({ + queryKey: ['gateway', walletAddress.toString()], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['gateways'], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['balances'], + refetchType: 'all', + }); + queryClient.invalidateQueries({ + queryKey: ['delegateStakes'], + refetchType: 'all', + }); + + setShowSuccessModal(true); + } catch (e: any) { + showErrorToast(`${e}`); + } finally { + setShowBlockingMessageModal(false); + } + } + }; + + return ( + <> + +
+
+ Review +
+
+ + + + + + + + +
+ +
+ + + {withdrawalType === 'expedited' && ( + <> + + + + )} +
+ +
+
+
+ Please type "WITHDRAW" in the text box to proceed. +
+ setConfirmText(e.target.value)} + className={ + 'h-7 w-full rounded-md border border-grey-700 bg-grey-1000 p-4 text-sm text-mid outline-none placeholder:text-grey-400 focus:text-high' + } + value={confirmText} + /> +
+ +
+
+
+ +
+
+
+
+ + {showBlockingMessageModal && ( + setShowBlockingMessageModal(false)} + message="Sign the following data with your wallet to proceed." + > + )} + {showSuccessModal && ( + { + setShowSuccessModal(false); + onClose(); + onSuccess(); + }} + title="Congratulations" + bodyText={ +
+
You have successfully updated your stake.
+
+
Transaction ID:
+ +
+
+ } + /> + )} + + ); +}; + +export default ReviewWithdrawalModal; diff --git a/src/components/modals/StakingModal.tsx b/src/components/modals/StakingModal.tsx index 1df49dd0..87743517 100644 --- a/src/components/modals/StakingModal.tsx +++ b/src/components/modals/StakingModal.tsx @@ -1,18 +1,13 @@ -import { IOToken, mIOToken } from '@ar.io/sdk/web'; -import { - EAY_TOOLTIP_FORMULA, - EAY_TOOLTIP_TEXT, - WRITE_OPTIONS, - log, -} from '@src/constants'; +import { mIOToken } from '@ar.io/sdk/web'; +import { Label, Radio, RadioGroup } from '@headlessui/react'; +import { EAY_TOOLTIP_FORMULA, EAY_TOOLTIP_TEXT } from '@src/constants'; import useBalances from '@src/hooks/useBalances'; import useDelegateStakes from '@src/hooks/useDelegateStakes'; import useGateway from '@src/hooks/useGateway'; import useRewardsInfo from '@src/hooks/useRewardsInfo'; import { useGlobalState } from '@src/store'; -import { formatWithCommas } from '@src/utils'; -import { showErrorToast } from '@src/utils/toast'; -import { useQueryClient } from '@tanstack/react-query'; +import { WithdrawalType } from '@src/types'; +import { formatAddress, formatWithCommas } from '@src/utils'; import { MathJax } from 'better-react-mathjax'; import { useEffect, useState } from 'react'; import Button, { ButtonType } from '../Button'; @@ -21,14 +16,13 @@ import Tooltip from '../Tooltip'; import ErrorMessageIcon from '../forms/ErrorMessageIcon'; import { validateIOAmount, - validateUnstakeAmount, validateWalletAddress, + validateWithdrawAmount, } from '../forms/validation'; -import { InfoIcon } from '../icons'; +import { CircleCheckIcon, CircleIcon, InfoIcon } from '../icons'; import BaseModal from './BaseModal'; -import BlockingMessageModal from './BlockingMessageModal'; -import SuccessModal from './SuccessModal'; -import UnstakeWarning from './UnstakeWarning'; +import ReviewStakeModal from './ReviewStakeModal'; +import ReviewWithdrawalModal from './ReviewWithdrawalModal'; const StakingModal = ({ onClose, @@ -38,11 +32,8 @@ const StakingModal = ({ onClose: () => void; ownerWallet?: string; }) => { - const queryClient = useQueryClient(); - const walletAddress = useGlobalState((state) => state.walletAddress); const { data: balances } = useBalances(walletAddress); - const arIOWriteableSDK = useGlobalState((state) => state.arIOWriteableSDK); const ticker = useGlobalState((state) => state.ticker); const [tab, setTab] = useState(0); @@ -51,11 +42,13 @@ const StakingModal = ({ const [currentStake, setCurrentStake] = useState(0); const [amountToStake, setAmountToStake] = useState(''); - const [amountToUnstake, setAmountToUnstake] = useState(''); + const [amountToWithdraw, setAmountToWithdraw] = useState(''); + const [withdrawalType, setWithdrawalType] = + useState('standard'); - const [showBlockingMessageModal, setShowBlockingMessageModal] = + const [showReviewStakeModal, setShowReviewStakeModal] = useState(false); + const [showReviewWithdrawalModal, setShowReviewWithdrawalModal] = useState(false); - const [showSuccessModal, setShowSuccessModal] = useState(false); const gatewayOwnerWallet = ownerWallet?.toString() ?? userEnteredWalletAddress; @@ -82,12 +75,12 @@ const StakingModal = ({ const newTotalStake = tab == 0 ? currentStake + parseFloat(amountToStake) - : currentStake - parseFloat(amountToUnstake); + : currentStake - parseFloat(amountToWithdraw); const newStake = - tab == 0 ? parseFloat(amountToStake) : -parseFloat(amountToUnstake); + tab == 0 ? parseFloat(amountToStake) : -parseFloat(amountToWithdraw); const rewardsInfo = useRewardsInfo(gateway, newStake); const EAY = - rewardsInfo && newTotalStake > 0 + rewardsInfo && newTotalStake > 0 && !isNaN(rewardsInfo.EAY) ? (rewardsInfo.EAY * 100).toLocaleString('en-us', { maximumFractionDigits: 2, }) + '%' @@ -98,6 +91,16 @@ const StakingModal = ({ : 500; const minRequiredStakeToAdd = currentStake > 0 ? 1 : minDelegatedStake; + const withdrawalFee = + withdrawalType === 'expedited' ? 0.5 * parseFloat(amountToWithdraw) : 0; + const returningAmount = isNaN(parseFloat(amountToWithdraw)) + ? '-' + : +( + isNaN(withdrawalFee) + ? parseFloat(amountToWithdraw) + : parseFloat(amountToWithdraw) - withdrawalFee + ).toFixed(4); + const validators = { address: validateWalletAddress('Gateway Owner'), stakeAmount: validateIOAmount( @@ -106,8 +109,8 @@ const StakingModal = ({ minRequiredStakeToAdd, balances?.io, ), - unstakeAmount: validateUnstakeAmount( - 'Unstake Amount', + withdrawAmount: validateWithdrawAmount( + 'Withdraw Amount', ticker, currentStake, minDelegatedStake, @@ -121,12 +124,18 @@ const StakingModal = ({ if (tab == 0) { return validators.stakeAmount(amountToStake) == undefined; } else { - return validators.unstakeAmount(amountToUnstake) == undefined; + return validators.withdrawAmount(amountToWithdraw) == undefined; } }; + const parsedStake = parseFloat( + amountToStake.length === 0 ? '0' : amountToStake, + ); const remainingBalance = - isFormValid() && balances ? balances.io - parseFloat(amountToStake) : '-'; + balances && parsedStake <= balances.io ? balances.io - parsedStake : -1; + + const parsedWithdrawing = parseFloat(amountToWithdraw.length === 0 ? '0' : amountToWithdraw); + const remainingWithdrawalBalance = currentStake - parsedWithdrawing; const baseTabClassName = 'text-center py-3'; const selectedTabClassNames = `${baseTabClassName} bg-grey-700 border-b border-red-400`; @@ -136,7 +145,7 @@ const StakingModal = ({ if (tab == 0) { setAmountToStake((balances?.io || 0) + ''); } else { - setAmountToUnstake(currentStake + ''); + setAmountToWithdraw(currentStake + ''); } }; @@ -147,63 +156,10 @@ const StakingModal = ({ !allowDelegatedStaking)) || (tab == 1 && currentStake <= 0); - const submitForm = async () => { - if (walletAddress && arIOWriteableSDK && gateway && isFormValid()) { - setShowBlockingMessageModal(true); - - try { - if (tab == 0) { - const { id: txID } = await arIOWriteableSDK.delegateStake( - { - target: gatewayOwnerWallet, - stakeQty: new IOToken(parseFloat(amountToStake)).toMIO(), - }, - WRITE_OPTIONS, - ); - - log.info(`Increase Delegate Stake txID: ${txID}`); - } else { - const { id: txID } = await arIOWriteableSDK.decreaseDelegateStake( - { - target: gatewayOwnerWallet, - decreaseQty: new IOToken(parseFloat(amountToUnstake)).toMIO(), - }, - WRITE_OPTIONS, - ); - - log.info(`Decrease Delegate Stake txID: ${txID}`); - } - - queryClient.invalidateQueries({ - queryKey: ['gateway', walletAddress.toString()], - refetchType: 'all', - }); - queryClient.invalidateQueries({ - queryKey: ['gateways'], - refetchType: 'all', - }); - queryClient.invalidateQueries({ - queryKey: ['balances'], - refetchType: 'all', - }); - queryClient.invalidateQueries({ - queryKey: ['delegateStakes'], - refetchType: 'all', - }); - - setShowSuccessModal(true); - } catch (e: any) { - showErrorToast(`${e}`); - } finally { - setShowBlockingMessageModal(false); - } - } - }; - const errorMessages = { gatewayOwner: validators.address(gatewayOwnerWallet), stakeAmount: validators.stakeAmount(amountToStake), - unstakeAmount: validators.unstakeAmount(amountToUnstake), + withdrawAmount: validators.withdrawAmount(amountToWithdraw), cannotStake: (balances?.io || 0) < minRequiredStakeToAdd ? `Insufficient balance, at least ${minRequiredStakeToAdd} IO required.` @@ -215,46 +171,65 @@ const StakingModal = ({ return (
-
+
-
Gateway Owner:
- {ownerWallet ? ( -
{ownerWallet}
- ) : ( - { - setUserEnteredWalletAddress(e.target.value); - }} - maxLength={43} +
+ {ownerWallet ? ( + + ) : ( + <> +
Gateway Owner:
+ { + setUserEnteredWalletAddress(e.target.value); + }} + maxLength={43} + /> + + )} + + - )} + + +
+
Amount:
{tab == 0 ? balances && - `Available: ${formatWithCommas(balances.io)} ${ticker}` - : `Available to Unstake: ${formatWithCommas(currentStake)} ${ticker}`} + `Available: ${remainingBalance >= 0 ? formatWithCommas(+remainingBalance) : '-'} ${ticker}` + : `Available to Withdraw: ${remainingWithdrawalBalance >= 0 ? formatWithCommas(remainingWithdrawalBalance) : '-'} ${ticker}`}
@@ -265,8 +240,8 @@ const StakingModal = ({ disabled={disableInput} readOnly={disableInput} type="text" - placeholder={`Enter amount of ${ticker} to ${tab == 0 ? 'stake' : 'unstake'}`} - value={tab == 0 ? amountToStake : amountToUnstake} + placeholder={`Enter amount of ${ticker} to ${tab == 0 ? 'stake' : 'withdraw'}`} + value={tab == 0 ? amountToStake : amountToWithdraw} onChange={(e) => { const textValue = e.target.value; @@ -277,7 +252,7 @@ const StakingModal = ({ if (tab == 0) { setAmountToStake(textValue); } else { - setAmountToUnstake(textValue); + setAmountToWithdraw(textValue); } }} > @@ -295,10 +270,10 @@ const StakingModal = ({ /> )} {tab == 1 && - amountToUnstake?.length > 0 && - errorMessages.unstakeAmount && ( + amountToWithdraw?.length > 0 && + errorMessages.withdrawAmount && ( )} @@ -311,103 +286,147 @@ const StakingModal = ({ text="Max" />
-
+
+ {tab == 1 && ( + setWithdrawalType(v)} + > + +
+
+ + + +
+

+ 30 day withdrawal period with no fees. +

+
+
+ + +
+
+ + + +
+

+ Instant withdrawal with 50% fee. +

+
+
+
+ )} +
+
+
+ {tab == 1 && withdrawalType == 'expedited' && ( + <> + + + + )} + +
{tab == 0 && ( )} - - -

{EAY_TOOLTIP_TEXT}

- {EAY_TOOLTIP_FORMULA} -
- } - > - - - } - /> - -
- -
+ {tab == 0 && ( + +

{EAY_TOOLTIP_TEXT}

+ + {EAY_TOOLTIP_FORMULA} + +
+ } + > + + + } + /> + )}
-
-
- - - {tab == 0 && ( - - )} -
- {showBlockingMessageModal && ( - setShowBlockingMessageModal(false)} - message="Sign the following data with your wallet to proceed." - > + {showReviewStakeModal && gateway && walletAddress && ( + setShowReviewStakeModal(false)} + onSuccess={() => onClose()} + ticker={ticker} + walletAddress={walletAddress} + /> )} - {showSuccessModal && ( - { - setShowSuccessModal(false); - onClose(); - }} - title="Congratulations" - bodyText="You have successfully updated stake." + {showReviewWithdrawalModal && gateway && walletAddress && ( + setShowReviewWithdrawalModal(false)} + onSuccess={() => onClose()} + ticker={ticker} + walletAddress={walletAddress} + withdrawalFee={withdrawalFee} + returningAmount={returningAmount} /> )}
diff --git a/src/components/modals/UnstakeAllModal.tsx b/src/components/modals/WithdrawAllModal.tsx similarity index 90% rename from src/components/modals/UnstakeAllModal.tsx rename to src/components/modals/WithdrawAllModal.tsx index 873bc3c0..2933d112 100644 --- a/src/components/modals/UnstakeAllModal.tsx +++ b/src/components/modals/WithdrawAllModal.tsx @@ -5,12 +5,12 @@ import { showErrorToast } from '@src/utils/toast'; import { useState } from 'react'; import Button, { ButtonType } from '../Button'; import BaseModal from './BaseModal'; -import UnstakeWarning from './UnstakeWarning'; +import WithdrawWarning from './WithdrawWarning'; import BlockingMessageModal from './BlockingMessageModal'; import SuccessModal from './SuccessModal'; import { useQueryClient } from '@tanstack/react-query'; -const UnstakeAllModal = ({ +const WithdrawAllModal = ({ onClose, activeStakes, }: { @@ -84,7 +84,7 @@ const UnstakeAllModal = ({
-
Unstake All
+
Withdraw All
Withdraw all delegated stakes.
@@ -115,14 +115,10 @@ const UnstakeAllModal = ({ ))} - +
-
-
-
Fee:
-
- AR
-
+
Total Withdrawal:
@@ -134,8 +130,8 @@ const UnstakeAllModal = ({
} + title="Withdraw" + text={
Withdraw
} className="w-full" />
@@ -162,4 +158,4 @@ const UnstakeAllModal = ({ ); }; -export default UnstakeAllModal; +export default WithdrawAllModal; diff --git a/src/components/modals/UnstakeWarning.tsx b/src/components/modals/WithdrawWarning.tsx similarity index 87% rename from src/components/modals/UnstakeWarning.tsx rename to src/components/modals/WithdrawWarning.tsx index 09fe1ef6..fc2aecfd 100644 --- a/src/components/modals/UnstakeWarning.tsx +++ b/src/components/modals/WithdrawWarning.tsx @@ -1,6 +1,6 @@ import { WarningTriangleIcon } from '../icons'; -const UnstakeWarning = () => { +const WithdrawWarning = () => { return (
@@ -14,4 +14,4 @@ const UnstakeWarning = () => { ); }; -export default UnstakeWarning; +export default WithdrawWarning; diff --git a/src/hooks/useDelegateStakes.ts b/src/hooks/useDelegateStakes.ts index f97ad1e3..47c9b61a 100644 --- a/src/hooks/useDelegateStakes.ts +++ b/src/hooks/useDelegateStakes.ts @@ -11,7 +11,7 @@ const useDelegateStakes = (address?: string) => { const arIOReadSDK = useGlobalState((state) => state.arIOReadSDK); const res = useQuery({ - queryKey: ['delegateStakes', address], + queryKey: ['delegateStakes', arIOReadSDK, address], queryFn: async () => { if (!address) { throw new Error('Address is not set'); @@ -30,6 +30,7 @@ const useDelegateStakes = (address?: string) => { cursor, limit: 10, }); + pageResult.items.forEach((d) => { if (d.type === 'stake') { retVal.stakes.push(d); diff --git a/src/hooks/useGateway.ts b/src/hooks/useGateway.ts index b42e40b3..a04979f2 100644 --- a/src/hooks/useGateway.ts +++ b/src/hooks/useGateway.ts @@ -10,7 +10,7 @@ const useGateway = ({ const arIOReadSDK = useGlobalState((state) => state.arIOReadSDK); const queryResults = useQuery({ - queryKey: ['gateway', ownerWalletAddress || ''], + queryKey: ['gateway', arIOReadSDK, ownerWalletAddress || ''], queryFn: () => { if (ownerWalletAddress === undefined) { return Promise.reject( diff --git a/src/pages/Staking/MyStakesTable.tsx b/src/pages/Staking/MyStakesTable.tsx index 55b6d4f5..971a4e19 100644 --- a/src/pages/Staking/MyStakesTable.tsx +++ b/src/pages/Staking/MyStakesTable.tsx @@ -12,7 +12,7 @@ import { import CancelWithdrawalModal from '@src/components/modals/CancelWithdrawalModal'; import InstantWithdrawalModal from '@src/components/modals/InstantWithdrawalModal'; import StakingModal from '@src/components/modals/StakingModal'; -import UnstakeAllModal from '@src/components/modals/UnstakeAllModal'; +import WithdrawAllModal from '@src/components/modals/WithdrawAllModal'; import useDelegateStakes from '@src/hooks/useDelegateStakes'; import useGateways from '@src/hooks/useGateways'; import { useGlobalState } from '@src/store'; @@ -54,7 +54,7 @@ const MyStakesTable = () => { const [tableMode, setTableMode] = useState('activeStakes'); - const [showUnstakeAllModal, setShowUnstakeAllModal] = useState(false); + const [showWithdrawAllModal, setShowWithdrawAllModal] = useState(false); const [stakingModalWalletAddress, setStakingModalWalletAddress] = useState(); const [showQuickStake, setShowQuickStake] = useState(false); @@ -317,7 +317,7 @@ const MyStakesTable = () => { active={true} title="Withdraw All" text="Withdraw All" - onClick={() => setShowUnstakeAllModal(true)} + onClick={() => setShowWithdrawAllModal(true)} /> )}