diff --git a/src/pages/RFOX/Widget.tsx b/src/pages/RFOX/Widget.tsx index 2d5caf257fa..c1bd06fb14b 100644 --- a/src/pages/RFOX/Widget.tsx +++ b/src/pages/RFOX/Widget.tsx @@ -97,7 +97,7 @@ export const Widget: React.FC = () => { - + diff --git a/src/pages/RFOX/components/AddressSelection.tsx b/src/pages/RFOX/components/AddressSelection.tsx index bbdeef5bfda..067c501d224 100644 --- a/src/pages/RFOX/components/AddressSelection.tsx +++ b/src/pages/RFOX/components/AddressSelection.tsx @@ -7,18 +7,22 @@ import { FormLabel, Input, Stack, + Tag, } from '@chakra-ui/react' import { fromAccountId, thorchainAssetId, thorchainChainId, toAccountId } from '@shapeshiftoss/caip' import type { FC } from 'react' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { useForm, useFormContext } from 'react-hook-form' import { useTranslate } from 'react-polyglot' import { AccountDropdown } from 'components/AccountDropdown/AccountDropdown' import { InlineCopyButton } from 'components/InlineCopyButton' +import { MiddleEllipsis } from 'components/MiddleEllipsis/MiddleEllipsis' +import { Text } from 'components/Text' import { validateAddress } from 'lib/address/address' import { selectAccountIdByAccountNumberAndChainId, selectAccountNumberByAccountId, + selectPortfolioAccountIdsByAssetIdFilter, } from 'state/slices/selectors' import { useAppSelector } from 'state/store' @@ -26,8 +30,10 @@ import { selectRuneAddress } from '../helpers' import { useRFOXContext } from '../hooks/useRfoxContext' import { useStakingInfoQuery } from '../hooks/useStakingInfoQuery' import type { AddressSelectionValues } from '../types' +import { RfoxTabIndex } from '../Widget' type AddressSelectionProps = { + setStepIndex: ((index: number) => void) | undefined onRuneAddressChange: (address: string | undefined) => void selectedAddress: string | undefined } & ( @@ -58,6 +64,7 @@ export const AddressSelection: FC = ({ isNewAddress, selectedAddress, validateIsNewAddress, + setStepIndex, }) => { const translate = useTranslate() @@ -77,6 +84,15 @@ export const AddressSelection: FC = ({ select: selectRuneAddress, }) + useEffect(() => { + handleRuneAddressChange(undefined) + setIsManualAddress(false) + }, [stakingAssetAccountId, handleRuneAddressChange]) + + const shouldDisableAccountDropdown = useMemo(() => { + return Boolean(currentRuneAddress && setStepIndex) + }, [currentRuneAddress, setStepIndex]) + const [isManualAddress, setIsManualAddress] = useState(false) const handleAccountIdChange = useCallback( @@ -91,6 +107,10 @@ export const AddressSelection: FC = ({ setIsManualAddress(!isManualAddress) }, [isManualAddress, handleRuneAddressChange]) + const handleChangeAddressClick = useCallback(() => { + setStepIndex?.(RfoxTabIndex.ChangeAddress) + }, [setStepIndex]) + const manualAddressSelection = useMemo(() => { if (!isManualAddress) return null return ( @@ -177,18 +197,44 @@ export const AddressSelection: FC = ({ }, [accountIdsByAccountNumberAndChainId, stakingAssetAccountNumber]) const maybeRuneAccountId = useMemo(() => { - if (selectedAddress) return toAccountId({ account: selectedAddress, chainId: thorchainChainId }) + if (selectedAddress && !shouldDisableAccountDropdown) + return toAccountId({ account: selectedAddress, chainId: thorchainChainId }) if (currentRuneAddress) return toAccountId({ account: currentRuneAddress, chainId: thorchainChainId }) if (maybeMatchingRuneAccountId) return maybeMatchingRuneAccountId + return undefined - }, [currentRuneAddress, maybeMatchingRuneAccountId, selectedAddress]) + }, [ + currentRuneAddress, + maybeMatchingRuneAccountId, + selectedAddress, + shouldDisableAccountDropdown, + ]) const maybeSelectedRuneAddress = useMemo(() => { if (!maybeRuneAccountId) return return fromAccountId(maybeRuneAccountId).account }, [maybeRuneAccountId]) + const filter = useMemo(() => ({ accountId: maybeRuneAccountId }), [maybeRuneAccountId]) + const accountNumber = useAppSelector(state => selectAccountNumberByAccountId(state, filter)) + + const accountsFilter = useMemo(() => ({ assetId: thorchainAssetId }), []) + const runeAccounts = useAppSelector(state => + selectPortfolioAccountIdsByAssetIdFilter(state, accountsFilter), + ) + + const CustomAddress = useCallback(() => { + if (!maybeSelectedRuneAddress) + return + + return ( + + + + ) + }, [maybeSelectedRuneAddress]) + const accountSelection = useMemo(() => { if (isManualAddress) return null @@ -197,16 +243,34 @@ export const AddressSelection: FC = ({ isDisabled={!maybeSelectedRuneAddress} value={maybeSelectedRuneAddress ?? ''} > - + {(!Boolean(currentRuneAddress) && maybeRuneAccountId && setStepIndex) || + accountNumber !== undefined || + (!setStepIndex && runeAccounts.length) ? ( + + ) : ( + + )} ) - }, [handleAccountIdChange, isManualAddress, maybeRuneAccountId, maybeSelectedRuneAddress]) + }, [ + handleAccountIdChange, + isManualAddress, + maybeRuneAccountId, + maybeSelectedRuneAddress, + CustomAddress, + currentRuneAddress, + setStepIndex, + shouldDisableAccountDropdown, + accountNumber, + runeAccounts, + ]) const addressSelectionLabel = useMemo( () => @@ -220,6 +284,39 @@ export const AddressSelection: FC = ({ [isNewAddress, translate], ) + const TopRightButton = useCallback(() => { + if (Boolean(currentRuneAddress && setStepIndex)) { + return ( + + ) + } + + return ( + + ) + }, [ + currentRuneAddress, + handleToggleInputMethod, + handleChangeAddressClick, + isManualAddress, + translate, + setStepIndex, + ]) + return ( @@ -227,16 +324,7 @@ export const AddressSelection: FC = ({ {addressSelectionLabel} - + {accountSelection || manualAddressSelection} {addressSelectionDescription} diff --git a/src/pages/RFOX/components/ChangeAddress/ChangeAddressInput.tsx b/src/pages/RFOX/components/ChangeAddress/ChangeAddressInput.tsx index ae233583c89..7629812f064 100644 --- a/src/pages/RFOX/components/ChangeAddress/ChangeAddressInput.tsx +++ b/src/pages/RFOX/components/ChangeAddress/ChangeAddressInput.tsx @@ -17,6 +17,7 @@ import { useTranslate } from 'react-polyglot' import { useHistory } from 'react-router' import { encodeFunctionData } from 'viem' import { Amount } from 'components/Amount/Amount' +import { InlineCopyButton } from 'components/InlineCopyButton' import { Row } from 'components/Row/Row' import { SlideTransition } from 'components/SlideTransition' import { RawText, Text } from 'components/Text' @@ -233,9 +234,13 @@ export const ChangeAddressInput: FC - {currentRuneAddress - ? middleEllipsis(currentRuneAddress) - : translate('RFOX.noAddressFound')} + {currentRuneAddress ? ( + + {middleEllipsis(currentRuneAddress)} + + ) : ( + translate('RFOX.noAddressFound') + )} @@ -268,6 +273,7 @@ export const ChangeAddressInput: FC diff --git a/src/pages/RFOX/components/Stake/Stake.tsx b/src/pages/RFOX/components/Stake/Stake.tsx index 604b05716d0..e1f43e5c345 100644 --- a/src/pages/RFOX/components/Stake/Stake.tsx +++ b/src/pages/RFOX/components/Stake/Stake.tsx @@ -57,15 +57,15 @@ const BridgeStatus = makeSuspenseful( const StakeEntries = [StakeRoutePaths.Input, StakeRoutePaths.Confirm, StakeRoutePaths.Status] -export const Stake: React.FC = ({ headerComponent }) => { +export const Stake: React.FC = ({ headerComponent, setStepIndex }) => { return ( - + ) } -export const StakeRoutes: React.FC = ({ headerComponent }) => { +export const StakeRoutes: React.FC = ({ headerComponent, setStepIndex }) => { const location = useLocation() const { state: maybeBridgeQuote } = location @@ -102,11 +102,12 @@ export const StakeRoutes: React.FC = ({ headerComponent }) => { stakingAssetId={stakingAssetId} runeAddress={runeAddress} headerComponent={headerComponent} + setStepIndex={setStepIndex} onRuneAddressChange={setRuneAddress} setConfirmedQuote={setConfirmedQuote} /> ) - }, [headerComponent, runeAddress]) + }, [headerComponent, runeAddress, setStepIndex]) const renderStakeConfirm = useCallback(() => { if (!confirmedQuote) return null @@ -115,11 +116,12 @@ export const StakeRoutes: React.FC = ({ headerComponent }) => { ) - }, [confirmedQuote, headerComponent, stakeTxid]) + }, [confirmedQuote, headerComponent, stakeTxid, setStepIndex]) const renderStakeStatus = useCallback(() => { if (!confirmedQuote) return null @@ -130,11 +132,12 @@ export const StakeRoutes: React.FC = ({ headerComponent }) => { txId={stakeTxid} setStakeTxid={setStakeTxid} confirmedQuote={confirmedQuote} + setStepIndex={setStepIndex} onTxConfirmed={handleTxConfirmed} headerComponent={headerComponent} /> ) - }, [confirmedQuote, handleTxConfirmed, headerComponent, stakeTxid]) + }, [confirmedQuote, handleTxConfirmed, headerComponent, stakeTxid, setStepIndex]) const renderBridgeConfirm = useCallback(() => { if (!maybeBridgeQuote) return null diff --git a/src/pages/RFOX/components/Stake/StakeInput.tsx b/src/pages/RFOX/components/Stake/StakeInput.tsx index 0beb3999cba..c563a6eb624 100644 --- a/src/pages/RFOX/components/Stake/StakeInput.tsx +++ b/src/pages/RFOX/components/Stake/StakeInput.tsx @@ -27,8 +27,10 @@ import { useWallet } from 'hooks/useWallet/useWallet' import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain' import { bnOrZero } from 'lib/bignumber/bignumber' import { toBaseUnit } from 'lib/math' +import { selectRuneAddress } from 'pages/RFOX/helpers' import { useCooldownPeriodQuery } from 'pages/RFOX/hooks/useCooldownPeriodQuery' import { useRFOXContext } from 'pages/RFOX/hooks/useRfoxContext' +import { useStakingInfoQuery } from 'pages/RFOX/hooks/useStakingInfoQuery' import { marketApi } from 'state/slices/marketDataSlice/marketDataSlice' import { selectAssetById, @@ -79,11 +81,19 @@ export const StakeInput: React.FC = ({ onRuneAddressChange, runeAddress, setConfirmedQuote, + setStepIndex, }) => { const assetIds = useMemo(() => [stakingAssetId, l1AssetId], [l1AssetId, stakingAssetId]) const { selectedAssetId, setSelectedAssetId, selectedAssetAccountId, stakingAssetAccountId } = useRFOXContext() + const { data: currentRuneAddress } = useStakingInfoQuery({ + stakingAssetAccountAddress: stakingAssetAccountId + ? fromAccountId(stakingAssetAccountId).account + : undefined, + select: selectRuneAddress, + }) + const isAccountMetadataLoading = useAppSelector(selectIsAccountMetadataLoading) const isBridgeRequired = stakingAssetId !== selectedAssetId const dispatch = useAppDispatch() @@ -206,7 +216,7 @@ export const StakeInput: React.FC = ({ }, } = useRfoxStake({ amountCryptoBaseUnit, - runeAddress, + runeAddress: currentRuneAddress || runeAddress, stakingAssetId, stakingAssetAccountId, hasEnoughBalance, @@ -238,7 +248,7 @@ export const StakeInput: React.FC = ({ !( selectedAssetAccountId && stakingAssetAccountId && - runeAddress && + (runeAddress || currentRuneAddress) && selectedAsset && stakingAsset && isValidStakingAmount @@ -250,7 +260,8 @@ export const StakeInput: React.FC = ({ stakingAssetAccountId, stakingAssetId, stakingAmountCryptoBaseUnit: toBaseUnit(amountCryptoPrecision, stakingAsset.precision), - runeAddress, + // typescript is borked, one of them is defined because of the early return + runeAddress: currentRuneAddress || runeAddress || '', } setConfirmedQuote(_confirmedQuote) @@ -280,6 +291,7 @@ export const StakeInput: React.FC = ({ isBridgeRequired, history, selectedAssetId, + currentRuneAddress, ]) const buyAssetSearch = useModal('buyAssetSearch') @@ -488,6 +500,7 @@ export const StakeInput: React.FC = ({ {stakingAssetAccountId && ( @@ -542,7 +555,7 @@ export const StakeInput: React.FC = ({ isValidWallet={Boolean(isChainSupportedByWallet || isAccountMetadataLoading)} isDisabled={Boolean( errors.amountFieldInput || - !runeAddress || + (!runeAddress && !currentRuneAddress) || !isValidStakingAmount || !(isStakeFeesSuccess || isGetApprovalFeesSuccess) || isAccountMetadataLoading || diff --git a/src/pages/RFOX/components/Stake/types.ts b/src/pages/RFOX/components/Stake/types.ts index 86a4ec43458..38e8cdaa3a0 100644 --- a/src/pages/RFOX/components/Stake/types.ts +++ b/src/pages/RFOX/components/Stake/types.ts @@ -10,6 +10,7 @@ export enum StakeRoutePaths { export type StakeRouteProps = { headerComponent?: JSX.Element + setStepIndex: (index: number) => void } export type RfoxStakingQuote = {