From 5822c8d14de4f11c9f2ed15f042d3b65a97d0207 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sun, 2 Oct 2022 21:45:42 +0200 Subject: [PATCH 01/41] Refactor mapping to not use redux store We decided that we don't have to store the data related to operator mapping in the redux store. This commit adds that. I've also commented out `OperatorAddressMappingCard`. This card will be addressed in the future commits when working on subcribtion to "OperatorRegistered" event --- .../index.tsx | 30 ++-- .../MapOperatorToStakingProviderForm.tsx | 26 +-- .../index.tsx | 38 ++-- src/hooks/staking-applications/index.ts | 1 - ...eOperatorMappedToStakingProviderHelpers.ts | 42 ----- .../useOperatorsMappedToStakingProvider.ts | 8 - ...useRegisterMultipleOperatorsTransaction.ts | 30 ++-- src/hooks/useRolesOf.ts | 11 -- .../Staking/OperatorAddressMappingCard.tsx | 12 +- src/pages/Staking/index.tsx | 62 +++---- .../connectedAccountSlice.ts | 48 ++--- src/store/connected-account/effects.ts | 29 --- src/store/connected-account/index.ts | 1 - src/store/staking-applications/effects.ts | 170 +++++++----------- src/store/staking-applications/slice.ts | 74 +------- src/threshold-ts/mas/__test__/mas.test.ts | 38 ++++ src/threshold-ts/mas/index.ts | 32 ++++ 17 files changed, 265 insertions(+), 387 deletions(-) delete mode 100644 src/hooks/staking-applications/useOperatorMappedToStakingProviderHelpers.ts delete mode 100644 src/hooks/staking-applications/useOperatorsMappedToStakingProvider.ts delete mode 100644 src/hooks/useRolesOf.ts delete mode 100644 src/store/connected-account/effects.ts diff --git a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx index dee189bd9..ac515c3fd 100644 --- a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx @@ -9,25 +9,19 @@ import { ModalHeader, } from "@chakra-ui/react" import { AddressZero } from "@ethersproject/constants" -import { - BodyLg, - BodyMd, - BodySm, - H5, - LabelSm, -} from "@threshold-network/components" +import { BodyLg, BodyMd, H5, LabelSm } from "@threshold-network/components" import { useWeb3React } from "@web3-react/core" import { ContractTransaction } from "ethers" import { FC, useCallback } from "react" import { useDispatch } from "react-redux" import { ModalType } from "../../../enums" -import { useOperatorMappedtoStakingProviderHelpers } from "../../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" import { useRegisterMultipleOperatorsTransaction } from "../../../hooks/staking-applications/useRegisterMultipleOperatorsTransaction" import { useRegisterOperatorTransaction } from "../../../hooks/staking-applications/useRegisterOperatorTransaction" import { useModal } from "../../../hooks/useModal" import StakeAddressInfo from "../../../pages/Staking/StakeCard/StakeAddressInfo" import { mapOperatorToStakingProviderModalClosed } from "../../../store/modalQueue" import { BaseModalProps } from "../../../types" +import { isAddressZero } from "../../../web3/utils" import InfoBox from "../../InfoBox" import withBaseModal from "../withBaseModal" @@ -60,17 +54,27 @@ const OperatorMappingConfirmation: FC< const MapOperatorToStakingProviderConfirmationModal: FC< BaseModalProps & { operator: string + mappedOperatorTbtc: string + mappedOperatorRandomBeacon: string } -> = ({ operator, closeModal }) => { +> = ({ + operator, + mappedOperatorTbtc, + mappedOperatorRandomBeacon, + closeModal, +}) => { const { account } = useWeb3React() const { registerMultipleOperators } = useRegisterMultipleOperatorsTransaction() const dispatch = useDispatch() - const operatorMappedToStakingProviderHelpers = - useOperatorMappedtoStakingProviderHelpers() - const { isOperatorMappedOnlyInRandomBeacon, isOperatorMappedOnlyInTbtc } = - operatorMappedToStakingProviderHelpers + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) const { openModal } = useModal() const onSuccess = useCallback( diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx index dd95f4b4e..d531eb5b7 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx @@ -2,7 +2,7 @@ import { FC, Ref } from "react" import { FormikProps, FormikErrors, withFormik } from "formik" import { Form, FormikInput } from "../../Forms" import { getErrorsObj, validateETHAddress } from "../../../utils/forms" -import { OperatorMappedToStakingProviderHelpers } from "../../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" +import { isAddressZero } from "../../../web3/utils" export interface MapOperatorToStakingProviderFormValues { operator: string @@ -28,8 +28,9 @@ const MapOperatorToStakingProviderFormBase: FC< type MapOperatorToStakingProviderFormProps = { initialAddress: string + mappedOperatorTbtc: string + mappedOperatorRandomBeacon: string innerRef: Ref> - operatorMappedToStakingProviderHelpers: OperatorMappedToStakingProviderHelpers checkIfOperatorIsMappedToAnotherStakingProvider: ( operator: string ) => Promise @@ -45,15 +46,18 @@ const MapOperatorToStakingProviderForm = withFormik< }), validate: async (values, props) => { const { + mappedOperatorTbtc, + mappedOperatorRandomBeacon, checkIfOperatorIsMappedToAnotherStakingProvider, - operatorMappedToStakingProviderHelpers, } = props - const { - operatorMappedRandomBeacon, - operatorMappedTbtc, - isOperatorMappedOnlyInRandomBeacon, - isOperatorMappedOnlyInTbtc, - } = operatorMappedToStakingProviderHelpers + + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) const errors: FormikErrors = {} errors.operator = validateETHAddress(values.operator) @@ -69,14 +73,14 @@ const MapOperatorToStakingProviderForm = withFormik< } if ( isOperatorMappedOnlyInRandomBeacon && - values.operator !== operatorMappedRandomBeacon + values.operator !== mappedOperatorRandomBeacon ) { validationMsg = "The operator address doesn't match the one used in tbtc app" } if ( isOperatorMappedOnlyInTbtc && - values.operator !== operatorMappedTbtc + values.operator !== mappedOperatorTbtc ) { validationMsg = "The operator address doesn't match the one used in random beacon app" diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx index 8e88e6217..6c34a6397 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx @@ -28,29 +28,38 @@ import { useWeb3React } from "@web3-react/core" import { AddressZero } from "@ethersproject/constants" import { useThreshold } from "../../../contexts/ThresholdContext" import { isAddressZero, isSameETHAddress } from "../../../web3/utils" -import { useOperatorMappedtoStakingProviderHelpers } from "../../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" -const MapOperatorToStakingProviderModal: FC = () => { +export interface MapOperatorToStakingProviderModalProps { + stakingProvider: string + mappedOperatorTbtc: string + mappedOperatorRandomBeacon: string +} + +const MapOperatorToStakingProviderModal: FC< + BaseModalProps & MapOperatorToStakingProviderModalProps +> = ({ stakingProvider, mappedOperatorTbtc, mappedOperatorRandomBeacon }) => { const { account } = useWeb3React() - const operatorMappedToStakingProviderHelpers = - useOperatorMappedtoStakingProviderHelpers() - const { - isOperatorMappedOnlyInRandomBeacon, - isOperatorMappedOnlyInTbtc, - operatorMappedRandomBeacon, - operatorMappedTbtc, - } = operatorMappedToStakingProviderHelpers const formRef = useRef>(null) const { closeModal, openModal } = useModal() const threshold = useThreshold() + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) + const onSubmit = async ({ operator, }: MapOperatorToStakingProviderFormValues) => { if (account) { openModal(ModalType.MapOperatorToStakingProviderConfirmation, { operator, + mappedOperatorTbtc, + mappedOperatorRandomBeacon, }) } } @@ -118,18 +127,17 @@ const MapOperatorToStakingProviderModal: FC = () => { formId="map-operator-to-staking-provider-form" initialAddress={ isOperatorMappedOnlyInRandomBeacon - ? operatorMappedRandomBeacon + ? mappedOperatorRandomBeacon : isOperatorMappedOnlyInTbtc - ? operatorMappedTbtc + ? mappedOperatorTbtc : "" } onSubmitForm={onSubmit} checkIfOperatorIsMappedToAnotherStakingProvider={ checkIfOperatorIsMappedToAnotherStakingProvider } - operatorMappedToStakingProviderHelpers={ - operatorMappedToStakingProviderHelpers - } + mappedOperatorTbtc={mappedOperatorTbtc} + mappedOperatorRandomBeacon={mappedOperatorRandomBeacon} /> OperatorMappedToStakingProviderHelpers = - () => { - const operatorMappedRandomBeacon = - useOperatorsMappedToStakingProvider("randomBeacon") - const operatorMappedTbtc = useOperatorsMappedToStakingProvider("tbtc") - const isInitiallyFetchedRandomBeacon = - useStakingApplicationState("randomBeacon").mappedOperator - .isInitialFetchDone - const isInitiallyFetchedTbtc = - useStakingApplicationState("tbtc").mappedOperator.isInitialFetchDone - - const isOperatorMappedOnlyInTbtc = - isAddressZero(operatorMappedRandomBeacon) && - !isAddressZero(operatorMappedTbtc) - const isOperatorMappedOnlyInRandomBeacon = - !isAddressZero(operatorMappedRandomBeacon) && - isAddressZero(operatorMappedTbtc) - - const isInitialFetchDone = - !!isInitiallyFetchedRandomBeacon && !!isInitiallyFetchedTbtc - - return { - operatorMappedRandomBeacon, - operatorMappedTbtc, - isOperatorMappedOnlyInTbtc, - isOperatorMappedOnlyInRandomBeacon, - isInitialFetchDone, - } - } diff --git a/src/hooks/staking-applications/useOperatorsMappedToStakingProvider.ts b/src/hooks/staking-applications/useOperatorsMappedToStakingProvider.ts deleted file mode 100644 index 29eeaa5aa..000000000 --- a/src/hooks/staking-applications/useOperatorsMappedToStakingProvider.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { StakingAppName } from "../../store/staking-applications" -import { useStakingApplicationState } from "./useStakingApplicationState" - -export const useOperatorsMappedToStakingProvider = ( - appName: StakingAppName -) => { - return useStakingApplicationState(appName).mappedOperator.data -} diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index b1f3d173c..031aa0af8 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -3,16 +3,17 @@ import { isAddressZero } from "../../web3/utils" import { useRegisterOperatorTransaction } from "./useRegisterOperatorTransaction" import { useModal } from "../useModal" import { ModalType } from "../../enums" -import { useOperatorMappedtoStakingProviderHelpers } from "./useOperatorMappedToStakingProviderHelpers" import { useWeb3React } from "@web3-react/core" import { OperatorMappedSuccessTx } from "../../components/Modal/MapOperatorToStakingProviderSuccessModal" import { mapOperatorToStakingProviderModalClosed } from "../../store/modalQueue" import { useDispatch } from "react-redux" +import { useThreshold } from "../../contexts/ThresholdContext" export const useRegisterMultipleOperatorsTransaction = () => { const { account } = useWeb3React() const { openModal, closeModal } = useModal() const dispatch = useDispatch() + const threshold = useThreshold() const { sendTransaction: sendRegisterOperatorTransactionTbtc, @@ -23,25 +24,34 @@ export const useRegisterMultipleOperatorsTransaction = () => { status: registerOperatorRandomBeaconStatus, } = useRegisterOperatorTransaction("randomBeacon") - const { - operatorMappedRandomBeacon, - operatorMappedTbtc, - isOperatorMappedOnlyInRandomBeacon, - isOperatorMappedOnlyInTbtc, - } = useOperatorMappedtoStakingProviderHelpers() - const registerMultipleOperators = useCallback( async (operator: string) => { try { if (!account) { throw new Error("Connect to the staking provider account first!") } + + const { + tbtc: mappedOperatorTbtc, + randomBeacon: mappedOperatorRandomBeacon, + } = await threshold.multiAppStaking.getMappedOperatorsForStakingProvider( + account + ) + if ( - !isAddressZero(operatorMappedRandomBeacon) && - !isAddressZero(operatorMappedTbtc) + !isAddressZero(mappedOperatorRandomBeacon) && + !isAddressZero(mappedOperatorTbtc) ) throw new Error("Both apps already have mapped operator!") + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) + if (isOperatorMappedOnlyInRandomBeacon) throw new Error("Random beacon app already has mapped operator!") diff --git a/src/hooks/useRolesOf.ts b/src/hooks/useRolesOf.ts deleted file mode 100644 index d6074d72e..000000000 --- a/src/hooks/useRolesOf.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useSelector } from "react-redux" -import { RootState } from "../store" -import { RolesOf } from "../threshold-ts/staking" - -export const useRolesOf: () => RolesOf = () => { - const rolesOf = useSelector( - (state: RootState) => state.connectedAccount.rolesOf - ) - - return rolesOf -} diff --git a/src/pages/Staking/OperatorAddressMappingCard.tsx b/src/pages/Staking/OperatorAddressMappingCard.tsx index 7caf47ce7..b1fc91a8e 100644 --- a/src/pages/Staking/OperatorAddressMappingCard.tsx +++ b/src/pages/Staking/OperatorAddressMappingCard.tsx @@ -9,15 +9,17 @@ import { } from "@threshold-network/components" import { LabelSm } from "@threshold-network/components" import { ModalType } from "../../enums" -import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" +// import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" import { useModal } from "../../hooks/useModal" +//TODO: Fix this const OperatorAddressMappingCard = () => { const { openModal } = useModal() - const { isOperatorMappedOnlyInRandomBeacon, isOperatorMappedOnlyInTbtc } = - useOperatorMappedtoStakingProviderHelpers() - const isOneOfTheAppsNotMapped = - isOperatorMappedOnlyInRandomBeacon || isOperatorMappedOnlyInTbtc + // const { isOperatorMappedOnlyInRandomBeacon, isOperatorMappedOnlyInTbtc } = + // useOperatorMappedtoStakingProviderHelpers() + // const isOneOfTheAppsNotMapped = + // isOperatorMappedOnlyInRandomBeacon || isOperatorMappedOnlyInTbtc + const isOneOfTheAppsNotMapped = false const onStartMappingClick = () => { openModal(ModalType.MapOperatorToStakingProvider) diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 3d8f6627a..29a5a7747 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -27,8 +27,8 @@ import { stakingApplicationsSlice } from "../../store/staking-applications/slice import StakeDetailsPage from "./StakeDetailsPage" import NewStakeCard from "./NewStakeCard" import OperatorAddressMappingCard from "./OperatorAddressMappingCard" -import { useRolesOf } from "../../hooks/useRolesOf" -import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" +// import { useRolesOf } from "../../hooks/useRolesOf" +// import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" import { isEmptyOrZeroAddress } from "../../web3/utils" const StakingPage: PageComponent = (props) => { @@ -47,32 +47,34 @@ const StakingPage: PageComponent = (props) => { const totalBonusBalance = useSelector(selectTotalBonusBalance) const hasStakes = stakes.length > 0 - const { owner, authorizer, beneficiary } = useRolesOf() - const { operatorMappedRandomBeacon, operatorMappedTbtc, isInitialFetchDone } = - useOperatorMappedtoStakingProviderHelpers() - - const shouldDisplayOperatorAddressMappingCard = useMemo(() => { - const isStakingProviderUsed = - !isEmptyOrZeroAddress(owner) || - !isEmptyOrZeroAddress(authorizer) || - !isEmptyOrZeroAddress(beneficiary) - - const isOperatorMappedInAllApps = - !isEmptyOrZeroAddress(operatorMappedRandomBeacon) && - !isEmptyOrZeroAddress(operatorMappedTbtc) - - return ( - isInitialFetchDone && isStakingProviderUsed && !isOperatorMappedInAllApps - ) - }, [ - owner, - authorizer, - beneficiary, - operatorMappedRandomBeacon, - operatorMappedTbtc, - isInitialFetchDone, - isEmptyOrZeroAddress, - ]) + // TODO: fix this + + // const { owner, authorizer, beneficiary } = useRolesOf() + // const { operatorMappedRandomBeacon, operatorMappedTbtc, isInitialFetchDone } = + // useOperatorMappedtoStakingProviderHelpers() + + // const shouldDisplayOperatorAddressMappingCard = useMemo(() => { + // const isStakingProviderUsed = + // !isEmptyOrZeroAddress(owner) || + // !isEmptyOrZeroAddress(authorizer) || + // !isEmptyOrZeroAddress(beneficiary) + + // const isOperatorMappedInAllApps = + // !isEmptyOrZeroAddress(operatorMappedRandomBeacon) && + // !isEmptyOrZeroAddress(operatorMappedTbtc) + + // return ( + // isInitialFetchDone && isStakingProviderUsed && !isOperatorMappedInAllApps + // ) + // }, [ + // owner, + // authorizer, + // beneficiary, + // operatorMappedRandomBeacon, + // operatorMappedTbtc, + // isInitialFetchDone, + // isEmptyOrZeroAddress, + // ]) return ( @@ -90,9 +92,9 @@ const StakingPage: PageComponent = (props) => { > Your Stake - {shouldDisplayOperatorAddressMappingCard && ( + {/* {shouldDisplayOperatorAddressMappingCard && ( - )} + )} */} {hasStakes ? ( stakes.map((stake) => ( diff --git a/src/store/connected-account/connectedAccountSlice.ts b/src/store/connected-account/connectedAccountSlice.ts index 0a1dd0398..47e971dc4 100644 --- a/src/store/connected-account/connectedAccountSlice.ts +++ b/src/store/connected-account/connectedAccountSlice.ts @@ -1,28 +1,14 @@ import { AnyAction, createSlice, PayloadAction } from "@reduxjs/toolkit" -import { RolesOf } from "../../threshold-ts/staking" -import { isSameETHAddress } from "../../web3/utils" -import { startAppListening } from "../listener" -import { - providerStaked, - providerStakedForStakingProvider, - setStakes, -} from "../staking" -import { getRolesOf } from "./effects" +import { providerStaked, providerStakedForStakingProvider } from "../staking" interface ConnectedAccountState { address: string - rolesOf: RolesOf } export const connectedAccountSlice = createSlice({ name: "connected-account", initialState: { address: "", - rolesOf: { - owner: "", - authorizer: "", - beneficiary: "", - }, } as ConnectedAccountState, reducers: { setConnectedAccountAddress: ( @@ -31,14 +17,6 @@ export const connectedAccountSlice = createSlice({ ) => { state.address = action.payload }, - setRolesOf: ( - state: ConnectedAccountState, - action: PayloadAction - ) => { - state.rolesOf.owner = action.payload.owner - state.rolesOf.authorizer = action.payload.authorizer - state.rolesOf.beneficiary = action.payload.beneficiary - }, }, extraReducers: (builder) => { builder.addMatcher( @@ -50,22 +28,18 @@ export const connectedAccountSlice = createSlice({ const { address } = state - if (isSameETHAddress(stakingProvider, address)) { - state.rolesOf = { - owner, - beneficiary, - authorizer, - } - } + // TODO: Fix this when refactoring "Staked" listener for provider + + // if (isSameETHAddress(stakingProvider, address)) { + // state.rolesOf = { + // owner, + // beneficiary, + // authorizer, + // } + // } } ) }, }) -startAppListening({ - actionCreator: setStakes, - effect: getRolesOf, -}) - -export const { setConnectedAccountAddress, setRolesOf } = - connectedAccountSlice.actions +export const { setConnectedAccountAddress } = connectedAccountSlice.actions diff --git a/src/store/connected-account/effects.ts b/src/store/connected-account/effects.ts deleted file mode 100644 index 25ad46433..000000000 --- a/src/store/connected-account/effects.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AnyAction } from "@reduxjs/toolkit" -import { AppListenerEffectAPI } from "../listener" -import { setRolesOf } from "./connectedAccountSlice" - -export const getRolesOf = async ( - action: AnyAction, - listenerApi: AppListenerEffectAPI -) => { - try { - const { connectedAccount } = listenerApi.getState() - const { address } = connectedAccount - - if (address) { - listenerApi.unsubscribe() - const { owner, authorizer, beneficiary } = - await listenerApi.extra.threshold.staking.rolesOf(address) - listenerApi.dispatch( - setRolesOf({ - owner, - authorizer, - beneficiary, - }) - ) - } - } catch (error) { - console.log("Could not fetch roles for connected staking provider: ", error) - listenerApi.subscribe() - } -} diff --git a/src/store/connected-account/index.ts b/src/store/connected-account/index.ts index 65a027d83..f0be16c93 100644 --- a/src/store/connected-account/index.ts +++ b/src/store/connected-account/index.ts @@ -1,2 +1 @@ export * from "./connectedAccountSlice" -export * from "./effects" diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index fadafbd91..dc1390d55 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -17,8 +17,7 @@ import { selectStakingAppByStakingProvider, selectStakingAppStateByAppName, } from "./selectors" -import { isAddressZero } from "../../web3/utils" -import { featureFlags } from "../../constants" +import { isAddressZero, isSameETHAddress } from "../../web3/utils" import { mapOperatorToStakingProviderModalClosed } from "../modalQueue" export const getSupportedAppsEffect = async ( @@ -168,114 +167,85 @@ const getKeepStakingAppStakingProvidersData = async ( } } -export const getMappedOperatorsEffect = async ( - action: AnyAction, - listenerApi: AppListenerEffectAPI -) => { - try { - const { connectedAccount } = listenerApi.getState() - const { address } = connectedAccount - - if (address) { - listenerApi.unsubscribe() - getMappedOperatorEffect(address, "randomBeacon", listenerApi) - getMappedOperatorEffect(address, "tbtc", listenerApi) - } - } catch (error) { - console.log( - "Could not fetch mapped operator for connected staking provider: ", - error - ) - listenerApi.subscribe() - } -} - -const getMappedOperatorEffect = async ( - stakingProvider: string, - appName: StakingAppName, - listenerApi: AppListenerEffectAPI -) => { - try { - listenerApi.dispatch( - stakingApplicationsSlice.actions.fetchingMappedOperator({ - appName, - }) - ) - const appNameProp = appName === "tbtc" ? "ecdsa" : appName - if (stakingProvider) { - const operatorMapped = await listenerApi.extra.threshold.multiAppStaking[ - appNameProp - ].stakingProviderToOperator(stakingProvider) - listenerApi.dispatch( - stakingApplicationsSlice.actions.setMappedOperator({ - appName: appName, - operator: operatorMapped, - }) - ) - listenerApi.dispatch( - stakingApplicationsSlice.actions.setMappedOperatorInitialFetch({ - appName: appName, - value: true, - }) - ) - } - } catch (error) { - listenerApi.dispatch( - stakingApplicationsSlice.actions.setStakingProvidersAppDataError({ - appName, - error: (error as Error).toString(), - }) - ) - throw error - } -} - export const displayMapOperatorToStakingProviderModalEffect = async ( action: AnyAction, listenerApi: AppListenerEffectAPI ) => { - const { connectedAccount } = listenerApi.getState() + const result = await listenerApi.condition((action, currentState: any) => { + return currentState.modalQueue.isSuccessfullLoginModalClosed + }) + const { connectedAccount, staking } = listenerApi.getState() const { address } = connectedAccount if (address) { - // check if the current connected address is used somewhere as a staking - // provider listenerApi.unsubscribe() - const { owner, authorizer, beneficiary } = - await listenerApi.extra.threshold.staking.rolesOf(address) + try { + const { stakes } = staking + let stakingProvider + + // Check if connected account is a staking provider in a current set of + // stakes saved in the state. Since we keep the stakes from the owner + // perspective this means that we are checking is there are stake for this + // connected account where owner === stakingProvider + const stake = stakes.find((stake) => + isSameETHAddress(stake.stakingProvider, address) + ) + + if (stake) { + // If there is such stake we are getting it's staking provider + stakingProvider = stake.stakingProvider + } else { + // If there is not such stakes we are checking if connected account is + // used as a staking provider in other stakes where it's not an owner. + const { owner, authorizer, beneficiary } = + await listenerApi.extra.threshold.staking.rolesOf(address) + + if ( + !isAddressZero(owner) && + !isAddressZero(authorizer) && + !isAddressZero(beneficiary) + ) { + // If such stakes exist then wer are getting a staking provider + stakingProvider = address + } + } + + if (stakingProvider) { + // get mapped operators for all apps for given staking provider + const mappedOperators = + await listenerApi.extra.threshold.multiAppStaking.getMappedOperatorsForStakingProvider( + address + ) - if ( - !isAddressZero(owner) || - !isAddressZero(authorizer) || - !isAddressZero(beneficiary) - ) { - if (featureFlags.MULTI_APP_STAKING) { - listenerApi.dispatch( - openModal({ modalType: ModalType.MapOperatorToStakingProvider }) - ) + if ( + isAddressZero(mappedOperators.tbtc) || + isAddressZero(mappedOperators.randomBeacon) + ) { + // If staking provider does not have operator mapped for all apps we + // are displaying him the `MapOperatorToStakingProvider` modal + listenerApi.dispatch( + openModal({ + modalType: ModalType.MapOperatorToStakingProvider, + props: { + stakingProvider, + mappedOperatorTbtc: mappedOperators.tbtc, + mappedOperatorRandomBeacon: mappedOperators.randomBeacon, + }, + }) + ) + } else { + listenerApi.dispatch(mapOperatorToStakingProviderModalClosed()) + } } + } catch (error) { + console.log( + "Could not fetch info about mapped operators for given staking provider:", + error + ) + listenerApi.subscribe() } } } -export const shouldDisplayMapOperatorToStakingProviderModal = ( - action: AnyAction, - currentState: RootState, - previousState: RootState -) => { - return ( - !!currentState.connectedAccount.address && - currentState.modalQueue.isSuccessfullLoginModalClosed && - (currentState.applications.randomBeacon.mappedOperator - .isInitialFetchDone as boolean) && - (currentState.applications.tbtc.mappedOperator - .isInitialFetchDone as boolean) && - (isAddressZero( - currentState.applications.randomBeacon.mappedOperator.data - ) || - isAddressZero(currentState.applications.tbtc.mappedOperator.data)) - ) -} - export const displayNewAppsToAuthorizeModalEffect = async ( action: AnyAction, listenerApi: AppListenerEffectAPI @@ -309,11 +279,7 @@ export const shouldDisplayNewAppsToAuthorizeModal = ( ) => { return ( currentState.modalQueue.isSuccessfullLoginModalClosed && - (currentState.modalQueue.isMappingOperatorToStakingProviderModalClosed || - (!isAddressZero( - currentState.applications.randomBeacon.mappedOperator.data - ) && - !isAddressZero(currentState.applications.tbtc.mappedOperator.data))) && + currentState.modalQueue.isMappingOperatorToStakingProviderModalClosed && Object.values( currentState.applications.randomBeacon.stakingProviders.data ?? {} ).length > 0 && diff --git a/src/store/staking-applications/slice.ts b/src/store/staking-applications/slice.ts index aa0c8d393..944df13ba 100644 --- a/src/store/staking-applications/slice.ts +++ b/src/store/staking-applications/slice.ts @@ -13,8 +13,6 @@ import { providerStaked, setStakes } from "../staking" import { getSupportedAppsStakingProvidersData, getSupportedAppsEffect, - getMappedOperatorsEffect, - shouldDisplayMapOperatorToStakingProviderModal, displayMapOperatorToStakingProviderModalEffect, shouldDisplayNewAppsToAuthorizeModal, displayNewAppsToAuthorizeModalEffect, @@ -29,7 +27,6 @@ type StakingApplicationDataByStakingProvider = { export type StakingApplicationState = { parameters: FetchingState> stakingProviders: FetchingState - mappedOperator: FetchingState } export interface StakingApplicationsState { @@ -57,12 +54,6 @@ export const stakingApplicationsSlice = createSlice({ error: "", data: {}, }, - mappedOperator: { - isInitialFetchDone: false, - isFetching: false, - error: "", - data: AddressZero, - }, }, randomBeacon: { parameters: { @@ -79,12 +70,6 @@ export const stakingApplicationsSlice = createSlice({ error: "", data: {}, }, - mappedOperator: { - isInitialFetchDone: false, - isFetching: false, - error: "", - data: AddressZero, - }, }, } as StakingApplicationsState, reducers: { @@ -152,52 +137,6 @@ export const stakingApplicationsSlice = createSlice({ state[appName].stakingProviders.isFetching = false state[appName].stakingProviders.error = error }, - fetchMappedOperators: (state: StakingApplicationsState, action) => {}, - setMappedOperator: ( - state: StakingApplicationsState, - action: PayloadAction<{ - appName: StakingAppName - operator: string - }> - ) => { - const { appName, operator } = action.payload - state[appName].mappedOperator = { - ...state[appName].mappedOperator, - isFetching: false, - error: "", - data: operator, - } - }, - setMappedOperatorInitialFetch: ( - state: StakingApplicationsState, - action: PayloadAction<{ - appName: StakingAppName - value: boolean - }> - ) => { - const { appName, value } = action.payload - state[appName].mappedOperator.isInitialFetchDone = value - }, - fetchingMappedOperator: ( - state: StakingApplicationsState, - action: PayloadAction<{ - appName: StakingAppName - }> - ) => { - const { appName } = action.payload - state[appName].mappedOperator.isFetching = true - }, - setMappedOperatorError: ( - state: StakingApplicationsState, - action: PayloadAction<{ - appName: StakingAppName - error: string - }> - ) => { - const { appName, error } = action.payload - state[appName].mappedOperator.isFetching = false - state[appName].mappedOperator.error = error - }, operatorMapped: ( state: StakingApplicationsState, action: PayloadAction<{ @@ -206,7 +145,8 @@ export const stakingApplicationsSlice = createSlice({ }> ) => { const { appName, operator } = action.payload - state[appName].mappedOperator.data = operator + // TODO: refactor this when refactoring subscribtion to + // `OperatorRegistered` event }, authorizationIncreased: ( state: StakingApplicationsState, @@ -349,16 +289,6 @@ export const registerStakingAppsListeners = () => { startAppListening({ actionCreator: setStakes, - effect: getMappedOperatorsEffect, - }) - - startAppListening({ - actionCreator: stakingApplicationsSlice.actions.fetchMappedOperators, - effect: getMappedOperatorsEffect, - }) - - startAppListening({ - predicate: shouldDisplayMapOperatorToStakingProviderModal, effect: displayMapOperatorToStakingProviderModalEffect, }) } diff --git a/src/threshold-ts/mas/__test__/mas.test.ts b/src/threshold-ts/mas/__test__/mas.test.ts index 0391219c9..88760890e 100644 --- a/src/threshold-ts/mas/__test__/mas.test.ts +++ b/src/threshold-ts/mas/__test__/mas.test.ts @@ -99,4 +99,42 @@ describe("Multi app staking test", () => { randomBeacon: randomBeaconAuthParams, }) }) + + test("should return mapped operators for given staking provider", async () => { + const mockStakingProvider = "0x3" + const mockOperator = "0x4" + const mappedOperatorTbtc = mockOperator + const mappedOperatorRandomBeacon = mockOperator + + const mulitcallMockResult = [ + [mappedOperatorTbtc], + [mappedOperatorRandomBeacon], + ] + const spyOnMulticall = jest + .spyOn(multicall, "aggregate") + .mockResolvedValue(mulitcallMockResult) + + const result = await mas.getMappedOperatorsForStakingProvider( + mockStakingProvider + ) + + expect(spyOnMulticall).toHaveBeenCalledWith([ + { + interface: mas.ecdsa.contract.interface, + address: mas.ecdsa.address, + method: "stakingProviderToOperator", + args: [mockStakingProvider], + }, + { + interface: mas.randomBeacon.contract.interface, + address: mas.randomBeacon.address, + method: "stakingProviderToOperator", + args: [mockStakingProvider], + }, + ]) + expect(result).toEqual({ + tbtc: mappedOperatorTbtc, + randomBeacon: mappedOperatorRandomBeacon, + }) + }) }) diff --git a/src/threshold-ts/mas/index.ts b/src/threshold-ts/mas/index.ts index 6eb324eac..f63a84e9c 100644 --- a/src/threshold-ts/mas/index.ts +++ b/src/threshold-ts/mas/index.ts @@ -14,6 +14,11 @@ export interface SupportedAppAuthorizationParameters { randomBeacon: AuthorizationParameters } +export interface MappedOperatorsForStakingProvider { + tbtc: string + randomBeacon: string +} + export class MultiAppStaking { private _staking: IStaking private _multicall: IMulticall @@ -63,4 +68,31 @@ export class MultiAppStaking { randomBeacon: randomBeaconMinAuthorizationParams, } } + + async getMappedOperatorsForStakingProvider( + stakingProvider: string + ): Promise { + const calls: ContractCall[] = [ + { + interface: this.ecdsa.contract.interface, + address: this.ecdsa.address, + method: "stakingProviderToOperator", + args: [stakingProvider], + }, + { + interface: this.randomBeacon.contract.interface, + address: this.randomBeacon.address, + method: "stakingProviderToOperator", + args: [stakingProvider], + }, + ] + + const [mappedOperatorTbtc, mappedOperatorRandomBeacon] = + await this._multicall.aggregate(calls) + + return { + tbtc: mappedOperatorTbtc.toString(), + randomBeacon: mappedOperatorRandomBeacon.toString(), + } + } } From 3dc60ea86d5900e844fddbf28147e9302835efc8 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sun, 2 Oct 2022 21:52:28 +0200 Subject: [PATCH 02/41] Fix display operator mapping effect There was a bug where when you close the login modal too quick, before `setStakes` action was dispatched, then the effect got blocked on `await listenerApi.condition` and was waiting for another action to dispatch and there were not any at that particular moment. To fix that I've added a condition to check if login modal was closed, if not, then we wait with the `condition()` function since the `displayMapOperatorToStakingProviderModalEffect` effect is run on a `setStakes` action, so we have all needed data fetcher already. --- src/store/staking-applications/effects.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index dc1390d55..616f98e4f 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -171,9 +171,12 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( action: AnyAction, listenerApi: AppListenerEffectAPI ) => { - const result = await listenerApi.condition((action, currentState: any) => { - return currentState.modalQueue.isSuccessfullLoginModalClosed - }) + const { modalQueue } = listenerApi.getState() + if (!modalQueue.isSuccessfullLoginModalClosed) { + await listenerApi.condition((action, currentState: any) => { + return currentState.modalQueue.isSuccessfullLoginModalClosed + }) + } const { connectedAccount, staking } = listenerApi.getState() const { address } = connectedAccount if (address) { From b09cf353b65c7a7d9be506e15b4cebd22837586f Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sun, 2 Oct 2022 22:43:21 +0200 Subject: [PATCH 03/41] Fix displaying modal when changing accounts Fix displaying operator mapping modal when changins accouns. The display of this modal is based on the condition that the user closed succesfull login modal. We store this flag in `modalQueue` redux store. When changing accounts this modal is not displayed thus the flag is not set. To fix that we wil set this flag to true when resetting redux store action is called. --- src/store/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/store/index.ts b/src/store/index.ts index d387d84ad..32941d15d 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -53,6 +53,11 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { T: { ...state.token.T, balance: 0 }, TBTC: { ...state.token.TBTC, balance: 0 }, }, + // we don't display successful login modal when changin account so we are + // setting this flag to true + modalQueue: { + isSuccessfullLoginModalClosed: true, + }, } as RootState } From ca8a09b2ec36808393c343214e752834a8223b8c Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sun, 2 Oct 2022 23:50:43 +0200 Subject: [PATCH 04/41] Add operatorMappingData to the store Adds data about operator mapping to the connectedAccount slice: { isUsedAsStakingProvider: boolean mappedOperator: { tbtc: string randomBeacon: string } } This data is neede to properly display the OperatorMappingCard that is on the Staking page. --- .../connectedAccountSlice.ts | 96 ++++++++++++++++--- src/store/connected-account/effects.ts | 66 +++++++++++++ src/store/index.ts | 6 +- src/store/staking-applications/effects.ts | 76 ++++----------- src/store/staking-applications/slice.ts | 3 +- 5 files changed, 178 insertions(+), 69 deletions(-) create mode 100644 src/store/connected-account/effects.ts diff --git a/src/store/connected-account/connectedAccountSlice.ts b/src/store/connected-account/connectedAccountSlice.ts index 47e971dc4..594e9b3ae 100644 --- a/src/store/connected-account/connectedAccountSlice.ts +++ b/src/store/connected-account/connectedAccountSlice.ts @@ -1,14 +1,41 @@ +import { AddressZero } from "@ethersproject/constants" import { AnyAction, createSlice, PayloadAction } from "@reduxjs/toolkit" -import { providerStaked, providerStakedForStakingProvider } from "../staking" +import { featureFlags } from "../../constants" +import { FetchingState } from "../../types" +import { isSameETHAddress } from "../../web3/utils" +import { startAppListening } from "../listener" +import { + providerStaked, + providerStakedForStakingProvider, + setStakes, +} from "../staking" +import { StakingAppName } from "../staking-applications" +import { getStakingProviderOperatorInfo } from "./effects" interface ConnectedAccountState { address: string + operatorMapping: FetchingState<{ + isUsedAsStakingProvider: boolean + mappedOperators: { + tbtc: string + randomBeacon: string + } + }> } export const connectedAccountSlice = createSlice({ name: "connected-account", initialState: { address: "", + operatorMapping: { + data: { + isUsedAsStakingProvider: false, + mappedOperators: { + tbtc: AddressZero, + randomBeacon: AddressZero, + }, + }, + }, } as ConnectedAccountState, reducers: { setConnectedAccountAddress: ( @@ -17,6 +44,42 @@ export const connectedAccountSlice = createSlice({ ) => { state.address = action.payload }, + accountUsedAsStakingProvider: ( + state: ConnectedAccountState, + action: PayloadAction + ) => { + state.operatorMapping.data.isUsedAsStakingProvider = true + }, + setMappedOperator: ( + state: ConnectedAccountState, + action: PayloadAction<{ + appName: StakingAppName + operator: string + }> + ) => { + const { appName, operator } = action.payload + state.operatorMapping.data.mappedOperators[appName] = operator + }, + setFetchingOperatorMapping: ( + state: ConnectedAccountState, + action: PayloadAction<{ isFetching: boolean }> + ) => { + const { isFetching } = action.payload + state.operatorMapping.isFetching = isFetching + }, + operatorMappingInitialFetchDone: ( + state: ConnectedAccountState, + action: PayloadAction + ) => { + state.operatorMapping.isInitialFetchDone = true + }, + setOperatorMappingError: ( + state: ConnectedAccountState, + action: PayloadAction<{ error: string }> + ) => { + const { error } = action.payload + state.operatorMapping.error = error + }, }, extraReducers: (builder) => { builder.addMatcher( @@ -28,18 +91,29 @@ export const connectedAccountSlice = createSlice({ const { address } = state - // TODO: Fix this when refactoring "Staked" listener for provider - - // if (isSameETHAddress(stakingProvider, address)) { - // state.rolesOf = { - // owner, - // beneficiary, - // authorizer, - // } - // } + if (isSameETHAddress(stakingProvider, address)) { + state.operatorMapping.data.isUsedAsStakingProvider = true + } } ) }, }) -export const { setConnectedAccountAddress } = connectedAccountSlice.actions +export const registerConnectedAccountListeners = () => { + if (featureFlags.MULTI_APP_STAKING) { + startAppListening({ + actionCreator: setStakes, + effect: getStakingProviderOperatorInfo, + }) + } +} +registerConnectedAccountListeners() + +export const { + setConnectedAccountAddress, + accountUsedAsStakingProvider, + setMappedOperator, + setFetchingOperatorMapping, + operatorMappingInitialFetchDone, + setOperatorMappingError, +} = connectedAccountSlice.actions diff --git a/src/store/connected-account/effects.ts b/src/store/connected-account/effects.ts new file mode 100644 index 000000000..c6816b302 --- /dev/null +++ b/src/store/connected-account/effects.ts @@ -0,0 +1,66 @@ +import { isZeroAddress } from "ethereumjs-util" +import { AppListenerEffectAPI } from "../listener" +import { setStakes } from "../staking" +import { + accountUsedAsStakingProvider, + connectedAccountSlice, + operatorMappingInitialFetchDone, + setFetchingOperatorMapping, + setMappedOperator, +} from "./connectedAccountSlice" + +export const getStakingProviderOperatorInfo = async ( + action: ReturnType, + listenerApi: AppListenerEffectAPI +) => { + try { + listenerApi.dispatch( + setFetchingOperatorMapping({ + isFetching: true, + }) + ) + const { connectedAccount } = listenerApi.getState() + const { address } = connectedAccount + const { owner, authorizer, beneficiary } = + await listenerApi.extra.threshold.staking.rolesOf(address) + + const isUsedAsStakingProvider = + !isZeroAddress(owner) && + !isZeroAddress(authorizer) && + !isZeroAddress(beneficiary) + + if (isUsedAsStakingProvider) { + listenerApi.dispatch(accountUsedAsStakingProvider()) + + const mappedOperators = + await listenerApi.extra.threshold.multiAppStaking.getMappedOperatorsForStakingProvider( + address + ) + + listenerApi.dispatch( + setMappedOperator({ + appName: "tbtc", + operator: mappedOperators.tbtc, + }) + ) + + listenerApi.dispatch( + setMappedOperator({ + appName: "randomBeacon", + operator: mappedOperators.randomBeacon, + }) + ) + + listenerApi.dispatch(setFetchingOperatorMapping({ isFetching: false })) + + listenerApi.dispatch(operatorMappingInitialFetchDone()) + } + } catch (error) { + listenerApi.dispatch( + connectedAccountSlice.actions.setFetchingOperatorMapping({ + isFetching: false, + }) + ) + throw new Error("Could not load staking provider's operator info: " + error) + } +} diff --git a/src/store/index.ts b/src/store/index.ts index 32941d15d..d77738053 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -17,7 +17,10 @@ import { stakingApplicationsSlice, } from "./staking-applications/slice" import { listenerMiddleware } from "./listener" -import { connectedAccountSlice } from "./connected-account" +import { + connectedAccountSlice, + registerConnectedAccountListeners, +} from "./connected-account" import { modalQueueSlice } from "./modalQueue" const combinedReducer = combineReducers({ @@ -45,6 +48,7 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { listenerMiddleware.clearListeners() registerStakingListeners() registerStakingAppsListeners() + registerConnectedAccountListeners() state = { eth: { ...state.eth }, token: { diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 616f98e4f..51adf4f92 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -172,72 +172,36 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( listenerApi: AppListenerEffectAPI ) => { const { modalQueue } = listenerApi.getState() + const { connectedAccount, staking } = listenerApi.getState() if (!modalQueue.isSuccessfullLoginModalClosed) { await listenerApi.condition((action, currentState: any) => { return currentState.modalQueue.isSuccessfullLoginModalClosed }) } - const { connectedAccount, staking } = listenerApi.getState() const { address } = connectedAccount - if (address) { + if (address && connectedAccount.operatorMapping.isInitialFetchDone) { listenerApi.unsubscribe() try { - const { stakes } = staking - let stakingProvider + const { isUsedAsStakingProvider, mappedOperators } = + connectedAccount.operatorMapping.data - // Check if connected account is a staking provider in a current set of - // stakes saved in the state. Since we keep the stakes from the owner - // perspective this means that we are checking is there are stake for this - // connected account where owner === stakingProvider - const stake = stakes.find((stake) => - isSameETHAddress(stake.stakingProvider, address) - ) - - if (stake) { - // If there is such stake we are getting it's staking provider - stakingProvider = stake.stakingProvider + if ( + isUsedAsStakingProvider && + (isAddressZero(mappedOperators.tbtc) || + isAddressZero(mappedOperators.randomBeacon)) + ) { + listenerApi.dispatch( + openModal({ + modalType: ModalType.MapOperatorToStakingProvider, + props: { + address, + mappedOperatorTbtc: mappedOperators.tbtc, + mappedOperatorRandomBeacon: mappedOperators.randomBeacon, + }, + }) + ) } else { - // If there is not such stakes we are checking if connected account is - // used as a staking provider in other stakes where it's not an owner. - const { owner, authorizer, beneficiary } = - await listenerApi.extra.threshold.staking.rolesOf(address) - - if ( - !isAddressZero(owner) && - !isAddressZero(authorizer) && - !isAddressZero(beneficiary) - ) { - // If such stakes exist then wer are getting a staking provider - stakingProvider = address - } - } - - if (stakingProvider) { - // get mapped operators for all apps for given staking provider - const mappedOperators = - await listenerApi.extra.threshold.multiAppStaking.getMappedOperatorsForStakingProvider( - address - ) - - if ( - isAddressZero(mappedOperators.tbtc) || - isAddressZero(mappedOperators.randomBeacon) - ) { - // If staking provider does not have operator mapped for all apps we - // are displaying him the `MapOperatorToStakingProvider` modal - listenerApi.dispatch( - openModal({ - modalType: ModalType.MapOperatorToStakingProvider, - props: { - stakingProvider, - mappedOperatorTbtc: mappedOperators.tbtc, - mappedOperatorRandomBeacon: mappedOperators.randomBeacon, - }, - }) - ) - } else { - listenerApi.dispatch(mapOperatorToStakingProviderModalClosed()) - } + listenerApi.dispatch(mapOperatorToStakingProviderModalClosed()) } } catch (error) { console.log( diff --git a/src/store/staking-applications/slice.ts b/src/store/staking-applications/slice.ts index 944df13ba..4c22aaff7 100644 --- a/src/store/staking-applications/slice.ts +++ b/src/store/staking-applications/slice.ts @@ -19,6 +19,7 @@ import { displayDeauthrizationCompletedModalEffect, displayDeauthrizationInitiatedModalEffect, } from "./effects" +import { operatorMappingInitialFetchDone } from "../connected-account" type StakingApplicationDataByStakingProvider = { [stakingProvider: string]: StakingProviderAppInfo @@ -288,7 +289,7 @@ export const registerStakingAppsListeners = () => { }) startAppListening({ - actionCreator: setStakes, + actionCreator: operatorMappingInitialFetchDone, effect: displayMapOperatorToStakingProviderModalEffect, }) } From c1694a09f67d9f820bf2478c10ee67621aee0428 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 3 Oct 2022 00:14:50 +0200 Subject: [PATCH 05/41] Fix displaying OperatorAddressMappingCard Gets the proper data from redux store and conditionally display OperatorAddressMappingCard in staking page --- .../Staking/OperatorAddressMappingCard.tsx | 27 +++++++--- src/pages/Staking/index.tsx | 49 ++++++------------- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/pages/Staking/OperatorAddressMappingCard.tsx b/src/pages/Staking/OperatorAddressMappingCard.tsx index b1fc91a8e..f299de0a6 100644 --- a/src/pages/Staking/OperatorAddressMappingCard.tsx +++ b/src/pages/Staking/OperatorAddressMappingCard.tsx @@ -8,21 +8,34 @@ import { HStack, } from "@threshold-network/components" import { LabelSm } from "@threshold-network/components" +import { FC } from "react" import { ModalType } from "../../enums" // import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" import { useModal } from "../../hooks/useModal" +import { isAddressZero } from "../../web3/utils" //TODO: Fix this -const OperatorAddressMappingCard = () => { +const OperatorAddressMappingCard: FC<{ + mappedOperatorTbtc: string + mappedOperatorRandomBeacon: string +}> = ({ mappedOperatorTbtc, mappedOperatorRandomBeacon }) => { const { openModal } = useModal() - // const { isOperatorMappedOnlyInRandomBeacon, isOperatorMappedOnlyInTbtc } = - // useOperatorMappedtoStakingProviderHelpers() - // const isOneOfTheAppsNotMapped = - // isOperatorMappedOnlyInRandomBeacon || isOperatorMappedOnlyInTbtc - const isOneOfTheAppsNotMapped = false + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) + + const isOneOfTheAppsNotMapped = + isOperatorMappedOnlyInRandomBeacon || isOperatorMappedOnlyInTbtc const onStartMappingClick = () => { - openModal(ModalType.MapOperatorToStakingProvider) + openModal(ModalType.MapOperatorToStakingProvider, { + mappedOperatorTbtc, + mappedOperatorRandomBeacon, + }) } return ( diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 29a5a7747..3e2f79cd2 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -27,9 +27,8 @@ import { stakingApplicationsSlice } from "../../store/staking-applications/slice import StakeDetailsPage from "./StakeDetailsPage" import NewStakeCard from "./NewStakeCard" import OperatorAddressMappingCard from "./OperatorAddressMappingCard" -// import { useRolesOf } from "../../hooks/useRolesOf" -// import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" -import { isEmptyOrZeroAddress } from "../../web3/utils" +import { isAddressZero } from "../../web3/utils" +import { RootState } from "../../store" const StakingPage: PageComponent = (props) => { const [data, fetchtTvlData] = useFetchTvl() @@ -47,34 +46,10 @@ const StakingPage: PageComponent = (props) => { const totalBonusBalance = useSelector(selectTotalBonusBalance) const hasStakes = stakes.length > 0 - // TODO: fix this - - // const { owner, authorizer, beneficiary } = useRolesOf() - // const { operatorMappedRandomBeacon, operatorMappedTbtc, isInitialFetchDone } = - // useOperatorMappedtoStakingProviderHelpers() - - // const shouldDisplayOperatorAddressMappingCard = useMemo(() => { - // const isStakingProviderUsed = - // !isEmptyOrZeroAddress(owner) || - // !isEmptyOrZeroAddress(authorizer) || - // !isEmptyOrZeroAddress(beneficiary) - - // const isOperatorMappedInAllApps = - // !isEmptyOrZeroAddress(operatorMappedRandomBeacon) && - // !isEmptyOrZeroAddress(operatorMappedTbtc) - - // return ( - // isInitialFetchDone && isStakingProviderUsed && !isOperatorMappedInAllApps - // ) - // }, [ - // owner, - // authorizer, - // beneficiary, - // operatorMappedRandomBeacon, - // operatorMappedTbtc, - // isInitialFetchDone, - // isEmptyOrZeroAddress, - // ]) + const { + isInitialFetchDone: isOperatorMappingInitialFetchDone, + data: { isUsedAsStakingProvider, mappedOperators }, + } = useSelector((state: RootState) => state.connectedAccount.operatorMapping) return ( @@ -92,9 +67,15 @@ const StakingPage: PageComponent = (props) => { > Your Stake - {/* {shouldDisplayOperatorAddressMappingCard && ( - - )} */} + {isUsedAsStakingProvider && + isOperatorMappingInitialFetchDone && + isAddressZero(mappedOperators.tbtc) && + isAddressZero(mappedOperators.randomBeacon) && ( + + )} {hasStakes ? ( stakes.map((stake) => ( From 6b98f5596a43f31aa8fadaf6683739a0d6d9e45d Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 3 Oct 2022 00:25:47 +0200 Subject: [PATCH 06/41] Rename and move operatorMapped event Move operatorMapped event to connectedAddress slice and rename it to operatorRegistered to indicate it's relation with `OperatorRegistered` event. --- .../useSubscribeToOperatorRegisteredEvent.ts | 21 ++++++++++--------- .../connectedAccountSlice.ts | 11 ++++++++++ src/store/staking-applications/slice.ts | 14 ------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts b/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts index 2f5b7dedd..697a68b7a 100644 --- a/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts +++ b/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts @@ -1,9 +1,8 @@ import { useWeb3React } from "@web3-react/core" -import { - operatorMapped, - StakingAppName, -} from "../../store/staking-applications" +import { operatorRegistered } from "../../store/connected-account" +import { StakingAppName } from "../../store/staking-applications" import { useSubscribeToContractEvent } from "../../web3/hooks" +import { isSameETHAddress } from "../../web3/utils" import { useAppDispatch } from "../store" import { useStakingAppContract } from "./useStakingAppContract" @@ -19,12 +18,14 @@ export const useSubscribeToOperatorRegisteredEvent = ( "OperatorRegistered", //@ts-ignore async (stakingProvider: string, operator: string) => { - dispatch( - operatorMapped({ - appName, - operator, - }) - ) + if (account && isSameETHAddress(stakingProvider, account)) { + dispatch( + operatorRegistered({ + appName, + operator, + }) + ) + } }, [account] ) diff --git a/src/store/connected-account/connectedAccountSlice.ts b/src/store/connected-account/connectedAccountSlice.ts index 594e9b3ae..feb786233 100644 --- a/src/store/connected-account/connectedAccountSlice.ts +++ b/src/store/connected-account/connectedAccountSlice.ts @@ -80,6 +80,16 @@ export const connectedAccountSlice = createSlice({ const { error } = action.payload state.operatorMapping.error = error }, + operatorRegistered: ( + state: ConnectedAccountState, + action: PayloadAction<{ + appName: StakingAppName + operator: string + }> + ) => { + const { appName, operator } = action.payload + state.operatorMapping.data.mappedOperators[appName] = operator + }, }, extraReducers: (builder) => { builder.addMatcher( @@ -116,4 +126,5 @@ export const { setFetchingOperatorMapping, operatorMappingInitialFetchDone, setOperatorMappingError, + operatorRegistered, } = connectedAccountSlice.actions diff --git a/src/store/staking-applications/slice.ts b/src/store/staking-applications/slice.ts index 4c22aaff7..f675bf04b 100644 --- a/src/store/staking-applications/slice.ts +++ b/src/store/staking-applications/slice.ts @@ -1,6 +1,5 @@ import { AnyAction, createSlice, PayloadAction } from "@reduxjs/toolkit" import { BigNumber } from "ethers" -import { AddressZero } from "@ethersproject/constants" import { featureFlags } from "../../constants" import { StakingProviderAppInfo, @@ -138,17 +137,6 @@ export const stakingApplicationsSlice = createSlice({ state[appName].stakingProviders.isFetching = false state[appName].stakingProviders.error = error }, - operatorMapped: ( - state: StakingApplicationsState, - action: PayloadAction<{ - appName: StakingAppName - operator: string - }> - ) => { - const { appName, operator } = action.payload - // TODO: refactor this when refactoring subscribtion to - // `OperatorRegistered` event - }, authorizationIncreased: ( state: StakingApplicationsState, action: PayloadAction<{ @@ -295,5 +283,3 @@ export const registerStakingAppsListeners = () => { } } registerStakingAppsListeners() - -export const { operatorMapped } = stakingApplicationsSlice.actions From 000ef3dea9fc55f734b35388f9b7d1fa50391a4e Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 3 Oct 2022 00:27:08 +0200 Subject: [PATCH 07/41] Remove unused prop `stakingProvider` prop was not used in `MapOperatorToStakingProviderModal` so we are removing it. --- .../Modal/MapOperatorToStakingProviderModal/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx index 6c34a6397..bf4975bc8 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx @@ -30,14 +30,13 @@ import { useThreshold } from "../../../contexts/ThresholdContext" import { isAddressZero, isSameETHAddress } from "../../../web3/utils" export interface MapOperatorToStakingProviderModalProps { - stakingProvider: string mappedOperatorTbtc: string mappedOperatorRandomBeacon: string } const MapOperatorToStakingProviderModal: FC< BaseModalProps & MapOperatorToStakingProviderModalProps -> = ({ stakingProvider, mappedOperatorTbtc, mappedOperatorRandomBeacon }) => { +> = ({ mappedOperatorTbtc, mappedOperatorRandomBeacon }) => { const { account } = useWeb3React() const formRef = useRef>(null) From 04e6e423497453eaf5260143d5d613759b57cb46 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 3 Oct 2022 00:27:58 +0200 Subject: [PATCH 08/41] Use mappedOperators data from the store Use mappedOperators data from the store instead of calling the `getMappedOperatorsForStakingProvider` method from threshold lib in `useRegisterMultipleOperatorsTransaction` hook. --- ...useRegisterMultipleOperatorsTransaction.ts | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index 031aa0af8..5e8a0f049 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -6,14 +6,21 @@ import { ModalType } from "../../enums" import { useWeb3React } from "@web3-react/core" import { OperatorMappedSuccessTx } from "../../components/Modal/MapOperatorToStakingProviderSuccessModal" import { mapOperatorToStakingProviderModalClosed } from "../../store/modalQueue" -import { useDispatch } from "react-redux" -import { useThreshold } from "../../contexts/ThresholdContext" +import { useDispatch, useSelector } from "react-redux" +import { RootState } from "../../store" export const useRegisterMultipleOperatorsTransaction = () => { + const mappedOperatorTbtc = useSelector( + (state: RootState) => + state.connectedAccount.operatorMapping.data.mappedOperators.tbtc + ) + const mappedOperatorRandomBeacon = useSelector( + (state: RootState) => + state.connectedAccount.operatorMapping.data.mappedOperators.randomBeacon + ) const { account } = useWeb3React() const { openModal, closeModal } = useModal() const dispatch = useDispatch() - const threshold = useThreshold() const { sendTransaction: sendRegisterOperatorTransactionTbtc, @@ -31,13 +38,6 @@ export const useRegisterMultipleOperatorsTransaction = () => { throw new Error("Connect to the staking provider account first!") } - const { - tbtc: mappedOperatorTbtc, - randomBeacon: mappedOperatorRandomBeacon, - } = await threshold.multiAppStaking.getMappedOperatorsForStakingProvider( - account - ) - if ( !isAddressZero(mappedOperatorRandomBeacon) && !isAddressZero(mappedOperatorTbtc) @@ -116,6 +116,9 @@ export const useRegisterMultipleOperatorsTransaction = () => { } }, [ + account, + mappedOperatorRandomBeacon, + mappedOperatorTbtc, sendRegisterOperatorTransactionTbtc, sendRegisterOperatorTransactionRandomBeacon, openModal, From 2d66a018c1127d4da4171456c7a401e48bd76e54 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Tue, 4 Oct 2022 13:46:06 +0200 Subject: [PATCH 09/41] Fix displaying OperatorAddressMappingCard Operator Address Mapping Card should be displayed when tbtc mapped operator is AddressZero OR (not AND) random beacon mapped operator is AddressZero. This commit fixes that. --- src/pages/Staking/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 3e2f79cd2..a383f8a0d 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -69,8 +69,8 @@ const StakingPage: PageComponent = (props) => { {isUsedAsStakingProvider && isOperatorMappingInitialFetchDone && - isAddressZero(mappedOperators.tbtc) && - isAddressZero(mappedOperators.randomBeacon) && ( + (isAddressZero(mappedOperators.tbtc) || + isAddressZero(mappedOperators.randomBeacon)) && ( Date: Tue, 4 Oct 2022 13:50:54 +0200 Subject: [PATCH 10/41] Refactor modalQueue state Move the store related to modal queue inside `modal` property since it's related to modal. --- .../index.tsx | 2 +- ...useRegisterMultipleOperatorsTransaction.ts | 2 +- src/hooks/useModal.ts | 6 +-- src/store/index.ts | 9 +++-- src/store/modal/modalSlice.ts | 36 +++++++++++++++--- src/store/modalQueue/index.ts | 1 - src/store/modalQueue/slice.ts | 37 ------------------- src/store/staking-applications/effects.ts | 22 +++++++---- 8 files changed, 53 insertions(+), 62 deletions(-) delete mode 100644 src/store/modalQueue/index.ts delete mode 100644 src/store/modalQueue/slice.ts diff --git a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx index ac515c3fd..ced8b2e95 100644 --- a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx @@ -19,7 +19,7 @@ import { useRegisterMultipleOperatorsTransaction } from "../../../hooks/staking- import { useRegisterOperatorTransaction } from "../../../hooks/staking-applications/useRegisterOperatorTransaction" import { useModal } from "../../../hooks/useModal" import StakeAddressInfo from "../../../pages/Staking/StakeCard/StakeAddressInfo" -import { mapOperatorToStakingProviderModalClosed } from "../../../store/modalQueue" +import { mapOperatorToStakingProviderModalClosed } from "../../../store/modal" import { BaseModalProps } from "../../../types" import { isAddressZero } from "../../../web3/utils" import InfoBox from "../../InfoBox" diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index 5e8a0f049..cfd84307e 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -5,9 +5,9 @@ import { useModal } from "../useModal" import { ModalType } from "../../enums" import { useWeb3React } from "@web3-react/core" import { OperatorMappedSuccessTx } from "../../components/Modal/MapOperatorToStakingProviderSuccessModal" -import { mapOperatorToStakingProviderModalClosed } from "../../store/modalQueue" import { useDispatch, useSelector } from "react-redux" import { RootState } from "../../store" +import { mapOperatorToStakingProviderModalClosed } from "../../store/modal" export const useRegisterMultipleOperatorsTransaction = () => { const mappedOperatorTbtc = useSelector( diff --git a/src/hooks/useModal.ts b/src/hooks/useModal.ts index 11360e51a..13d148183 100644 --- a/src/hooks/useModal.ts +++ b/src/hooks/useModal.ts @@ -2,14 +2,12 @@ import { useDispatch, useSelector } from "react-redux" import { UseModal } from "../types" import { closeModal as closeModalAction, + mapOperatorToStakingProviderModalClosed, openModal as openModalAction, + successfullLoginModalClosed, } from "../store/modal" import { RootState } from "../store" import { ModalType } from "../enums" -import { - mapOperatorToStakingProviderModalClosed, - successfullLoginModalClosed, -} from "../store/modalQueue" export const useModal: UseModal = () => { const modalType = useSelector((state: RootState) => state.modal.modalType) diff --git a/src/store/index.ts b/src/store/index.ts index d77738053..95c58b88e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -21,7 +21,6 @@ import { connectedAccountSlice, registerConnectedAccountListeners, } from "./connected-account" -import { modalQueueSlice } from "./modalQueue" const combinedReducer = combineReducers({ connectedAccount: connectedAccountSlice.reducer, @@ -34,7 +33,6 @@ const combinedReducer = combineReducers({ tbtc: tbtcSlice.reducer, rewards: rewardsSlice.reducer, applications: stakingApplicationsSlice.reducer, - modalQueue: modalQueueSlice.reducer, }) const APP_RESET_STORE = "app/reset_store" @@ -59,8 +57,11 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { }, // we don't display successful login modal when changin account so we are // setting this flag to true - modalQueue: { - isSuccessfullLoginModalClosed: true, + modal: { + modalQueue: { + ...state.modal.modalQueue, + isSuccessfullLoginModalClosed: true, + }, }, } as RootState } diff --git a/src/store/modal/modalSlice.ts b/src/store/modal/modalSlice.ts index 38ff13384..e76e08c30 100644 --- a/src/store/modal/modalSlice.ts +++ b/src/store/modal/modalSlice.ts @@ -1,9 +1,15 @@ -import { createSlice } from "@reduxjs/toolkit" +import { createSlice, PayloadAction } from "@reduxjs/toolkit" import { ModalType } from "../../enums" -export interface modalState { +export interface ModalQueueState { + isSuccessfullLoginModalClosed: boolean + isMappingOperatorToStakingProviderModalClosed: boolean +} + +export interface ModalState { modalType: ModalType | null props: any + modalQueue: ModalQueueState } export const modalSlice = createSlice({ @@ -11,17 +17,35 @@ export const modalSlice = createSlice({ initialState: { modalType: null, props: {}, - } as modalState, + modalQueue: { + isSuccessfullLoginModalClosed: false, + isMappingOperatorToStakingProviderModalClosed: false, + }, + } as ModalState, reducers: { - openModal: (state, action) => { + openModal: ( + state: ModalState, + action: PayloadAction<{ modalType: ModalType; props?: any }> + ) => { state.modalType = action.payload.modalType state.props = action.payload.props }, - closeModal: (state) => { + closeModal: (state: ModalState) => { state.modalType = null state.props = {} }, + successfullLoginModalClosed: (state: ModalState) => { + state.modalQueue.isSuccessfullLoginModalClosed = true + }, + mapOperatorToStakingProviderModalClosed: (state: ModalState) => { + state.modalQueue.isMappingOperatorToStakingProviderModalClosed = true + }, }, }) -export const { openModal, closeModal } = modalSlice.actions +export const { + openModal, + closeModal, + successfullLoginModalClosed, + mapOperatorToStakingProviderModalClosed, +} = modalSlice.actions diff --git a/src/store/modalQueue/index.ts b/src/store/modalQueue/index.ts deleted file mode 100644 index 6f89f45e1..000000000 --- a/src/store/modalQueue/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./slice" diff --git a/src/store/modalQueue/slice.ts b/src/store/modalQueue/slice.ts deleted file mode 100644 index 92883f5ba..000000000 --- a/src/store/modalQueue/slice.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { createSlice, PayloadAction } from "@reduxjs/toolkit" -import { featureFlags } from "../../constants" - -export interface ModalQueueState { - isSuccessfullLoginModalClosed: boolean - isMappingOperatorToStakingProviderModalClosed: boolean -} - -/* - Simplpified modal queue, we should think how to do it properly whenever we have more time -*/ -export const modalQueueSlice = createSlice({ - name: "modal-queue", - initialState: { - isSuccessfullLoginModalClosed: false, - isMappingOperatorToStakingProviderModalClosed: false, - } as ModalQueueState, - reducers: { - successfullLoginModalClosed: ( - state: ModalQueueState, - action: PayloadAction - ) => { - state.isSuccessfullLoginModalClosed = true - }, - mapOperatorToStakingProviderModalClosed: ( - state: ModalQueueState, - action: PayloadAction - ) => { - state.isMappingOperatorToStakingProviderModalClosed = true - }, - }, -}) - -export const { - successfullLoginModalClosed, - mapOperatorToStakingProviderModalClosed, -} = modalQueueSlice.actions diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 51adf4f92..363782581 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -6,7 +6,11 @@ import { selectStakingProviders, setStakes, } from "../staking" -import { modalSlice, openModal } from "../modal" +import { + mapOperatorToStakingProviderModalClosed, + modalSlice, + openModal, +} from "../modal" import { IApplication, StakingProviderAppInfo, @@ -17,8 +21,7 @@ import { selectStakingAppByStakingProvider, selectStakingAppStateByAppName, } from "./selectors" -import { isAddressZero, isSameETHAddress } from "../../web3/utils" -import { mapOperatorToStakingProviderModalClosed } from "../modalQueue" +import { isAddressZero } from "../../web3/utils" export const getSupportedAppsEffect = async ( action: ReturnType, @@ -171,11 +174,13 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( action: AnyAction, listenerApi: AppListenerEffectAPI ) => { - const { modalQueue } = listenerApi.getState() + const { + modal: { modalQueue }, + } = listenerApi.getState() const { connectedAccount, staking } = listenerApi.getState() if (!modalQueue.isSuccessfullLoginModalClosed) { - await listenerApi.condition((action, currentState: any) => { - return currentState.modalQueue.isSuccessfullLoginModalClosed + await listenerApi.condition((action, currentState: RootState) => { + return currentState.modal.modalQueue.isSuccessfullLoginModalClosed }) } const { address } = connectedAccount @@ -245,8 +250,9 @@ export const shouldDisplayNewAppsToAuthorizeModal = ( previousState: RootState ) => { return ( - currentState.modalQueue.isSuccessfullLoginModalClosed && - currentState.modalQueue.isMappingOperatorToStakingProviderModalClosed && + currentState.modal.modalQueue.isSuccessfullLoginModalClosed && + currentState.modal.modalQueue + .isMappingOperatorToStakingProviderModalClosed && Object.values( currentState.applications.randomBeacon.stakingProviders.data ?? {} ).length > 0 && From 73490d2d4989457031f4922d6f8900d679856e6a Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 13:00:39 +0200 Subject: [PATCH 11/41] Refactor map operator success modal - move provider address to the top - change `Staking Provider` -> `Provider Address` - change `Operator` -> `Operator Address` - Display `View transaction 1 and transaction 2` in one row instead of two separate rows foe each app. --- .../index.tsx | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index ff17c60f5..a1c09b696 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -1,4 +1,4 @@ -import { FC } from "react" +import { FC, Fragment } from "react" import { BodyMd, BodySm, @@ -37,43 +37,50 @@ const MapOperatorToStakingProviderSuccessBase: FC< body={ <> - + - Operator + Provider Address - {shortenAddress(transactions[0].application.operator)} + {shortenAddress(transactions[0].application.stakingProvider)} - + - Staking Provider + Operator Address - {shortenAddress(transactions[0].application.stakingProvider)} + {shortenAddress(transactions[0].application.operator)} - {transactions.map((transaction, i) => { - const text = `${camelCaseToNormal( - transaction.application.appName - )} transaction` - return ( - - View{" "} + + {transactions.length === 1 ? ( + <> {" "} + transaction on Etherscan + + ) : ( + <> + View{" "} + {transactions.map((_, index) => ( + + + {index + 1 === transactions.length ? " " : " and "} + + ))} on Etherscan - - ) - })} + + )} + } /> From 008179ba647f6bb640c8ed7d23963e2fd42d81e9 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 13:04:19 +0200 Subject: [PATCH 12/41] Fix imports --- .../Modal/MapOperatorToStakingProviderModal/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx index bf4975bc8..c6442fd18 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx @@ -7,7 +7,6 @@ import { Box, Button, H5, - HStack, LabelSm, ModalBody, ModalCloseButton, @@ -25,9 +24,12 @@ import { ModalType } from "../../../enums" import { useModal } from "../../../hooks/useModal" import StakeAddressInfo from "../../../pages/Staking/StakeCard/StakeAddressInfo" import { useWeb3React } from "@web3-react/core" -import { AddressZero } from "@ethersproject/constants" import { useThreshold } from "../../../contexts/ThresholdContext" -import { isAddressZero, isSameETHAddress } from "../../../web3/utils" +import { + isAddressZero, + isSameETHAddress, + AddressZero, +} from "../../../web3/utils" export interface MapOperatorToStakingProviderModalProps { mappedOperatorTbtc: string From 2e665b463fa556af307fedf341a9bb50653391ac Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 13:06:51 +0200 Subject: [PATCH 13/41] Use useAppDispatch and useAppSelector hooks --- .../index.tsx | 4 ++-- .../useRegisterMultipleOperatorsTransaction.ts | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx index ced8b2e95..181c89deb 100644 --- a/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderConfirmationModal/index.tsx @@ -13,10 +13,10 @@ import { BodyLg, BodyMd, H5, LabelSm } from "@threshold-network/components" import { useWeb3React } from "@web3-react/core" import { ContractTransaction } from "ethers" import { FC, useCallback } from "react" -import { useDispatch } from "react-redux" import { ModalType } from "../../../enums" import { useRegisterMultipleOperatorsTransaction } from "../../../hooks/staking-applications/useRegisterMultipleOperatorsTransaction" import { useRegisterOperatorTransaction } from "../../../hooks/staking-applications/useRegisterOperatorTransaction" +import { useAppDispatch } from "../../../hooks/store" import { useModal } from "../../../hooks/useModal" import StakeAddressInfo from "../../../pages/Staking/StakeCard/StakeAddressInfo" import { mapOperatorToStakingProviderModalClosed } from "../../../store/modal" @@ -66,7 +66,7 @@ const MapOperatorToStakingProviderConfirmationModal: FC< const { account } = useWeb3React() const { registerMultipleOperators } = useRegisterMultipleOperatorsTransaction() - const dispatch = useDispatch() + const dispatch = useAppDispatch() const isOperatorMappedOnlyInTbtc = !isAddressZero(mappedOperatorTbtc) && diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index cfd84307e..bdd72d265 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -5,22 +5,20 @@ import { useModal } from "../useModal" import { ModalType } from "../../enums" import { useWeb3React } from "@web3-react/core" import { OperatorMappedSuccessTx } from "../../components/Modal/MapOperatorToStakingProviderSuccessModal" -import { useDispatch, useSelector } from "react-redux" -import { RootState } from "../../store" import { mapOperatorToStakingProviderModalClosed } from "../../store/modal" +import { useAppDispatch, useAppSelector } from "../store" export const useRegisterMultipleOperatorsTransaction = () => { - const mappedOperatorTbtc = useSelector( - (state: RootState) => - state.connectedAccount.operatorMapping.data.mappedOperators.tbtc + const mappedOperatorTbtc = useAppSelector( + (state) => state.connectedAccount.operatorMapping.data.mappedOperators.tbtc ) - const mappedOperatorRandomBeacon = useSelector( - (state: RootState) => + const mappedOperatorRandomBeacon = useAppSelector( + (state) => state.connectedAccount.operatorMapping.data.mappedOperators.randomBeacon ) const { account } = useWeb3React() const { openModal, closeModal } = useModal() - const dispatch = useDispatch() + const dispatch = useAppDispatch() const { sendTransaction: sendRegisterOperatorTransactionTbtc, From 2cf5d876b50dbf9d6e7c082d32e8cf39bf015904 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 13:24:46 +0200 Subject: [PATCH 14/41] Fix displaying modals when changing accounts The operator mapping modal and new apps to authorize modal were not displayed properly when changin accounts in MetaMask. This commit fixes that. --- src/store/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.ts b/src/store/index.ts index 95c58b88e..f7b9424dc 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -59,8 +59,8 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { // setting this flag to true modal: { modalQueue: { - ...state.modal.modalQueue, isSuccessfullLoginModalClosed: true, + isMappingOperatorToStakingProviderModalClosed: false, }, }, } as RootState From 497617aeed75a3c35aee44930e4c3e13a291999b Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 14:00:20 +0200 Subject: [PATCH 15/41] Fix `isFetching` prop for operator address mapping Property `isFetching` was wrongly set to true and stays at this value when the connected account was not a staking provider. This commit fixes that. --- src/store/connected-account/connectedAccountSlice.ts | 4 ++++ src/store/connected-account/effects.ts | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/store/connected-account/connectedAccountSlice.ts b/src/store/connected-account/connectedAccountSlice.ts index feb786233..cbf1e9036 100644 --- a/src/store/connected-account/connectedAccountSlice.ts +++ b/src/store/connected-account/connectedAccountSlice.ts @@ -35,6 +35,8 @@ export const connectedAccountSlice = createSlice({ randomBeacon: AddressZero, }, }, + isFetching: false, + isInitialFetchDone: false, }, } as ConnectedAccountState, reducers: { @@ -71,6 +73,7 @@ export const connectedAccountSlice = createSlice({ state: ConnectedAccountState, action: PayloadAction ) => { + state.operatorMapping.isFetching = false state.operatorMapping.isInitialFetchDone = true }, setOperatorMappingError: ( @@ -78,6 +81,7 @@ export const connectedAccountSlice = createSlice({ action: PayloadAction<{ error: string }> ) => { const { error } = action.payload + state.operatorMapping.isFetching = false state.operatorMapping.error = error }, operatorRegistered: ( diff --git a/src/store/connected-account/effects.ts b/src/store/connected-account/effects.ts index c6816b302..f3ddf2611 100644 --- a/src/store/connected-account/effects.ts +++ b/src/store/connected-account/effects.ts @@ -14,11 +14,6 @@ export const getStakingProviderOperatorInfo = async ( listenerApi: AppListenerEffectAPI ) => { try { - listenerApi.dispatch( - setFetchingOperatorMapping({ - isFetching: true, - }) - ) const { connectedAccount } = listenerApi.getState() const { address } = connectedAccount const { owner, authorizer, beneficiary } = @@ -30,6 +25,11 @@ export const getStakingProviderOperatorInfo = async ( !isZeroAddress(beneficiary) if (isUsedAsStakingProvider) { + listenerApi.dispatch( + setFetchingOperatorMapping({ + isFetching: true, + }) + ) listenerApi.dispatch(accountUsedAsStakingProvider()) const mappedOperators = @@ -51,8 +51,6 @@ export const getStakingProviderOperatorInfo = async ( }) ) - listenerApi.dispatch(setFetchingOperatorMapping({ isFetching: false })) - listenerApi.dispatch(operatorMappingInitialFetchDone()) } } catch (error) { From e381413591cd0055df024b8bf5cb131e1d326998 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 5 Oct 2022 14:13:04 +0200 Subject: [PATCH 16/41] Update comment --- src/store/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/index.ts b/src/store/index.ts index f7b9424dc..4c802c6f2 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -56,7 +56,8 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { TBTC: { ...state.token.TBTC, balance: 0 }, }, // we don't display successful login modal when changin account so we are - // setting this flag to true + // setting the isSuccessfullLoginModalClosed flag to true and also + // isMappingOperatorToStakingProviderModalClosed flag back to false modal: { modalQueue: { isSuccessfullLoginModalClosed: true, From 88603134d545e9164e5c2de371435ea44441091d Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Fri, 7 Oct 2022 23:53:35 +0200 Subject: [PATCH 17/41] Simplify if statement If statement in `displayMapOperatorToStakingProviderModalEffect` could be simplified by removing `isInitialFetchDone` from the statement (because this effect is run on `operatorMappingInitialFetchDone` so we can assumet it's true) and also by inverting it and returning nothing if address is undefined instead of wrapping the whole code in the if and chacking if it's defined. --- src/store/staking-applications/effects.ts | 56 +++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 363782581..4e0ce2538 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -184,37 +184,37 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( }) } const { address } = connectedAccount - if (address && connectedAccount.operatorMapping.isInitialFetchDone) { - listenerApi.unsubscribe() - try { - const { isUsedAsStakingProvider, mappedOperators } = - connectedAccount.operatorMapping.data + if (!address) return + + listenerApi.unsubscribe() + try { + const { isUsedAsStakingProvider, mappedOperators } = + connectedAccount.operatorMapping.data - if ( - isUsedAsStakingProvider && - (isAddressZero(mappedOperators.tbtc) || - isAddressZero(mappedOperators.randomBeacon)) - ) { - listenerApi.dispatch( - openModal({ - modalType: ModalType.MapOperatorToStakingProvider, - props: { - address, - mappedOperatorTbtc: mappedOperators.tbtc, - mappedOperatorRandomBeacon: mappedOperators.randomBeacon, - }, - }) - ) - } else { - listenerApi.dispatch(mapOperatorToStakingProviderModalClosed()) - } - } catch (error) { - console.log( - "Could not fetch info about mapped operators for given staking provider:", - error + if ( + isUsedAsStakingProvider && + (isAddressZero(mappedOperators.tbtc) || + isAddressZero(mappedOperators.randomBeacon)) + ) { + listenerApi.dispatch( + openModal({ + modalType: ModalType.MapOperatorToStakingProvider, + props: { + address, + mappedOperatorTbtc: mappedOperators.tbtc, + mappedOperatorRandomBeacon: mappedOperators.randomBeacon, + }, + }) ) - listenerApi.subscribe() + } else { + listenerApi.dispatch(mapOperatorToStakingProviderModalClosed()) } + } catch (error) { + console.log( + "Could not fetch info about mapped operators for given staking provider:", + error + ) + listenerApi.subscribe() } } From 530837e2820eff1546685b441fe3dddd7c680b02 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sat, 8 Oct 2022 00:02:37 +0200 Subject: [PATCH 18/41] Remove unnecessary type --- src/store/staking-applications/effects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 4e0ce2538..9572155b6 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -179,7 +179,7 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( } = listenerApi.getState() const { connectedAccount, staking } = listenerApi.getState() if (!modalQueue.isSuccessfullLoginModalClosed) { - await listenerApi.condition((action, currentState: RootState) => { + await listenerApi.condition((action, currentState) => { return currentState.modal.modalQueue.isSuccessfullLoginModalClosed }) } From 45c0b72fa274f3314d3c3bd6e471aa5a49a53475 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sat, 8 Oct 2022 00:05:37 +0200 Subject: [PATCH 19/41] Simplify another if statement --- src/store/connected-account/effects.ts | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/store/connected-account/effects.ts b/src/store/connected-account/effects.ts index f3ddf2611..533488aca 100644 --- a/src/store/connected-account/effects.ts +++ b/src/store/connected-account/effects.ts @@ -24,35 +24,35 @@ export const getStakingProviderOperatorInfo = async ( !isZeroAddress(authorizer) && !isZeroAddress(beneficiary) - if (isUsedAsStakingProvider) { - listenerApi.dispatch( - setFetchingOperatorMapping({ - isFetching: true, - }) - ) - listenerApi.dispatch(accountUsedAsStakingProvider()) + if (!isUsedAsStakingProvider) return - const mappedOperators = - await listenerApi.extra.threshold.multiAppStaking.getMappedOperatorsForStakingProvider( - address - ) + listenerApi.dispatch( + setFetchingOperatorMapping({ + isFetching: true, + }) + ) + listenerApi.dispatch(accountUsedAsStakingProvider()) - listenerApi.dispatch( - setMappedOperator({ - appName: "tbtc", - operator: mappedOperators.tbtc, - }) + const mappedOperators = + await listenerApi.extra.threshold.multiAppStaking.getMappedOperatorsForStakingProvider( + address ) - listenerApi.dispatch( - setMappedOperator({ - appName: "randomBeacon", - operator: mappedOperators.randomBeacon, - }) - ) + listenerApi.dispatch( + setMappedOperator({ + appName: "tbtc", + operator: mappedOperators.tbtc, + }) + ) + + listenerApi.dispatch( + setMappedOperator({ + appName: "randomBeacon", + operator: mappedOperators.randomBeacon, + }) + ) - listenerApi.dispatch(operatorMappingInitialFetchDone()) - } + listenerApi.dispatch(operatorMappingInitialFetchDone()) } catch (error) { listenerApi.dispatch( connectedAccountSlice.actions.setFetchingOperatorMapping({ From 4fd84b4c7f1e0a5910ec6a557540305d823d1789 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sat, 8 Oct 2022 00:12:25 +0200 Subject: [PATCH 20/41] Use useAppSelector hook instead of useSelector --- src/pages/Staking/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index a383f8a0d..01d2734bf 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react" -import { HStack, Stack, VStack } from "@chakra-ui/react" +import { HStack, VStack } from "@chakra-ui/react" import StakingTVLCard from "./StakingTVLCard" import StakedPortfolioCard from "./StakedPortfolioCard" import PageLayout from "../PageLayout" @@ -28,7 +28,7 @@ import StakeDetailsPage from "./StakeDetailsPage" import NewStakeCard from "./NewStakeCard" import OperatorAddressMappingCard from "./OperatorAddressMappingCard" import { isAddressZero } from "../../web3/utils" -import { RootState } from "../../store" +import { useAppSelector } from "../../hooks/store" const StakingPage: PageComponent = (props) => { const [data, fetchtTvlData] = useFetchTvl() @@ -49,7 +49,7 @@ const StakingPage: PageComponent = (props) => { const { isInitialFetchDone: isOperatorMappingInitialFetchDone, data: { isUsedAsStakingProvider, mappedOperators }, - } = useSelector((state: RootState) => state.connectedAccount.operatorMapping) + } = useAppSelector((state) => state.connectedAccount.operatorMapping) return ( From 369c9c908018a9448a3c5a543197d6d8e9bba994 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sat, 8 Oct 2022 00:15:36 +0200 Subject: [PATCH 21/41] Clean imports --- src/pages/Staking/OperatorAddressMappingCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/Staking/OperatorAddressMappingCard.tsx b/src/pages/Staking/OperatorAddressMappingCard.tsx index f299de0a6..9ff24a2d7 100644 --- a/src/pages/Staking/OperatorAddressMappingCard.tsx +++ b/src/pages/Staking/OperatorAddressMappingCard.tsx @@ -6,11 +6,10 @@ import { Button, Card, HStack, + LabelSm, } from "@threshold-network/components" -import { LabelSm } from "@threshold-network/components" import { FC } from "react" import { ModalType } from "../../enums" -// import { useOperatorMappedtoStakingProviderHelpers } from "../../hooks/staking-applications/useOperatorMappedToStakingProviderHelpers" import { useModal } from "../../hooks/useModal" import { isAddressZero } from "../../web3/utils" From cdf31809bb34c6f8ea30553d4a91ec44644c5010 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Sat, 8 Oct 2022 00:16:38 +0200 Subject: [PATCH 22/41] Simplify key for the fragment Simplify the key used for a fragment in Operator Mapping success modal. --- .../Modal/MapOperatorToStakingProviderSuccessModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index a1c09b696..fd12856a4 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -68,7 +68,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< <> View{" "} {transactions.map((_, index) => ( - + Date: Mon, 10 Oct 2022 13:10:09 +0200 Subject: [PATCH 23/41] Fix Id of the ViewInExplorer The id was wronlgy used because i've mistakend it with a key. It needs the th hash to work properly. --- .../Modal/MapOperatorToStakingProviderSuccessModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index fd12856a4..7bf5cac6f 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -59,7 +59,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< <> {" "} transaction on Etherscan From a1810ef1f34f6a585b10a1241964defb5fbad25b Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 13:21:33 +0200 Subject: [PATCH 24/41] Fix error message Fix error message when one of the apps has the operator mapped already. --- .../MapOperatorToStakingProviderForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx index d531eb5b7..68cd513c1 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx @@ -76,14 +76,14 @@ const MapOperatorToStakingProviderForm = withFormik< values.operator !== mappedOperatorRandomBeacon ) { validationMsg = - "The operator address doesn't match the one used in tbtc app" + "The operator address doesn't match the one used in random beacon app" } if ( isOperatorMappedOnlyInTbtc && values.operator !== mappedOperatorTbtc ) { validationMsg = - "The operator address doesn't match the one used in random beacon app" + "The operator address doesn't match the one used in tbtc app" } } catch (error) { console.error( From 45a5009ea7eb56c44fdb0e2846bb33c11a955c07 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 13:24:34 +0200 Subject: [PATCH 25/41] Fix typo succes -> success --- .../Modal/MapOperatorToStakingProviderSuccessModal/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index 7bf5cac6f..4c4708a3f 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -37,7 +37,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< body={ <> - + Provider Address @@ -45,7 +45,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< - + Operator Address From 0de4912594f5fd6521aa3345b3308a75abcdd607 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 13:35:44 +0200 Subject: [PATCH 26/41] Clean up success modal Clean up succes modal for operator mapping --- .../index.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index 4c4708a3f..bdb0d4ce4 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -1,11 +1,5 @@ import { FC, Fragment } from "react" -import { - BodyMd, - BodySm, - HStack, - List, - ListItem, -} from "@threshold-network/components" +import { BodySm, HStack, List, ListItem } from "@threshold-network/components" import withBaseModal from "../withBaseModal" import { BaseModalProps } from "../../../types" import { StakingAppName } from "../../../store/staking-applications" @@ -13,7 +7,6 @@ import TransactionSuccessModal from "../TransactionSuccessModal" import shortenAddress from "../../../utils/shortenAddress" import { ExplorerDataType } from "../../../utils/createEtherscanLink" import ViewInBlockExplorer from "../../ViewInBlockExplorer" -import { camelCaseToNormal } from "../../../utils/text" export type OperatorMappedSuccessTx = { application: { @@ -36,7 +29,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< subTitle="You successfully mapped your Operator Address." body={ <> - + Provider Address From 08e6e157803311e44c512bc77cce4c93fedd31dd Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 13:37:20 +0200 Subject: [PATCH 27/41] Remove unnecessary TODO --- src/pages/Staking/OperatorAddressMappingCard.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Staking/OperatorAddressMappingCard.tsx b/src/pages/Staking/OperatorAddressMappingCard.tsx index 9ff24a2d7..d3a25fdfa 100644 --- a/src/pages/Staking/OperatorAddressMappingCard.tsx +++ b/src/pages/Staking/OperatorAddressMappingCard.tsx @@ -13,7 +13,6 @@ import { ModalType } from "../../enums" import { useModal } from "../../hooks/useModal" import { isAddressZero } from "../../web3/utils" -//TODO: Fix this const OperatorAddressMappingCard: FC<{ mappedOperatorTbtc: string mappedOperatorRandomBeacon: string From d35e967400e6c49cf6c8b8f23ddb6667fb84f61d Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 13:39:25 +0200 Subject: [PATCH 28/41] Fix typo isSuccessfullLoginModalClosed -> isSuccessfulLoginModalClosed --- src/store/index.ts | 4 ++-- src/store/modal/modalSlice.ts | 6 +++--- src/store/staking-applications/effects.ts | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/store/index.ts b/src/store/index.ts index 4c802c6f2..04b30300e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -56,11 +56,11 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { TBTC: { ...state.token.TBTC, balance: 0 }, }, // we don't display successful login modal when changin account so we are - // setting the isSuccessfullLoginModalClosed flag to true and also + // setting the isSuccessfulLoginModalClosed flag to true and also // isMappingOperatorToStakingProviderModalClosed flag back to false modal: { modalQueue: { - isSuccessfullLoginModalClosed: true, + isSuccessfulLoginModalClosed: true, isMappingOperatorToStakingProviderModalClosed: false, }, }, diff --git a/src/store/modal/modalSlice.ts b/src/store/modal/modalSlice.ts index e76e08c30..91d1e00ad 100644 --- a/src/store/modal/modalSlice.ts +++ b/src/store/modal/modalSlice.ts @@ -2,7 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit" import { ModalType } from "../../enums" export interface ModalQueueState { - isSuccessfullLoginModalClosed: boolean + isSuccessfulLoginModalClosed: boolean isMappingOperatorToStakingProviderModalClosed: boolean } @@ -18,7 +18,7 @@ export const modalSlice = createSlice({ modalType: null, props: {}, modalQueue: { - isSuccessfullLoginModalClosed: false, + isSuccessfulLoginModalClosed: false, isMappingOperatorToStakingProviderModalClosed: false, }, } as ModalState, @@ -35,7 +35,7 @@ export const modalSlice = createSlice({ state.props = {} }, successfullLoginModalClosed: (state: ModalState) => { - state.modalQueue.isSuccessfullLoginModalClosed = true + state.modalQueue.isSuccessfulLoginModalClosed = true }, mapOperatorToStakingProviderModalClosed: (state: ModalState) => { state.modalQueue.isMappingOperatorToStakingProviderModalClosed = true diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 9572155b6..b9db92f20 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -178,9 +178,9 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( modal: { modalQueue }, } = listenerApi.getState() const { connectedAccount, staking } = listenerApi.getState() - if (!modalQueue.isSuccessfullLoginModalClosed) { + if (!modalQueue.isSuccessfulLoginModalClosed) { await listenerApi.condition((action, currentState) => { - return currentState.modal.modalQueue.isSuccessfullLoginModalClosed + return currentState.modal.modalQueue.isSuccessfulLoginModalClosed }) } const { address } = connectedAccount @@ -250,7 +250,7 @@ export const shouldDisplayNewAppsToAuthorizeModal = ( previousState: RootState ) => { return ( - currentState.modal.modalQueue.isSuccessfullLoginModalClosed && + currentState.modal.modalQueue.isSuccessfulLoginModalClosed && currentState.modal.modalQueue .isMappingOperatorToStakingProviderModalClosed && Object.values( From d3c637b990b9f530b560e94054ff0dd3261d06f9 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 14:38:05 +0200 Subject: [PATCH 29/41] Improvde getStakingProviderOperatorInfo effect Before calling `rolesOf` method from the contract we want to check if there are stakes in `staking` slice that have the owner === staking provider (since we keep them there form the owner perspective, so owner === currently connected account). If yes then we get the data from there and we don't have to do a call to contract. Note: Even though the `getStakingProviderOperatorInfo` effect is called on `setStakes` action, the store does not containe the stakes yet. Forutnately we can get them from the `action` argument. --- src/store/connected-account/effects.ts | 29 +++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/store/connected-account/effects.ts b/src/store/connected-account/effects.ts index 533488aca..c2fcfcc77 100644 --- a/src/store/connected-account/effects.ts +++ b/src/store/connected-account/effects.ts @@ -1,6 +1,9 @@ import { isZeroAddress } from "ethereumjs-util" +import { useAppSelector } from "../../hooks/store" +import { StakeData } from "../../types" +import { isSameETHAddress } from "../../web3/utils" import { AppListenerEffectAPI } from "../listener" -import { setStakes } from "../staking" +import { selectStakeByStakingProvider, setStakes } from "../staking" import { accountUsedAsStakingProvider, connectedAccountSlice, @@ -16,13 +19,25 @@ export const getStakingProviderOperatorInfo = async ( try { const { connectedAccount } = listenerApi.getState() const { address } = connectedAccount - const { owner, authorizer, beneficiary } = - await listenerApi.extra.threshold.staking.rolesOf(address) + const stakes = action.payload - const isUsedAsStakingProvider = - !isZeroAddress(owner) && - !isZeroAddress(authorizer) && - !isZeroAddress(beneficiary) + const stake = stakes.find((_: StakeData) => + isSameETHAddress(_.stakingProvider, address) + ) + + let isUsedAsStakingProvider = false + + if (stake) { + isUsedAsStakingProvider = true + } else { + const { owner, authorizer, beneficiary } = + await listenerApi.extra.threshold.staking.rolesOf(address) + + isUsedAsStakingProvider = + !isZeroAddress(owner) && + !isZeroAddress(authorizer) && + !isZeroAddress(beneficiary) + } if (!isUsedAsStakingProvider) return From 47639bf858c8fb04be780e3eed636d8e742526b2 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 10 Oct 2022 14:52:23 +0200 Subject: [PATCH 30/41] Rename connected account to account Rename connected account slice to just "account" --- ...useRegisterMultipleOperatorsTransaction.ts | 5 ++- .../useSubscribeToOperatorRegisteredEvent.ts | 2 +- src/hooks/useSaveConnectedAddressToStore.ts | 4 +-- src/pages/Staking/index.tsx | 2 +- .../{connected-account => account}/effects.ts | 13 ++++---- src/store/account/index.ts | 1 + .../slice.ts} | 33 +++++++++---------- src/store/connected-account/index.ts | 1 - src/store/index.ts | 9 ++--- src/store/staking-applications/effects.ts | 6 ++-- src/store/staking-applications/slice.ts | 2 +- 11 files changed, 35 insertions(+), 43 deletions(-) rename src/store/{connected-account => account}/effects.ts (84%) create mode 100644 src/store/account/index.ts rename src/store/{connected-account/connectedAccountSlice.ts => account/slice.ts} (83%) delete mode 100644 src/store/connected-account/index.ts diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index bdd72d265..0ebe1f2b1 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -10,11 +10,10 @@ import { useAppDispatch, useAppSelector } from "../store" export const useRegisterMultipleOperatorsTransaction = () => { const mappedOperatorTbtc = useAppSelector( - (state) => state.connectedAccount.operatorMapping.data.mappedOperators.tbtc + (state) => state.account.operatorMapping.data.mappedOperators.tbtc ) const mappedOperatorRandomBeacon = useAppSelector( - (state) => - state.connectedAccount.operatorMapping.data.mappedOperators.randomBeacon + (state) => state.account.operatorMapping.data.mappedOperators.randomBeacon ) const { account } = useWeb3React() const { openModal, closeModal } = useModal() diff --git a/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts b/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts index 697a68b7a..c9b6055e9 100644 --- a/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts +++ b/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts @@ -1,5 +1,5 @@ import { useWeb3React } from "@web3-react/core" -import { operatorRegistered } from "../../store/connected-account" +import { operatorRegistered } from "../../store/account" import { StakingAppName } from "../../store/staking-applications" import { useSubscribeToContractEvent } from "../../web3/hooks" import { isSameETHAddress } from "../../web3/utils" diff --git a/src/hooks/useSaveConnectedAddressToStore.ts b/src/hooks/useSaveConnectedAddressToStore.ts index 827bfe13d..97f1ccd26 100644 --- a/src/hooks/useSaveConnectedAddressToStore.ts +++ b/src/hooks/useSaveConnectedAddressToStore.ts @@ -1,7 +1,7 @@ import { useWeb3React } from "@web3-react/core" import { useEffect } from "react" import { useDispatch } from "react-redux" -import { setConnectedAccountAddress } from "../store/connected-account" +import { setAccountAddress } from "../store/account" export const useSaveConnectedAddressToStore = () => { const { account } = useWeb3React() @@ -9,6 +9,6 @@ export const useSaveConnectedAddressToStore = () => { useEffect(() => { const address = account ? account : "" - dispatch(setConnectedAccountAddress(address)) + dispatch(setAccountAddress(address)) }, [account]) } diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 01d2734bf..ca4eb3af9 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -49,7 +49,7 @@ const StakingPage: PageComponent = (props) => { const { isInitialFetchDone: isOperatorMappingInitialFetchDone, data: { isUsedAsStakingProvider, mappedOperators }, - } = useAppSelector((state) => state.connectedAccount.operatorMapping) + } = useAppSelector((state) => state.account.operatorMapping) return ( diff --git a/src/store/connected-account/effects.ts b/src/store/account/effects.ts similarity index 84% rename from src/store/connected-account/effects.ts rename to src/store/account/effects.ts index c2fcfcc77..d3872a9a4 100644 --- a/src/store/connected-account/effects.ts +++ b/src/store/account/effects.ts @@ -1,24 +1,23 @@ import { isZeroAddress } from "ethereumjs-util" -import { useAppSelector } from "../../hooks/store" import { StakeData } from "../../types" import { isSameETHAddress } from "../../web3/utils" import { AppListenerEffectAPI } from "../listener" -import { selectStakeByStakingProvider, setStakes } from "../staking" +import { setStakes } from "../staking" import { accountUsedAsStakingProvider, - connectedAccountSlice, + accountSlice, operatorMappingInitialFetchDone, setFetchingOperatorMapping, setMappedOperator, -} from "./connectedAccountSlice" +} from "./slice" export const getStakingProviderOperatorInfo = async ( action: ReturnType, listenerApi: AppListenerEffectAPI ) => { try { - const { connectedAccount } = listenerApi.getState() - const { address } = connectedAccount + const { account } = listenerApi.getState() + const { address } = account const stakes = action.payload const stake = stakes.find((_: StakeData) => @@ -70,7 +69,7 @@ export const getStakingProviderOperatorInfo = async ( listenerApi.dispatch(operatorMappingInitialFetchDone()) } catch (error) { listenerApi.dispatch( - connectedAccountSlice.actions.setFetchingOperatorMapping({ + accountSlice.actions.setFetchingOperatorMapping({ isFetching: false, }) ) diff --git a/src/store/account/index.ts b/src/store/account/index.ts new file mode 100644 index 000000000..6f89f45e1 --- /dev/null +++ b/src/store/account/index.ts @@ -0,0 +1 @@ +export * from "./slice" diff --git a/src/store/connected-account/connectedAccountSlice.ts b/src/store/account/slice.ts similarity index 83% rename from src/store/connected-account/connectedAccountSlice.ts rename to src/store/account/slice.ts index cbf1e9036..a533f91ef 100644 --- a/src/store/connected-account/connectedAccountSlice.ts +++ b/src/store/account/slice.ts @@ -12,7 +12,7 @@ import { import { StakingAppName } from "../staking-applications" import { getStakingProviderOperatorInfo } from "./effects" -interface ConnectedAccountState { +interface AccountState { address: string operatorMapping: FetchingState<{ isUsedAsStakingProvider: boolean @@ -23,8 +23,8 @@ interface ConnectedAccountState { }> } -export const connectedAccountSlice = createSlice({ - name: "connected-account", +export const accountSlice = createSlice({ + name: "account", initialState: { address: "", operatorMapping: { @@ -38,22 +38,19 @@ export const connectedAccountSlice = createSlice({ isFetching: false, isInitialFetchDone: false, }, - } as ConnectedAccountState, + } as AccountState, reducers: { - setConnectedAccountAddress: ( - state: ConnectedAccountState, - action: PayloadAction - ) => { + setAccountAddress: (state: AccountState, action: PayloadAction) => { state.address = action.payload }, accountUsedAsStakingProvider: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction ) => { state.operatorMapping.data.isUsedAsStakingProvider = true }, setMappedOperator: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction<{ appName: StakingAppName operator: string @@ -63,21 +60,21 @@ export const connectedAccountSlice = createSlice({ state.operatorMapping.data.mappedOperators[appName] = operator }, setFetchingOperatorMapping: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction<{ isFetching: boolean }> ) => { const { isFetching } = action.payload state.operatorMapping.isFetching = isFetching }, operatorMappingInitialFetchDone: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction ) => { state.operatorMapping.isFetching = false state.operatorMapping.isInitialFetchDone = true }, setOperatorMappingError: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction<{ error: string }> ) => { const { error } = action.payload @@ -85,7 +82,7 @@ export const connectedAccountSlice = createSlice({ state.operatorMapping.error = error }, operatorRegistered: ( - state: ConnectedAccountState, + state: AccountState, action: PayloadAction<{ appName: StakingAppName operator: string @@ -113,7 +110,7 @@ export const connectedAccountSlice = createSlice({ }, }) -export const registerConnectedAccountListeners = () => { +export const registerAccountListeners = () => { if (featureFlags.MULTI_APP_STAKING) { startAppListening({ actionCreator: setStakes, @@ -121,14 +118,14 @@ export const registerConnectedAccountListeners = () => { }) } } -registerConnectedAccountListeners() +registerAccountListeners() export const { - setConnectedAccountAddress, + setAccountAddress, accountUsedAsStakingProvider, setMappedOperator, setFetchingOperatorMapping, operatorMappingInitialFetchDone, setOperatorMappingError, operatorRegistered, -} = connectedAccountSlice.actions +} = accountSlice.actions diff --git a/src/store/connected-account/index.ts b/src/store/connected-account/index.ts deleted file mode 100644 index f0be16c93..000000000 --- a/src/store/connected-account/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./connectedAccountSlice" diff --git a/src/store/index.ts b/src/store/index.ts index 04b30300e..f9f98f05d 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -17,13 +17,10 @@ import { stakingApplicationsSlice, } from "./staking-applications/slice" import { listenerMiddleware } from "./listener" -import { - connectedAccountSlice, - registerConnectedAccountListeners, -} from "./connected-account" +import { accountSlice, registerAccountListeners } from "./account" const combinedReducer = combineReducers({ - connectedAccount: connectedAccountSlice.reducer, + account: accountSlice.reducer, modal: modalSlice.reducer, token: tokenSlice.reducer, sidebar: sidebarSlice.reducer, @@ -46,7 +43,7 @@ const rootReducer: Reducer = (state: RootState, action: AnyAction) => { listenerMiddleware.clearListeners() registerStakingListeners() registerStakingAppsListeners() - registerConnectedAccountListeners() + registerAccountListeners() state = { eth: { ...state.eth }, token: { diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index b9db92f20..9a8b6d992 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -177,19 +177,19 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( const { modal: { modalQueue }, } = listenerApi.getState() - const { connectedAccount, staking } = listenerApi.getState() + const { account } = listenerApi.getState() if (!modalQueue.isSuccessfulLoginModalClosed) { await listenerApi.condition((action, currentState) => { return currentState.modal.modalQueue.isSuccessfulLoginModalClosed }) } - const { address } = connectedAccount + const { address } = account if (!address) return listenerApi.unsubscribe() try { const { isUsedAsStakingProvider, mappedOperators } = - connectedAccount.operatorMapping.data + account.operatorMapping.data if ( isUsedAsStakingProvider && diff --git a/src/store/staking-applications/slice.ts b/src/store/staking-applications/slice.ts index f675bf04b..1b9d18482 100644 --- a/src/store/staking-applications/slice.ts +++ b/src/store/staking-applications/slice.ts @@ -18,7 +18,7 @@ import { displayDeauthrizationCompletedModalEffect, displayDeauthrizationInitiatedModalEffect, } from "./effects" -import { operatorMappingInitialFetchDone } from "../connected-account" +import { operatorMappingInitialFetchDone } from "../account" type StakingApplicationDataByStakingProvider = { [stakingProvider: string]: StakingProviderAppInfo From 64677b39e1b6c5234354bcdb5adb933bf3d191bf Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Tue, 11 Oct 2022 10:08:27 +0200 Subject: [PATCH 31/41] Update text Update text based on Figma designs in OperatorAddressMappingCard component and in MapOperatorToStakingProviderModal. --- .../Modal/MapOperatorToStakingProviderModal/index.tsx | 7 ++++--- src/pages/Staking/OperatorAddressMappingCard.tsx | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx index c6442fd18..ed143c056 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/index.tsx @@ -95,13 +95,14 @@ const MapOperatorToStakingProviderModal: FC< ) : (
- We’ve noticed your wallet address is the same with your Provider + We’ve noticed your wallet address is the same as your Provider Address
)} - Would you like to map your Operator Address? Mapping an Operator - Address will require one transaction per application. + Map your Operator Address to your Provider Address to improve the + support of your hardware wallet. Mapping will require one + transaction per application. diff --git a/src/pages/Staking/OperatorAddressMappingCard.tsx b/src/pages/Staking/OperatorAddressMappingCard.tsx index d3a25fdfa..5bf14874d 100644 --- a/src/pages/Staking/OperatorAddressMappingCard.tsx +++ b/src/pages/Staking/OperatorAddressMappingCard.tsx @@ -58,7 +58,7 @@ const OperatorAddressMappingCard: FC<{ ) From 7ed1d17e9e0707d79ad3b49c2ef80816c2c48092 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 17 Oct 2022 00:31:29 +0200 Subject: [PATCH 32/41] Simplify MapOperatorToStakingProviderForm - use `isSameEthAddress` function in some conditions instead of `!==` - move large part of the validation to a new `validateInputtedOperatorAddress` function --- .../MapOperatorToStakingProviderForm.tsx | 94 +++++++++++-------- 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx index 68cd513c1..68ad8680b 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx @@ -2,7 +2,7 @@ import { FC, Ref } from "react" import { FormikProps, FormikErrors, withFormik } from "formik" import { Form, FormikInput } from "../../Forms" import { getErrorsObj, validateETHAddress } from "../../../utils/forms" -import { isAddressZero } from "../../../web3/utils" +import { isAddressZero, isSameETHAddress } from "../../../web3/utils" export interface MapOperatorToStakingProviderFormValues { operator: string @@ -26,6 +26,53 @@ const MapOperatorToStakingProviderFormBase: FC< ) } +const validateInputtedOperatorAddress = async ( + operator: string, + checkIfOperatorIsMappedToAnotherStakingProvider: ( + operator: string + ) => Promise, + mappedOperatorRandomBeacon: string, + mappedOperatorTbtc: string +): Promise => { + let validationMsg: string | undefined = "" + + const isOperatorMappedOnlyInTbtc = + !isAddressZero(mappedOperatorTbtc) && + isAddressZero(mappedOperatorRandomBeacon) + + const isOperatorMappedOnlyInRandomBeacon = + isAddressZero(mappedOperatorTbtc) && + !isAddressZero(mappedOperatorRandomBeacon) + + try { + const isOperatorMappedToAnotherStakingProvider = + await checkIfOperatorIsMappedToAnotherStakingProvider(operator) + validationMsg = undefined + if (isOperatorMappedToAnotherStakingProvider) { + validationMsg = "Operator is already mapped to another staking provider." + } + if ( + isOperatorMappedOnlyInRandomBeacon && + !isSameETHAddress(operator, mappedOperatorRandomBeacon) + ) { + validationMsg = + "The operator address doesn't match the one used in random beacon app" + } + if ( + isOperatorMappedOnlyInTbtc && + !isSameETHAddress(operator, mappedOperatorTbtc) + ) { + validationMsg = + "The operator address doesn't match the one used in random beacon app" + } + } catch (error) { + console.error("`MapOperatorToStakingProviderForm` validation error.", error) + validationMsg = (error as Error)?.message + } + + return validationMsg +} + type MapOperatorToStakingProviderFormProps = { initialAddress: string mappedOperatorTbtc: string @@ -50,49 +97,16 @@ const MapOperatorToStakingProviderForm = withFormik< mappedOperatorRandomBeacon, checkIfOperatorIsMappedToAnotherStakingProvider, } = props - - const isOperatorMappedOnlyInTbtc = - !isAddressZero(mappedOperatorTbtc) && - isAddressZero(mappedOperatorRandomBeacon) - - const isOperatorMappedOnlyInRandomBeacon = - isAddressZero(mappedOperatorTbtc) && - !isAddressZero(mappedOperatorRandomBeacon) const errors: FormikErrors = {} errors.operator = validateETHAddress(values.operator) if (!errors.operator) { - let validationMsg: string | undefined = "" - try { - const isOperatorMappedToAnotherStakingProvider = - await checkIfOperatorIsMappedToAnotherStakingProvider(values.operator) - validationMsg = undefined - if (isOperatorMappedToAnotherStakingProvider) { - validationMsg = - "Operator is already mapped to another staking provider." - } - if ( - isOperatorMappedOnlyInRandomBeacon && - values.operator !== mappedOperatorRandomBeacon - ) { - validationMsg = - "The operator address doesn't match the one used in random beacon app" - } - if ( - isOperatorMappedOnlyInTbtc && - values.operator !== mappedOperatorTbtc - ) { - validationMsg = - "The operator address doesn't match the one used in tbtc app" - } - } catch (error) { - console.error( - "`MapOperatorToStakingProviderForm` validation error.", - error - ) - validationMsg = (error as Error)?.message - } - errors.operator = validationMsg + errors.operator = await validateInputtedOperatorAddress( + values.operator, + checkIfOperatorIsMappedToAnotherStakingProvider, + mappedOperatorRandomBeacon, + mappedOperatorTbtc + ) } return getErrorsObj(errors) From 009344de756a6593c914dec921f15bdd2ce13b55 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 17 Oct 2022 10:49:44 +0200 Subject: [PATCH 33/41] Fix isAddressZero import Use `isAddressZero` instead of `isZeroAddress` --- src/store/account/effects.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/store/account/effects.ts b/src/store/account/effects.ts index d3872a9a4..31f2ee5d7 100644 --- a/src/store/account/effects.ts +++ b/src/store/account/effects.ts @@ -1,6 +1,5 @@ -import { isZeroAddress } from "ethereumjs-util" import { StakeData } from "../../types" -import { isSameETHAddress } from "../../web3/utils" +import { isAddressZero, isSameETHAddress } from "../../web3/utils" import { AppListenerEffectAPI } from "../listener" import { setStakes } from "../staking" import { @@ -33,9 +32,9 @@ export const getStakingProviderOperatorInfo = async ( await listenerApi.extra.threshold.staking.rolesOf(address) isUsedAsStakingProvider = - !isZeroAddress(owner) && - !isZeroAddress(authorizer) && - !isZeroAddress(beneficiary) + !isAddressZero(owner) && + !isAddressZero(authorizer) && + !isAddressZero(beneficiary) } if (!isUsedAsStakingProvider) return From c5453fdba5eb88c51259e8c60a66bc010648f832 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 17 Oct 2022 11:22:37 +0200 Subject: [PATCH 34/41] Change `setAccountAddress` action name setAccountAddress -> walletConnected --- src/hooks/useSaveConnectedAddressToStore.ts | 4 ++-- src/store/account/slice.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hooks/useSaveConnectedAddressToStore.ts b/src/hooks/useSaveConnectedAddressToStore.ts index 97f1ccd26..8bc50225a 100644 --- a/src/hooks/useSaveConnectedAddressToStore.ts +++ b/src/hooks/useSaveConnectedAddressToStore.ts @@ -1,7 +1,7 @@ import { useWeb3React } from "@web3-react/core" import { useEffect } from "react" import { useDispatch } from "react-redux" -import { setAccountAddress } from "../store/account" +import { walletConnected } from "../store/account" export const useSaveConnectedAddressToStore = () => { const { account } = useWeb3React() @@ -9,6 +9,6 @@ export const useSaveConnectedAddressToStore = () => { useEffect(() => { const address = account ? account : "" - dispatch(setAccountAddress(address)) + dispatch(walletConnected(address)) }, [account]) } diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index a533f91ef..a07b77e22 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -40,7 +40,7 @@ export const accountSlice = createSlice({ }, } as AccountState, reducers: { - setAccountAddress: (state: AccountState, action: PayloadAction) => { + walletConnected: (state: AccountState, action: PayloadAction) => { state.address = action.payload }, accountUsedAsStakingProvider: ( @@ -121,7 +121,7 @@ export const registerAccountListeners = () => { registerAccountListeners() export const { - setAccountAddress, + walletConnected, accountUsedAsStakingProvider, setMappedOperator, setFetchingOperatorMapping, From 2fd71544f69bea87569f98eb62149aa93f710ee2 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 17 Oct 2022 11:24:47 +0200 Subject: [PATCH 35/41] Remove unnecessary variables --- src/store/account/slice.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index a07b77e22..e091c09cd 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -97,8 +97,7 @@ export const accountSlice = createSlice({ (action: AnyAction) => action.type.match(providerStakedForStakingProvider), (state, action: ReturnType) => { - const { owner, beneficiary, authorizer, stakingProvider } = - action.payload + const { stakingProvider } = action.payload const { address } = state From 676058f0e90ae34a6d3350b34261fcc5fb1524be Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Mon, 17 Oct 2022 11:38:11 +0200 Subject: [PATCH 36/41] Remove unnecessary keys from ListItem --- .../Modal/MapOperatorToStakingProviderSuccessModal/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx index bdb0d4ce4..71d4ddc57 100644 --- a/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderSuccessModal/index.tsx @@ -30,7 +30,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< body={ <> - + Provider Address @@ -38,7 +38,7 @@ const MapOperatorToStakingProviderSuccessBase: FC< - + Operator Address From f754bc4f0a0f1f626255c1279d8f7ccdfca703c8 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 19 Oct 2022 08:01:22 +0200 Subject: [PATCH 37/41] Rename isUsedAsStakingProvider prop in store isUsedAsStakingProvider -> isStakingProvider Also move it outside of mappedOperators object and keep it in the root of the account slice. --- src/pages/Staking/index.tsx | 11 +++++++---- src/store/account/effects.ts | 8 ++++---- src/store/account/slice.ts | 8 ++++---- src/store/staking-applications/effects.ts | 10 +++++++--- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index ca4eb3af9..5473d9488 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -47,9 +47,12 @@ const StakingPage: PageComponent = (props) => { const hasStakes = stakes.length > 0 const { - isInitialFetchDone: isOperatorMappingInitialFetchDone, - data: { isUsedAsStakingProvider, mappedOperators }, - } = useAppSelector((state) => state.account.operatorMapping) + isStakingProvider, + operatorMapping: { + isInitialFetchDone: isOperatorMappingInitialFetchDone, + data: { mappedOperators }, + }, + } = useAppSelector((state) => state.account) return ( @@ -67,7 +70,7 @@ const StakingPage: PageComponent = (props) => { > Your Stake - {isUsedAsStakingProvider && + {isStakingProvider && isOperatorMappingInitialFetchDone && (isAddressZero(mappedOperators.tbtc) || isAddressZero(mappedOperators.randomBeacon)) && ( diff --git a/src/store/account/effects.ts b/src/store/account/effects.ts index 31f2ee5d7..0f6aad168 100644 --- a/src/store/account/effects.ts +++ b/src/store/account/effects.ts @@ -23,21 +23,21 @@ export const getStakingProviderOperatorInfo = async ( isSameETHAddress(_.stakingProvider, address) ) - let isUsedAsStakingProvider = false + let isStakingProvider = false if (stake) { - isUsedAsStakingProvider = true + isStakingProvider = true } else { const { owner, authorizer, beneficiary } = await listenerApi.extra.threshold.staking.rolesOf(address) - isUsedAsStakingProvider = + isStakingProvider = !isAddressZero(owner) && !isAddressZero(authorizer) && !isAddressZero(beneficiary) } - if (!isUsedAsStakingProvider) return + if (!isStakingProvider) return listenerApi.dispatch( setFetchingOperatorMapping({ diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index e091c09cd..47e3f97a8 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -14,8 +14,8 @@ import { getStakingProviderOperatorInfo } from "./effects" interface AccountState { address: string + isStakingProvider: boolean operatorMapping: FetchingState<{ - isUsedAsStakingProvider: boolean mappedOperators: { tbtc: string randomBeacon: string @@ -27,9 +27,9 @@ export const accountSlice = createSlice({ name: "account", initialState: { address: "", + isStakingProvider: false, operatorMapping: { data: { - isUsedAsStakingProvider: false, mappedOperators: { tbtc: AddressZero, randomBeacon: AddressZero, @@ -47,7 +47,7 @@ export const accountSlice = createSlice({ state: AccountState, action: PayloadAction ) => { - state.operatorMapping.data.isUsedAsStakingProvider = true + state.isStakingProvider = true }, setMappedOperator: ( state: AccountState, @@ -102,7 +102,7 @@ export const accountSlice = createSlice({ const { address } = state if (isSameETHAddress(stakingProvider, address)) { - state.operatorMapping.data.isUsedAsStakingProvider = true + state.isStakingProvider = true } } ) diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 9a8b6d992..6314ff4c2 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -188,11 +188,15 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( listenerApi.unsubscribe() try { - const { isUsedAsStakingProvider, mappedOperators } = - account.operatorMapping.data + const { + isStakingProvider, + operatorMapping: { + data: { mappedOperators }, + }, + } = account if ( - isUsedAsStakingProvider && + isStakingProvider && (isAddressZero(mappedOperators.tbtc) || isAddressZero(mappedOperators.randomBeacon)) ) { From 390eaea8ac74313b2a48458ab44c8b234971ef15 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 19 Oct 2022 08:41:37 +0200 Subject: [PATCH 38/41] Remove `mappedOperators` from store We don't need mapped operator in `account` slice because we already have `operatorMapping` property. --- .../useRegisterMultipleOperatorsTransaction.ts | 4 ++-- src/pages/Staking/index.tsx | 2 +- src/store/account/slice.ts | 17 +++++------------ src/store/staking-applications/effects.ts | 4 +--- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts index 0ebe1f2b1..5ea1cc39b 100644 --- a/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts +++ b/src/hooks/staking-applications/useRegisterMultipleOperatorsTransaction.ts @@ -10,10 +10,10 @@ import { useAppDispatch, useAppSelector } from "../store" export const useRegisterMultipleOperatorsTransaction = () => { const mappedOperatorTbtc = useAppSelector( - (state) => state.account.operatorMapping.data.mappedOperators.tbtc + (state) => state.account.operatorMapping.data.tbtc ) const mappedOperatorRandomBeacon = useAppSelector( - (state) => state.account.operatorMapping.data.mappedOperators.randomBeacon + (state) => state.account.operatorMapping.data.randomBeacon ) const { account } = useWeb3React() const { openModal, closeModal } = useModal() diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 5473d9488..3036210b1 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -50,7 +50,7 @@ const StakingPage: PageComponent = (props) => { isStakingProvider, operatorMapping: { isInitialFetchDone: isOperatorMappingInitialFetchDone, - data: { mappedOperators }, + data: mappedOperators, }, } = useAppSelector((state) => state.account) diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index 47e3f97a8..13f71a02f 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -15,12 +15,7 @@ import { getStakingProviderOperatorInfo } from "./effects" interface AccountState { address: string isStakingProvider: boolean - operatorMapping: FetchingState<{ - mappedOperators: { - tbtc: string - randomBeacon: string - } - }> + operatorMapping: FetchingState> } export const accountSlice = createSlice({ @@ -30,10 +25,8 @@ export const accountSlice = createSlice({ isStakingProvider: false, operatorMapping: { data: { - mappedOperators: { - tbtc: AddressZero, - randomBeacon: AddressZero, - }, + tbtc: AddressZero, + randomBeacon: AddressZero, }, isFetching: false, isInitialFetchDone: false, @@ -57,7 +50,7 @@ export const accountSlice = createSlice({ }> ) => { const { appName, operator } = action.payload - state.operatorMapping.data.mappedOperators[appName] = operator + state.operatorMapping.data[appName] = operator }, setFetchingOperatorMapping: ( state: AccountState, @@ -89,7 +82,7 @@ export const accountSlice = createSlice({ }> ) => { const { appName, operator } = action.payload - state.operatorMapping.data.mappedOperators[appName] = operator + state.operatorMapping.data[appName] = operator }, }, extraReducers: (builder) => { diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index 6314ff4c2..da0e76785 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -190,9 +190,7 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( try { const { isStakingProvider, - operatorMapping: { - data: { mappedOperators }, - }, + operatorMapping: { data: mappedOperators }, } = account if ( From 7cf4736f217ed8dfb9a84c0fdc262a242f064d7d Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 19 Oct 2022 10:10:18 +0200 Subject: [PATCH 39/41] Refactor setMappingOperator reducer --- src/store/account/effects.ts | 18 ++++------------- src/store/account/slice.ts | 24 ++++++++++------------- src/store/staking-applications/effects.ts | 16 ++++++++------- src/store/staking-applications/slice.ts | 4 ++-- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/src/store/account/effects.ts b/src/store/account/effects.ts index 0f6aad168..f5f284b94 100644 --- a/src/store/account/effects.ts +++ b/src/store/account/effects.ts @@ -5,9 +5,8 @@ import { setStakes } from "../staking" import { accountUsedAsStakingProvider, accountSlice, - operatorMappingInitialFetchDone, setFetchingOperatorMapping, - setMappedOperator, + setMappedOperators, } from "./slice" export const getStakingProviderOperatorInfo = async ( @@ -52,20 +51,11 @@ export const getStakingProviderOperatorInfo = async ( ) listenerApi.dispatch( - setMappedOperator({ - appName: "tbtc", - operator: mappedOperators.tbtc, + setMappedOperators({ + tbtc: mappedOperators.tbtc, + randomBeacon: mappedOperators.randomBeacon, }) ) - - listenerApi.dispatch( - setMappedOperator({ - appName: "randomBeacon", - operator: mappedOperators.randomBeacon, - }) - ) - - listenerApi.dispatch(operatorMappingInitialFetchDone()) } catch (error) { listenerApi.dispatch( accountSlice.actions.setFetchingOperatorMapping({ diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index 13f71a02f..a80a832ec 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -42,15 +42,19 @@ export const accountSlice = createSlice({ ) => { state.isStakingProvider = true }, - setMappedOperator: ( + setMappedOperators: ( state: AccountState, action: PayloadAction<{ - appName: StakingAppName - operator: string + tbtc: string + randomBeacon: string }> ) => { - const { appName, operator } = action.payload - state.operatorMapping.data[appName] = operator + const { tbtc, randomBeacon } = action.payload + state.operatorMapping.data.tbtc = tbtc + state.operatorMapping.data.randomBeacon = randomBeacon + state.operatorMapping.isFetching = false + state.operatorMapping.isInitialFetchDone = true + state.operatorMapping.error = "" }, setFetchingOperatorMapping: ( state: AccountState, @@ -59,13 +63,6 @@ export const accountSlice = createSlice({ const { isFetching } = action.payload state.operatorMapping.isFetching = isFetching }, - operatorMappingInitialFetchDone: ( - state: AccountState, - action: PayloadAction - ) => { - state.operatorMapping.isFetching = false - state.operatorMapping.isInitialFetchDone = true - }, setOperatorMappingError: ( state: AccountState, action: PayloadAction<{ error: string }> @@ -115,9 +112,8 @@ registerAccountListeners() export const { walletConnected, accountUsedAsStakingProvider, - setMappedOperator, + setMappedOperators, setFetchingOperatorMapping, - operatorMappingInitialFetchDone, setOperatorMappingError, operatorRegistered, } = accountSlice.actions diff --git a/src/store/staking-applications/effects.ts b/src/store/staking-applications/effects.ts index da0e76785..86ba37261 100644 --- a/src/store/staking-applications/effects.ts +++ b/src/store/staking-applications/effects.ts @@ -188,23 +188,25 @@ export const displayMapOperatorToStakingProviderModalEffect = async ( listenerApi.unsubscribe() try { + const { isStakingProvider } = account + const { - isStakingProvider, - operatorMapping: { data: mappedOperators }, - } = account + tbtc: mappedOperatorTbtc, + randomBeacon: mappedOperatorRandomBeacon, + } = action.payload if ( isStakingProvider && - (isAddressZero(mappedOperators.tbtc) || - isAddressZero(mappedOperators.randomBeacon)) + (isAddressZero(mappedOperatorTbtc) || + isAddressZero(mappedOperatorRandomBeacon)) ) { listenerApi.dispatch( openModal({ modalType: ModalType.MapOperatorToStakingProvider, props: { address, - mappedOperatorTbtc: mappedOperators.tbtc, - mappedOperatorRandomBeacon: mappedOperators.randomBeacon, + mappedOperatorTbtc: mappedOperatorTbtc, + mappedOperatorRandomBeacon: mappedOperatorRandomBeacon, }, }) ) diff --git a/src/store/staking-applications/slice.ts b/src/store/staking-applications/slice.ts index 1b9d18482..4fdeb67d1 100644 --- a/src/store/staking-applications/slice.ts +++ b/src/store/staking-applications/slice.ts @@ -18,7 +18,7 @@ import { displayDeauthrizationCompletedModalEffect, displayDeauthrizationInitiatedModalEffect, } from "./effects" -import { operatorMappingInitialFetchDone } from "../account" +import { setMappedOperators } from "../account" type StakingApplicationDataByStakingProvider = { [stakingProvider: string]: StakingProviderAppInfo @@ -277,7 +277,7 @@ export const registerStakingAppsListeners = () => { }) startAppListening({ - actionCreator: operatorMappingInitialFetchDone, + actionCreator: setMappedOperators, effect: displayMapOperatorToStakingProviderModalEffect, }) } From 111117d9eb9b07ada32e7e4e501e357ee07f942c Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 19 Oct 2022 15:07:03 +0200 Subject: [PATCH 40/41] Remove setFetchingOperatorMapping Rename the `setFetchingOperatorMapping` action to `fetchingOperatorMapping` and set the fetching to true automatically. --- src/store/account/effects.ts | 15 ++++++--------- src/store/account/slice.ts | 10 +++------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/store/account/effects.ts b/src/store/account/effects.ts index f5f284b94..a4f23ecbc 100644 --- a/src/store/account/effects.ts +++ b/src/store/account/effects.ts @@ -5,7 +5,7 @@ import { setStakes } from "../staking" import { accountUsedAsStakingProvider, accountSlice, - setFetchingOperatorMapping, + fetchingOperatorMapping, setMappedOperators, } from "./slice" @@ -38,11 +38,8 @@ export const getStakingProviderOperatorInfo = async ( if (!isStakingProvider) return - listenerApi.dispatch( - setFetchingOperatorMapping({ - isFetching: true, - }) - ) + listenerApi.dispatch(fetchingOperatorMapping()) + listenerApi.dispatch(accountUsedAsStakingProvider()) const mappedOperators = @@ -56,10 +53,10 @@ export const getStakingProviderOperatorInfo = async ( randomBeacon: mappedOperators.randomBeacon, }) ) - } catch (error) { + } catch (error: any) { listenerApi.dispatch( - accountSlice.actions.setFetchingOperatorMapping({ - isFetching: false, + accountSlice.actions.setOperatorMappingError({ + error, }) ) throw new Error("Could not load staking provider's operator info: " + error) diff --git a/src/store/account/slice.ts b/src/store/account/slice.ts index a80a832ec..88cd21cf0 100644 --- a/src/store/account/slice.ts +++ b/src/store/account/slice.ts @@ -56,12 +56,8 @@ export const accountSlice = createSlice({ state.operatorMapping.isInitialFetchDone = true state.operatorMapping.error = "" }, - setFetchingOperatorMapping: ( - state: AccountState, - action: PayloadAction<{ isFetching: boolean }> - ) => { - const { isFetching } = action.payload - state.operatorMapping.isFetching = isFetching + fetchingOperatorMapping: (state: AccountState) => { + state.operatorMapping.isFetching = true }, setOperatorMappingError: ( state: AccountState, @@ -113,7 +109,7 @@ export const { walletConnected, accountUsedAsStakingProvider, setMappedOperators, - setFetchingOperatorMapping, + fetchingOperatorMapping, setOperatorMappingError, operatorRegistered, } = accountSlice.actions From 96105de2008a529d156597a8b3b94947085c30c1 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Wed, 19 Oct 2022 15:11:44 +0200 Subject: [PATCH 41/41] Fix validation in OperatorToStakingProvider form --- .../MapOperatorToStakingProviderForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx index 68ad8680b..d87056062 100644 --- a/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx +++ b/src/components/Modal/MapOperatorToStakingProviderModal/MapOperatorToStakingProviderForm.tsx @@ -63,7 +63,7 @@ const validateInputtedOperatorAddress = async ( !isSameETHAddress(operator, mappedOperatorTbtc) ) { validationMsg = - "The operator address doesn't match the one used in random beacon app" + "The operator address doesn't match the one used in tbtc app" } } catch (error) { console.error("`MapOperatorToStakingProviderForm` validation error.", error)