Skip to content

Commit

Permalink
Merge pull request #2044 from keep-network/hide-copy-stake-banner-whe…
Browse files Browse the repository at this point in the history
…n-no-old-delegations

Hiding a copy stake banner when no old delegations available

Hide the copy stake banner when no delegations are available on the old token stake contracts. We do not want to confuse users with displaying them a banner when they don't have any old delegations in the first place.
  • Loading branch information
r-czajkowski authored Sep 9, 2020
2 parents ba99a44 + 0dffb00 commit 87613a5
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 34 deletions.
7 changes: 1 addition & 6 deletions solidity/dashboard/src/components/copy-stake-steps/Step1.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from "react"
import React from "react"
import TokenAmount from "../TokenAmount"
import Button from "../Button"
import { KeepLoadingIndicator } from "../Loadable"
Expand Down Expand Up @@ -26,18 +26,13 @@ const styles = {
}

const CopyStakeStep1 = ({
fetchDelegations,
isFetching,
delegations,
decrementStep,
incrementStep,
onSelectDelegation,
selectedDelegation,
}) => {
useEffect(() => {
fetchDelegations()
}, [fetchDelegations])

return (
<>
<h2 style={styles.title}>Stake balances to be upgraded.</h2>
Expand Down
4 changes: 0 additions & 4 deletions solidity/dashboard/src/pages/CopyStakePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
DECREMENT_STEP,
SET_STRATEGY,
SET_DELEGATION,
FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST,
RESET_COPY_STAKE_FLOW,
} from "../actions"
import { connect } from "react-redux"
Expand Down Expand Up @@ -72,7 +71,6 @@ const CopyStakePage = ({
isFetching={oldDelegationsFetching}
selectedDelegation={selectedDelegation}
onSelectDelegation={setDelegation}
fetchDelegations={fetchOldDelegations}
/>
)
case 2:
Expand Down Expand Up @@ -135,8 +133,6 @@ const mapDispatchToProps = (dispatch) => {
dispatch({ type: SET_STRATEGY, payload: strategy }),
setDelegation: (delegation) =>
dispatch({ type: SET_DELEGATION, payload: delegation }),
fetchOldDelegations: () =>
dispatch({ type: FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST }),
undelegateOldStake: (delegation) =>
dispatch({ type: "copy-stake/undelegate_request", payload: delegation }),
recoverOldStake: (delegation) =>
Expand Down
71 changes: 49 additions & 22 deletions solidity/dashboard/src/pages/TokensPageContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import {
TOP_UP_INITIATED,
TOP_UP_COMPLETED,
} from "../reducers/tokens-page.reducer.js"
import { FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST } from "../actions"
import { connect } from "react-redux"
import {
TOKEN_STAKING_CONTRACT_NAME,
TOKEN_GRANT_CONTRACT_NAME,
TOKEN_STAKING_ESCROW_CONTRACT_NAME,
} from "../constants/constants"
import { isSameEthAddress } from "../utils/general.utils"
import { sub, add } from "../utils/arithmetics.utils"
import { isEmptyArray } from "../utils/array.utils"
import moment from "moment"
import {
createManagedGrantContractInstance,
Expand All @@ -38,7 +41,7 @@ import Button from "../components/Button"
import { useModal } from "../hooks/useModal"
import CopyStakePage from "./CopyStakePage"

const TokensPageContainer = () => {
const TokensPageContainer = ({ oldDelegations, fetchOldDelegations }) => {
useSubscribeToStakedEvent()
useSubscribeToUndelegatedEvent()
useSubscribeToRecoveredStakeEvent()
Expand All @@ -55,24 +58,30 @@ const TokensPageContainer = () => {
}
}, [hash, dispatch])

useEffect(() => {
fetchOldDelegations()
}, [fetchOldDelegations])

const { openModal } = useModal()

return (
<>
<Banner
type={BANNER_TYPE.NOTIFICATION}
withIcon
title="New upgrade available for your stake delegations!"
titleClassName="h4"
subtitle="Upgrade now to keep earning rewards on your stake."
>
<Button
className="btn btn-tertiary btn-sm ml-a"
onClick={() => openModal(<CopyStakePage />, { isFullScreen: true })}
{!isEmptyArray(oldDelegations) && (
<Banner
type={BANNER_TYPE.NOTIFICATION}
withIcon
title="New upgrade available for your stake delegations!"
titleClassName="h4"
subtitle="Upgrade now to keep earning rewards on your stake."
>
upgrade my stake
</Button>
</Banner>
<Button
className="btn btn-tertiary btn-sm ml-a"
onClick={() => openModal(<CopyStakePage />, { isFullScreen: true })}
>
upgrade my stake
</Button>
</Banner>
)}
<Switch>
<Route exact path="/tokens/overview" component={TokenOverviewPage} />
<Route exact path="/tokens/delegate" component={TokensPage} />
Expand All @@ -83,14 +92,6 @@ const TokensPageContainer = () => {
)
}

const TokensPageContainerWithContext = () => (
<TokensPageContextProvider>
<TokensPageContainer />
</TokensPageContextProvider>
)

export default React.memo(TokensPageContainerWithContext)

const useSubscribeToStakedEvent = () => {
const {
initializationPeriod,
Expand Down Expand Up @@ -450,3 +451,29 @@ const useSubscribeToTopUpsEvents = () => {
subscribeToTopUpCompleted
)
}

const mapStateToProps = ({ copyStake }) => {
const { oldDelegations } = copyStake

return { oldDelegations }
}

const mapDispatchToProps = (dispatch) => {
return {
fetchOldDelegations: () =>
dispatch({ type: FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST }),
}
}

const TokensPageContainerWithRedux = connect(
mapStateToProps,
mapDispatchToProps
)(TokensPageContainer)

const TokensPageContainerWithContext = () => (
<TokensPageContextProvider>
<TokensPageContainerWithRedux />
</TokensPageContextProvider>
)

export default React.memo(TokensPageContainerWithContext)
10 changes: 10 additions & 0 deletions solidity/dashboard/src/reducers/copy-stake.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST,
RESET_COPY_STAKE_FLOW,
} from "../actions"
import { isSameEthAddress } from "../utils/general.utils"

export const copyStakeInitialData = {
oldDelegations: [],
Expand Down Expand Up @@ -90,6 +91,15 @@ const copyStakeReducer = (state = copyStakeInitialData, action) => {
isProcessing: false,
error: action.payload,
}
case "copy-stake/remove_old_delegation": {
return {
...state,
oldDelegations: state.oldDelegations.filter(
(delegation) =>
!isSameEthAddress(delegation.operatorAddress, action.payload)
),
}
}
default:
return state
}
Expand Down
42 changes: 40 additions & 2 deletions solidity/dashboard/src/sagas/copy-stake.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { takeLatest, call, put, delay } from "redux-saga/effects"
import { takeLatest, take, call, put, delay, fork } from "redux-saga/effects"
import {
FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_REQUEST,
FETCH_DELEGATIONS_FROM_OLD_STAKING_CONTRACT_SUCCESS,
Expand All @@ -7,7 +7,7 @@ import {
} from "../actions"
import { fetchOldDelegations } from "../services/staking-port-backer.service"
import { getContractsContext } from "./utils"
import { sendTransaction } from "./web3"
import { sendTransaction, createSubcribeToContractEventChannel } from "./web3"
import { CONTRACT_DEPLOY_BLOCK_NUMBER } from "../contracts"
import { showMessage, showCreatedMessage } from "../actions/messages"
import { isEmptyArray } from "../utils/array.utils"
Expand All @@ -29,6 +29,8 @@ function* fetchOldStakingDelegations() {
payload: error,
})
}

yield fork(observeEvents)
}

export function* watchFetchOldStakingContract() {
Expand Down Expand Up @@ -186,3 +188,39 @@ export function* watchUndelegateOldStakeRequest() {
export function* watchRecovereOldStakeRequest() {
yield takeLatest("copy-stake/recover_request", recoverFromOldStakingContract)
}

function* observeEvents() {
const { oldTokenStakingContract, stakingPortBackerContract } = yield call(
getContractsContext
)

yield fork(removeOldDelegationWatcher, oldTokenStakingContract, "Undelegated")
yield fork(
removeOldDelegationWatcher,
stakingPortBackerContract,
"StakeCopied"
)
yield fork(removeOldDelegationWatcher, oldTokenStakingContract, "Recovered")
}

function* removeOldDelegationWatcher(contract, eventName) {
// Create subscription channel.
const contractEventCahnnel = yield call(
createSubcribeToContractEventChannel,
contract,
eventName
)

// Observe and dispatch an action that updates copy-stake reducer.
while (true) {
try {
const {
returnValues: { operator },
} = yield take(contractEventCahnnel)
yield put({ type: "copy-stake/remove_old_delegation", payload: operator })
} catch (error) {
console.error(`Failed subscribing to ${eventName} event`, error)
contractEventCahnnel.close()
}
}
}
34 changes: 34 additions & 0 deletions solidity/dashboard/src/sagas/web3.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ function createTransactionEventChannel(contract, method, args, options) {
}, buffers.expanding())
}

export function createSubcribeToContractEventChannel(contract, eventName) {
const contractHasEvent = contract.options.jsonInterface.find(
(entry) => entry.type === "event" && entry.name === eventName
)
if (!contractHasEvent) {
return eventChannel((emit) => {
emit(END)

return () => {}
}, buffers.expanding())
}

const eventEmitter = contract.events[eventName]()
let eventTxCache = null

return eventChannel((emit) => {
eventEmitter
.on("data", (event) => {
if (eventTxCache !== event.transactionHash) {
eventTxCache = event.transactionHash
emit(event)
}
})
.on("error", () => {
emit(new Error())
emit(END)
})

return () => {
eventEmitter.unsubscribe()
}
})
}

export function* sendTransaction(action) {
const { contract, methodName, args, options } = action.payload

Expand Down

0 comments on commit 87613a5

Please sign in to comment.