Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
2382/already claimed (#2394)
Browse files Browse the repository at this point in the history
* Updated state to store count of classified claims other than a boolean

* Updated the updater to store the count of classified claims

* Updated claims on other network banner to check according to claim counts

* Fixed issues with claim on multiple networks

- Updated state to add new dimension to claim info: account
  Otherwise when checking a different account the state would be
  preserved and would lead to bad data
- Refactored Updater to fix dependency on obj causing it to
  being stuck in a re-render loop
- Fixed logic that compared different types using `===` instead of `==`
- Fixed logic that was causing claim to be displayed when there were no claims

* Refactoring variable

Co-authored-by: Leandro <[email protected]>
  • Loading branch information
alfetopito and Leandro authored Feb 10, 2022
1 parent 451206f commit 9189731
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 39 deletions.
50 changes: 39 additions & 11 deletions src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import useChangeNetworks from 'hooks/useChangeNetworks'
import { useActiveWeb3React } from 'hooks/web3'
import NotificationBanner from '@src/custom/components/NotificationBanner'
import { AlertTriangle } from 'react-feather'
import { ClaimInfo } from 'state/claim/reducer'

const ChainSpan = styled.span``
const Wrapper = styled.div`
Expand Down Expand Up @@ -46,23 +47,50 @@ const Wrapper = styled.div`
}
`

/**
* Returns true when you shouldn't display the banner for the checkedChain
*/
function _shouldNotDisplayBannerForChain(
checkedChain: SupportedChainId,
chainId: number | undefined,
claimInfo: ClaimInfo
) {
const { available, total } = claimInfo
return (
// If this is the same network
// Important, the double equal comparison is intentional!
// Don't be dumb like me and change to triple equal and spend awhile figuring out why it doesn't work...
checkedChain == chainId ||
// If total claims is 0
total === 0 ||
// If there are no available
available === 0
)
}

function ClaimsOnOtherChainsBanner({ className }: { className?: string }) {
const { account, library, chainId } = useActiveWeb3React()
const { callback } = useChangeNetworks({ account, library, chainId })

const { hasClaimsOnOtherChains } = useClaimState()
const chainsWithClaims: SupportedChainId[] = useMemo(
() =>
Object.keys(hasClaimsOnOtherChains).reduce((acc, chain) => {
const checkedChain = chain as unknown as SupportedChainId
const chainHasClaim = hasClaimsOnOtherChains[checkedChain]
if (!chainHasClaim || checkedChain == chainId) return acc
const { claimInfoPerAccount, activeClaimAccount } = useClaimState()

const chainsWithClaims: SupportedChainId[] = useMemo(() => {
const claimInfoPerChain = claimInfoPerAccount[activeClaimAccount]

acc.push(checkedChain)
if (!claimInfoPerChain) return []

return Object.keys(claimInfoPerChain).reduce<SupportedChainId[]>((acc, chain) => {
const checkedChain = chain as unknown as SupportedChainId
const claimsCountOnChain = claimInfoPerChain[checkedChain]

if (_shouldNotDisplayBannerForChain(checkedChain, chainId, claimsCountOnChain)) {
return acc
}, [] as SupportedChainId[]),
[chainId, hasClaimsOnOtherChains]
)
}

acc.push(checkedChain)
return acc
}, [])
}, [activeClaimAccount, chainId, claimInfoPerAccount])

if (chainsWithClaims.length === 0) {
return null
Expand Down
9 changes: 6 additions & 3 deletions src/custom/state/claim/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createAction } from '@reduxjs/toolkit'
import { SupportedChainId } from 'constants/chains'
import { ClaimInfo } from 'state/claim/reducer'

export enum ClaimStatus {
DEFAULT = 'DEFAULT',
Expand Down Expand Up @@ -71,6 +72,8 @@ export const setSelectedAll = createAction<boolean>('claim/setSelectedAll')
// Claim UI reset sugar
export const resetClaimUi = createAction('claims/resetClaimUi')
// Claims on other chains
export const setHasClaimsOnOtherChains = createAction<{ chain: SupportedChainId; hasClaims: boolean }>(
'claims/setHasClaimsOnOtherChains'
)
export const setClaimsCount = createAction<{
chain: SupportedChainId
claimInfo: Partial<ClaimInfo>
account: string
}>('claims/setClaimsCount')
9 changes: 5 additions & 4 deletions src/custom/state/claim/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ import {
updateInvestError,
setEstimatedGas,
setIsTouched,
setHasClaimsOnOtherChains,
setClaimsCount,
} from '../actions'
import { EnhancedUserClaimData } from 'pages/Claim/types'
import { supportedChainId } from 'utils/supportedChainId'
import { AMOUNT_PRECISION } from 'constants/index'
import useIsMounted from 'hooks/useIsMounted'
import { ClaimInfo } from 'state/claim/reducer'

const CLAIMS_REPO_BRANCH = '2022-01-22-test-deployment-all-networks'
export const CLAIMS_REPO = `https://raw.githubusercontent.com/gnosis/cow-merkle-drop/${CLAIMS_REPO_BRANCH}/`
Expand Down Expand Up @@ -118,7 +119,7 @@ type Account = string | null | undefined
export type UserClaims = UserClaimData[]
export type RepoClaims = RepoClaimData[]

type ClassifiedUserClaims = {
export type ClassifiedUserClaims = {
available: UserClaims
expired: UserClaims
claimed: UserClaims
Expand Down Expand Up @@ -856,8 +857,8 @@ export function useClaimDispatchers() {
// reset claim ui
resetClaimUi: () => dispatch(resetClaimUi()),
// has claims on other chains
setHasClaimsOnOtherChains: (payload: { chain: SupportedChainId; hasClaims: boolean }) =>
dispatch(setHasClaimsOnOtherChains(payload)),
setClaimsCount: (payload: { chain: SupportedChainId; claimInfo: ClaimInfo; account: string }) =>
dispatch(setClaimsCount(payload)),
}),
[dispatch]
)
Expand Down
50 changes: 39 additions & 11 deletions src/custom/state/claim/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,31 @@ import {
updateInvestError,
setEstimatedGas,
setIsTouched,
setHasClaimsOnOtherChains,
setClaimsCount,
} from './actions'

export type ClaimsOnOtherChains = {
[chain in SupportedChainId]: boolean
export type ClaimInfo = {
total: number
available?: number | undefined
claimed?: number | undefined
expired?: number | undefined
}
const DEFAULT_CLAIM_INFO: ClaimInfo = {
total: 0,
}

type ClaimInfoPerChain = Record<SupportedChainId, ClaimInfo>

const DEFAULT_CLAIMS_ON_OTHER_CHAINS_STATE = {
[SupportedChainId.MAINNET]: false,
[SupportedChainId.RINKEBY]: false,
[SupportedChainId.XDAI]: false,
const DEFAULT_CLAIM_INFO_PER_CHAIN: ClaimInfoPerChain = {
[SupportedChainId.MAINNET]: { ...DEFAULT_CLAIM_INFO },
[SupportedChainId.XDAI]: { ...DEFAULT_CLAIM_INFO },
[SupportedChainId.RINKEBY]: { ...DEFAULT_CLAIM_INFO },
}

type ClaimInfoPerAccount = Record<string, ClaimInfoPerChain>

const DEFAULT_CLAIM_INFO_PER_ACCOUNT: ClaimInfoPerAccount = {}

export const initialState: ClaimState = {
// address/ENS address
inputAddress: '',
Expand All @@ -51,7 +63,7 @@ export const initialState: ClaimState = {
selected: [],
selectedAll: false,
// claims on other networks
hasClaimsOnOtherChains: DEFAULT_CLAIMS_ON_OTHER_CHAINS_STATE,
claimInfoPerAccount: { ...DEFAULT_CLAIM_INFO_PER_ACCOUNT },
}

export type InvestClaim = {
Expand Down Expand Up @@ -81,13 +93,29 @@ export type ClaimState = {
selected: number[]
selectedAll: boolean
// claims on other chains
hasClaimsOnOtherChains: ClaimsOnOtherChains
claimInfoPerAccount: ClaimInfoPerAccount
}

export default createReducer(initialState, (builder) =>
builder
.addCase(setHasClaimsOnOtherChains, (state, { payload }) => {
state.hasClaimsOnOtherChains[payload.chain] = payload.hasClaims
.addCase(setClaimsCount, (state, { payload }) => {
const { chain, claimInfo, account } = payload
state.claimInfoPerAccount[account] = state.claimInfoPerAccount[account] || {
...DEFAULT_CLAIM_INFO_PER_CHAIN,
}

const newState: ClaimInfo = { ...DEFAULT_CLAIM_INFO }

// Only update the value if present to avoid overwriting data fetched on another network
if (claimInfo.total !== undefined) newState.total = claimInfo.total
if (claimInfo.claimed !== undefined) newState.claimed = claimInfo.claimed
if (claimInfo.available !== undefined) newState.available = claimInfo.available
if (claimInfo.expired !== undefined) newState.expired = claimInfo.expired

state.claimInfoPerAccount[account][chain] = {
...state.claimInfoPerAccount[account][chain],
...newState,
}
})
.addCase(setInputAddress, (state, { payload }) => {
state.inputAddress = payload
Expand Down
77 changes: 67 additions & 10 deletions src/custom/state/claim/updater.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,81 @@
import { useEffect } from 'react'
import { useEffect, useMemo } from 'react'
import { SupportedChainId } from 'constants/chains'
import { useClaimDispatchers, useClaimState, useUserAvailableClaims } from './hooks'
import { ClassifiedUserClaims, useClaimDispatchers, useClaimState, useClassifiedUserClaims } from './hooks'
import { useActiveWeb3React } from 'hooks'
import { ClaimInfo } from 'state/claim/reducer'

export default function Updater() {
const { chainId } = useActiveWeb3React()
const { activeClaimAccount } = useClaimState()
const { setHasClaimsOnOtherChains } = useClaimDispatchers()
const { setClaimsCount } = useClaimDispatchers()

const { claims: mainnetAvailable } = useUserAvailableClaims(activeClaimAccount, SupportedChainId.MAINNET)
const { claims: gnosisAvailable } = useUserAvailableClaims(activeClaimAccount, SupportedChainId.XDAI)
// --- MAINNET ---
// Fetches all classified claims
const mainnetClaims = useClassifiedUserClaims(activeClaimAccount, SupportedChainId.MAINNET)
// De-normalizing to avoid react hook update nightmare
const {
total: mTotal,
expired: mExpired,
claimed: mClaimed,
available: mAvailable,
// Counts the claims, based on which is the current network
} = useMemo(() => _countClaims(mainnetClaims, chainId, SupportedChainId.MAINNET), [chainId, mainnetClaims])

// Stores it on redux
useEffect(() => {
setHasClaimsOnOtherChains({
if (!activeClaimAccount) return
setClaimsCount({
chain: SupportedChainId.MAINNET,
hasClaims: Boolean(mainnetAvailable && mainnetAvailable.length > 0),
claimInfo: { total: mTotal, expired: mExpired, claimed: mClaimed, available: mAvailable },
account: activeClaimAccount,
})
setHasClaimsOnOtherChains({
}, [activeClaimAccount, mAvailable, mClaimed, mExpired, mTotal, setClaimsCount])

// --- GCHAIN ---
const gChainClaims = useClassifiedUserClaims(activeClaimAccount, SupportedChainId.XDAI)
const {
total: gTotal,
expired: gExpired,
claimed: gClaimed,
available: gAvailable,
} = useMemo(() => _countClaims(gChainClaims, chainId, SupportedChainId.XDAI), [chainId, gChainClaims])

useEffect(() => {
if (!activeClaimAccount) return
setClaimsCount({
chain: SupportedChainId.XDAI,
hasClaims: Boolean(gnosisAvailable && gnosisAvailable.length > 0),
claimInfo: { total: gTotal, expired: gExpired, claimed: gClaimed, available: gAvailable },
account: activeClaimAccount,
})
}, [setHasClaimsOnOtherChains, mainnetAvailable, gnosisAvailable])
}, [activeClaimAccount, gAvailable, gClaimed, gExpired, gTotal, setClaimsCount])

return null
}

/**
* Counts claims per network
*/
function _countClaims(
mainnetClaims: ClassifiedUserClaims,
currentChainId: number | undefined,
chainId: SupportedChainId
) {
const { available, claimed, expired } = mainnetClaims

const count: ClaimInfo = {
// Total is easy, just add everything up
// This will always be accurate.
// When we only have airdrop repo as reference, everything will be `available`
// Otherwise the sum of all categories
total: claimed.length + available.length + expired.length,
}
// Only if we are in the network we want to check we are able to do smart contract calls
// and fetch contract data
// Otherwise the count would be replaced with outdated info
if (currentChainId === chainId) {
count.available = available.length
count.expired = expired.length
count.claimed = claimed.length
}
return count
}

0 comments on commit 9189731

Please sign in to comment.