Skip to content

Commit

Permalink
get default common tokens from ks setting (#2114)
Browse files Browse the repository at this point in the history
* get default common tokens from ks setting

* update logic of favorite tokens to adapt with common bases from api

* clean code

* migrate old state to new state on load

* update env

* update env

* fix comment

* update to handle lowercase address

* remove console.log
  • Loading branch information
XiaoYhun authored Jul 27, 2023
1 parent 24be3f7 commit 922c45f
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 72 deletions.
7 changes: 2 additions & 5 deletions src/components/SearchModal/CurrencyList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,15 @@ export function CurrencyRow({
return false
}

if (isTokenNative(currency, currency.chainId)) {
return !!favoriteTokens.includeNativeToken
}

if (currency.isToken) {
const addr = (currency as Token).address ?? ''
const addresses = favoriteTokens?.addresses ?? []
const addresses = favoriteTokens ?? []
return !!addresses?.includes(addr) || !!addresses?.includes(addr.toLowerCase())
}

return false
})()

const balanceComponent = hideBalance ? (
'******'
) : currencyBalance ? (
Expand Down
57 changes: 24 additions & 33 deletions src/components/SearchModal/CurrencySearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ const ButtonClear = styled.div`
gap: 5px;
cursor: pointer;
`
const MAX_FAVORITE_PAIR = 12

interface CurrencySearchProps {
isOpen: boolean
Expand Down Expand Up @@ -254,32 +253,15 @@ export function CurrencySearch({
const handleClickFavorite = useCallback(
(e: React.MouseEvent, currency: any) => {
e.stopPropagation()

const address = currency?.wrapped?.address || currency.address
if (!address) return

const currentList = favoriteTokens?.addresses || []
const isAddFavorite = isTokenNative(currency, currency.chainId)
? !favoriteTokens?.includeNativeToken
: !currentList.find(el => el === address) // else remove favorite
const curTotal =
currentList.filter(address => !!defaultTokens[address]).length + (favoriteTokens?.includeNativeToken ? 1 : 0)
if (isAddFavorite && curTotal === MAX_FAVORITE_PAIR) return

if (isTokenNative(currency, currency.chainId)) {
toggleFavoriteToken({
chainId,
isNative: true,
})
return
}

toggleFavoriteToken({
chainId,
address,
})
},
[chainId, favoriteTokens, toggleFavoriteToken, defaultTokens],
[chainId, toggleFavoriteToken],
)

// menu ui
Expand All @@ -292,20 +274,30 @@ export function CurrencySearch({
if (!Object.keys(defaultTokens).length) return
setLoadingCommon(true)
let result: (Token | Currency)[] = []
if (favoriteTokens?.includeNativeToken) {
result.push(NativeCurrencies[chainId])
}
const addressesToFetch: string[] = []
favoriteTokens?.addresses.forEach(address => {
if (defaultTokens[address]) {
result.push(defaultTokens[address])

favoriteTokens?.forEach(address => {
let token
Object.entries(defaultTokens).forEach(([add, t]) => {
if (add.toLowerCase() === address.toLowerCase()) {
token = t
}
})
if (token) {
result.push(token)
return
}
addressesToFetch.push(address)
})

if (addressesToFetch.length) {
const tokens = await fetchListTokenByAddresses(addressesToFetch, chainId)
result = result.concat(tokens)
// Sort the returned token list to match the order of the passed address list
result = result.concat(
tokens.sort((x, y) => {
return addressesToFetch.indexOf(x.wrapped.address) - addressesToFetch.indexOf(y.wrapped.address)
}),
)
}
setCommonTokens(result)
} catch (error) {
Expand Down Expand Up @@ -393,14 +385,13 @@ export function CurrencySearch({
const removeImportedToken = useCallback(
(token: Token) => {
removeToken(chainId, token.address)
if (favoriteTokens?.addresses?.includes(token.address))
// remove in favorite too
toggleFavoriteToken({
chainId,
address: token.address,
})

toggleFavoriteToken({
chainId,
address: token.address,
})
},
[chainId, toggleFavoriteToken, removeToken, favoriteTokens?.addresses],
[chainId, toggleFavoriteToken, removeToken],
)

const removeAllImportToken = () => {
Expand Down
2 changes: 2 additions & 0 deletions src/services/ksSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type KyberSwapConfig = {
elasticClient: ApolloClient<NormalizedCacheObject>
readProvider: AppJsonRpcProvider | undefined
connection: Connection | undefined
commonTokens?: string[]
}

export type KyberSwapConfigResponse = {
Expand All @@ -25,6 +26,7 @@ export type KyberSwapConfigResponse = {
blockSubgraph: string
classicSubgraph: string
elasticSubgraph: string
commonTokens?: string[]
}

export type KyberswapConfigurationResponse = {
Expand Down
3 changes: 3 additions & 0 deletions src/state/application/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ function getDefaultConfig(chainId: ChainId): KyberSwapConfigResponse {
blockSubgraph: (evm ? NETWORKS_INFO[chainId] : ethereumInfo).defaultBlockSubgraph,
elasticSubgraph: (evm ? NETWORKS_INFO[chainId] : ethereumInfo).elastic.defaultSubgraph,
classicSubgraph: (evm ? NETWORKS_INFO[chainId] : ethereumInfo).classic.defaultSubgraph,
commonTokens: undefined,
}
}

Expand Down Expand Up @@ -469,11 +470,13 @@ export const useKyberSwapConfig = (customChainId?: ChainId): KyberSwapConfig =>
elasticClient,
classicClient,
connection: isSolana(chainId) ? new Connection(config.rpc, { commitment: 'confirmed' }) : undefined,
commonTokens: config.commonTokens,
}
}, [
config.rpc,
config.isEnableBlockService,
config.prochart,
config.commonTokens,
readProvider,
blockClient,
elasticClient,
Expand Down
1 change: 1 addition & 0 deletions src/state/application/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ export default createReducer(initialState, builder =>
blockSubgraph,
elasticSubgraph,
classicSubgraph,
commonTokens: data.commonTokens,
},
}
}),
Expand Down
23 changes: 21 additions & 2 deletions src/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,31 @@ import tokenPrices from './tokenPrices'
import topTokens from './topTokens'
import transactions from './transactions/reducer'
import tutorial from './tutorial/reducer'
import user from './user/reducer'
import user, { UserState } from './user/reducer'
import vesting from './vesting/reducer'

const PERSISTED_KEYS: string[] = ['user', 'transactions', 'profile']
ENV_LEVEL < ENV_TYPE.PROD && PERSISTED_KEYS.push('customizeDexes')

// Migrate from old version to new version, prevent lost favorite tokens of user
const preloadedState: any = load({ states: PERSISTED_KEYS })
if ('user' in preloadedState) {
const userState: UserState = preloadedState.user
if (userState.favoriteTokensByChainId) {
userState.favoriteTokensByChainIdv2 = Object.entries(userState.favoriteTokensByChainId).reduce(
(acc, [chainId, obj]) => {
acc[chainId] = {}
obj.addresses.forEach((address: string) => {
acc[chainId][address.toLowerCase()] = true
})
return acc
},
{} as any,
)
userState.favoriteTokensByChainId = undefined
}
}

const store = configureStore({
devTools: process.env.NODE_ENV !== 'production',
reducer: {
Expand Down Expand Up @@ -110,7 +129,7 @@ const store = configureStore({
.concat(earningApi.middleware)
.concat(socialApi.middleware)
.concat(tokenApi.middleware),
preloadedState: load({ states: PERSISTED_KEYS }),
preloadedState,
})

const PREFIX_REDUX_PERSIST = 'redux_localstorage_simple_'
Expand Down
4 changes: 3 additions & 1 deletion src/state/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export const toggleTopTrendingTokens = createAction<void>('user/toggleTopTrendin

export type ToggleFavoriteTokenPayload = {
chainId: ChainId
} & ({ isNative?: false; address: string } | { isNative: true; address?: never })
address: string
newValue?: boolean
}
export const toggleFavoriteToken = createAction<ToggleFavoriteTokenPayload>('user/toggleFavoriteToken')
export const updateChainId = createAction<ChainId>('user/updateChainId')
export const updateTokenAnalysisSettings = createAction<string>('user/updateTokenAnalysisSettings')
Expand Down
37 changes: 29 additions & 8 deletions src/state/user/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useCallback, useMemo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useGetParticipantInfoQuery } from 'services/kyberAISubscription'

import { SUGGESTED_BASES } from 'constants/bases'
import { DEFAULT_SLIPPAGE_TESTNET, TERM_FILES_PATH } from 'constants/index'
import { SupportedLocale } from 'constants/locales'
import { PINNED_PAIRS } from 'constants/tokens'
Expand All @@ -16,6 +17,7 @@ import {
import useDebounce from 'hooks/useDebounce'
import { ParticipantInfo, ParticipantStatus } from 'pages/TrueSightV2/types'
import { AppDispatch, AppState } from 'state'
import { useKyberSwapConfig } from 'state/application/hooks'
import { useIsConnectingWallet, useSessionInfo } from 'state/authen/hooks'
import { useAppDispatch, useAppSelector } from 'state/hooks'
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
Expand Down Expand Up @@ -49,9 +51,11 @@ import {
updateUserSlippageTolerance,
updateUserSlippageToleranceForLineaTestnet,
} from 'state/user/actions'
import { CROSS_CHAIN_SETTING_DEFAULT, CrossChainSetting, VIEW_MODE, getFavoriteTokenDefault } from 'state/user/reducer'
import { CROSS_CHAIN_SETTING_DEFAULT, CrossChainSetting, VIEW_MODE } from 'state/user/reducer'
import { isAddress, isChristmasTime } from 'utils'

const MAX_FAVORITE_LIMIT = 12

function serializeToken(token: Token | WrappedTokenInfo): SerializedToken {
return {
chainId: token.chainId,
Expand Down Expand Up @@ -395,18 +399,35 @@ export function useToggleTopTrendingTokens(): () => void {

export const useUserFavoriteTokens = (chainId: ChainId) => {
const dispatch = useDispatch<AppDispatch>()
const { favoriteTokensByChainId } = useSelector((state: AppState) => state.user)
const { favoriteTokensByChainIdv2: favoriteTokensByChainId } = useSelector((state: AppState) => state.user)
const { commonTokens } = useKyberSwapConfig(chainId)
const defaultTokens = useMemo(() => {
return commonTokens || SUGGESTED_BASES[chainId || ChainId.MAINNET].map(e => e.address)
}, [commonTokens, chainId])

const favoriteTokens = useMemo(() => {
if (!chainId) return undefined
return favoriteTokensByChainId
? favoriteTokensByChainId[chainId] || getFavoriteTokenDefault(chainId)
: getFavoriteTokenDefault(chainId)
}, [chainId, favoriteTokensByChainId])
const favoritedTokens = favoriteTokensByChainId?.[chainId] || {}
const favoritedTokenAddresses = defaultTokens
.filter(address => favoritedTokens[address.toLowerCase()] !== false)
.concat(Object.keys(favoritedTokens).filter(address => favoritedTokens[address]))

return [...new Set(favoritedTokenAddresses.map(a => a.toLowerCase()))]
}, [chainId, favoriteTokensByChainId, defaultTokens])

const toggleFavoriteToken = useCallback(
(payload: ToggleFavoriteTokenPayload) => dispatch(toggleFavoriteTokenAction(payload)),
[dispatch],
(payload: ToggleFavoriteTokenPayload) => {
if (!favoriteTokens) return
const address = payload.address.toLowerCase()
// Is adding favorite and reached max limit
if (favoriteTokens.indexOf(address) < 0 && favoriteTokens.length >= MAX_FAVORITE_LIMIT) {
return
}
const newValue = favoriteTokens.indexOf(address) < 0

dispatch(toggleFavoriteTokenAction({ ...payload, newValue }))
},
[dispatch, favoriteTokens],
)

return { favoriteTokens, toggleFavoriteToken }
Expand Down
43 changes: 20 additions & 23 deletions src/state/user/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export type CrossChainSetting = {
enableExpressExecution: boolean
}

interface UserState {
export interface UserState {
// the timestamp of the last updateVersion action
lastUpdateVersionTimestamp?: number

Expand Down Expand Up @@ -101,7 +101,7 @@ interface UserState {
kyberAIDisplaySettings: {
[k: string]: boolean
}
favoriteTokensByChainId: Partial<
favoriteTokensByChainId?: Partial<
Record<
ChainId,
{
Expand All @@ -110,6 +110,14 @@ interface UserState {
}
>
>
favoriteTokensByChainIdv2: Partial<
Record<
ChainId,
{
[address: string]: boolean
}
>
>
readonly chainId: ChainId
acceptedTermVersion: number | null
viewMode: VIEW_MODE
Expand Down Expand Up @@ -181,6 +189,7 @@ const initialState: UserState = {
liquidationsOnCEX: true,
},
favoriteTokensByChainId: {},
favoriteTokensByChainIdv2: {},
chainId: ChainId.MAINNET,
acceptedTermVersion: null,
viewMode: VIEW_MODE.GRID,
Expand Down Expand Up @@ -296,31 +305,19 @@ export default createReducer(initialState, builder =>
.addCase(toggleKyberAIBanner, state => {
state.showKyberAIBanner = !state.showKyberAIBanner
})
.addCase(toggleFavoriteToken, (state, { payload: { chainId, isNative, address } }) => {
if (!state.favoriteTokensByChainId) {
state.favoriteTokensByChainId = {}
.addCase(toggleFavoriteToken, (state, { payload: { chainId, address, newValue } }) => {
if (!state.favoriteTokensByChainIdv2) {
state.favoriteTokensByChainIdv2 = {}
}

let favoriteTokens = state.favoriteTokensByChainId[chainId]
if (!favoriteTokens) {
favoriteTokens = getFavoriteTokenDefault(chainId)
state.favoriteTokensByChainId[chainId] = favoriteTokens
if (!state.favoriteTokensByChainIdv2[chainId]) {
state.favoriteTokensByChainIdv2[chainId] = {}
}

if (isNative) {
const previousValue = favoriteTokens.includeNativeToken
favoriteTokens.includeNativeToken = !previousValue
return
}

if (address) {
// this is intentionally added, to remove compiler error
const index = favoriteTokens.addresses.findIndex(addr => addr === address)
if (index === -1) {
favoriteTokens.addresses.push(address)
return
}
favoriteTokens.addresses.splice(index, 1)
const favoriteTokens = state.favoriteTokensByChainIdv2[chainId]
const lowercaseAddress = address.toLowerCase()
if (favoriteTokens) {
favoriteTokens[lowercaseAddress] = newValue !== undefined ? newValue : !favoriteTokens[lowercaseAddress]
}
})
.addCase(updateChainId, (state, { payload: chainId }) => {
Expand Down

0 comments on commit 922c45f

Please sign in to comment.