import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { type Address } from 'viem' import { type Token } from '@/utils/types' import { getRoutePossibilities, getSymbol, } from '@/utils/routeMaker/generateRoutePossibilities' import { getFromChainIds } from '@/utils/routeMaker/getFromChainIds' import { getFromTokens } from '@/utils/routeMaker/getFromTokens' import { getToChainIds } from '@/utils/routeMaker/getToChainIds' import { getToTokens } from '@/utils/routeMaker/getToTokens' import { findTokenByRouteSymbol } from '@/utils/findTokenByRouteSymbol' import { findValidToken } from '@/utils/findValidToken' import { isActiveChainId } from '@/constants/chains' export interface BridgeState { fromChainId: number fromToken: Token toChainId: number toToken: Token fromChainIds: number[] toChainIds: number[] fromTokens: Token[] toTokens: Token[] debouncedFromValue: string debouncedToTokensFromValue: string deadlineMinutes: number | null destinationAddress: Address | null } const { fromChainId, fromToken, toChainId, toToken, fromChainIds, fromTokens, toChainIds, toTokens, } = getRoutePossibilities({ fromChainId: null, fromToken: null, toChainId: null, toToken: null, }) export const initialState: BridgeState = { fromChainId, fromToken, toChainId, toToken, fromChainIds, toChainIds, fromTokens, toTokens, debouncedFromValue: '', debouncedToTokensFromValue: '', deadlineMinutes: null, destinationAddress: null, } export const bridgeSlice = createSlice({ name: 'bridge', initialState, reducers: { setFromChainId: (state, action: PayloadAction) => { const incomingFromChainId = action.payload if ( incomingFromChainId !== null && !isActiveChainId(incomingFromChainId) ) { return } const validFromTokens = getFromTokens({ fromChainId: incomingFromChainId ?? null, fromTokenRouteSymbol: state.fromToken?.routeSymbol ?? null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) const validToChainIds = getToChainIds({ fromChainId: incomingFromChainId ?? null, fromTokenRouteSymbol: null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: null, }) const validToTokens = getToTokens({ fromChainId: incomingFromChainId ?? null, fromTokenRouteSymbol: state.fromToken?.routeSymbol ?? null, toChainId: null, toTokenRouteSymbol: null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) let validFromToken let validToChainId let validToToken if ( validFromTokens?.some( (token) => token?.routeSymbol === state.fromToken?.routeSymbol ) ) { validFromToken = state.fromToken } else { validFromToken = findValidToken( validFromTokens, state.toToken?.routeSymbol, state.toToken?.swapableType ) } if ( validToChainIds?.includes(state.toChainId) && incomingFromChainId !== state.toChainId ) { validToChainId = state.toChainId } else { validToChainId = null } if ( validToTokens?.some( (token) => token?.routeSymbol === state.toToken?.routeSymbol ) ) { validToToken = state.toToken } else { validToToken = findValidToken( validToTokens, state.fromToken?.routeSymbol, state.fromToken?.swapableType ) } const { fromChainId, fromToken, toChainId, toToken, fromChainIds, fromTokens, toChainIds, toTokens, } = getRoutePossibilities({ fromChainId: incomingFromChainId, fromToken: validFromToken, toChainId: validToChainId, toToken: validToToken, }) state.fromChainId = fromChainId state.fromToken = fromToken state.toChainId = toChainId state.toToken = toToken state.fromChainIds = fromChainIds state.fromTokens = fromTokens state.toChainIds = toChainIds state.toTokens = toTokens }, setFromToken: (state, action: PayloadAction) => { const incomingFromToken = action.payload const validFromChainIds = getFromChainIds({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: incomingFromToken?.routeSymbol ?? null, toChainId: null, toTokenRouteSymbol: null, }) if (!incomingFromToken || !validFromChainIds?.length) { return } const validToChainIds = getToChainIds({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: incomingFromToken?.routeSymbol ?? null, toChainId: null, toTokenRouteSymbol: null, }) const validToTokens = getToTokens({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: incomingFromToken?.routeSymbol ?? null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) let validFromChainId let validToChainId let validToToken if (validFromChainIds?.includes(state.fromChainId)) { validFromChainId = state.fromChainId } else { validFromChainId = null } if (validToChainIds?.includes(state.toChainId)) { validToChainId = state.toChainId } else { validToChainId = null } if ( validToTokens?.some( (token) => token?.routeSymbol === state.toToken?.routeSymbol ) ) { validToToken = state.toToken } else { validToToken = findValidToken( validToTokens, incomingFromToken?.routeSymbol, incomingFromToken?.swapableType ) } const { fromChainId, fromToken, toChainId, toToken, fromChainIds, fromTokens, toChainIds, toTokens, } = getRoutePossibilities({ fromChainId: validFromChainId, fromToken: incomingFromToken, toChainId: validToChainId, toToken: validToToken, }) state.fromChainId = fromChainId state.fromToken = fromToken state.toToken = state.toChainId ? toToken : null state.toChainId = toChainId state.fromChainIds = fromChainIds state.fromTokens = fromTokens state.toChainIds = toChainIds state.toTokens = toTokens }, setToChainId: (state, action: PayloadAction) => { const incomingToChainId = action.payload if (incomingToChainId !== null && !isActiveChainId(incomingToChainId)) { return } const validFromChainIds = getFromChainIds({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: null, toChainId: incomingToChainId ?? null, toTokenRouteSymbol: null, }) const validFromTokens = getFromTokens({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: state.fromToken?.routeSymbol ?? null, toChainId: incomingToChainId ?? null, toTokenRouteSymbol: state.toToken?.routeSymbol ?? null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) const validToTokens = getToTokens({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: state.fromToken?.routeSymbol ?? null, toChainId: incomingToChainId ?? null, toTokenRouteSymbol: state.toToken?.routeSymbol ?? null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) let validFromChainId let validFromToken let validToToken if ( validFromChainIds?.includes(state.fromChainId) && incomingToChainId !== state.fromChainId ) { validFromChainId = state.fromChainId } else { validFromChainId = null } if ( validFromTokens?.some( (token) => token?.routeSymbol === state.fromToken?.routeSymbol ) ) { validFromToken = state.fromToken } else { validFromToken = findValidToken( validFromTokens, state.fromToken?.routeSymbol, state.fromToken?.swapableType ) } if ( validToTokens?.some( (token) => token?.routeSymbol === state.toToken?.routeSymbol ) ) { validToToken = state.toToken } else { validToToken = findValidToken( validToTokens, state.fromToken?.routeSymbol, state.fromToken?.swapableType ) } const { fromChainId, fromToken, toChainId, toToken, fromChainIds, fromTokens, toChainIds, toTokens, } = getRoutePossibilities({ fromChainId: validFromChainId, fromToken: validFromToken, toChainId: incomingToChainId, toToken: validToToken, }) state.fromChainId = fromChainId state.fromToken = fromToken state.toChainId = toChainId state.toToken = toToken state.fromChainIds = fromChainIds state.fromTokens = fromTokens state.toChainIds = toChainIds state.toTokens = toTokens }, setToToken: (state, action: PayloadAction) => { const incomingToToken = action.payload const validFromChainIds = getFromChainIds({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: incomingToToken?.routeSymbol ?? null, }) const validFromTokens = getFromTokens({ fromChainId: state.fromChainId ?? null, fromTokenRouteSymbol: state.fromToken?.routeSymbol ?? null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: incomingToToken?.routeSymbol ?? null, }) ?.map(getSymbol) .map((s) => findTokenByRouteSymbol(s)) .filter(Boolean) const validToChainIds = getToChainIds({ fromChainId: null, fromTokenRouteSymbol: null, toChainId: state.toChainId ?? null, toTokenRouteSymbol: incomingToToken?.routeSymbol ?? null, }) if (!incomingToToken || !validToChainIds?.length) { return } let validFromChainId let validFromToken let validToChainId if (validFromChainIds?.includes(state.fromChainId)) { validFromChainId = state.fromChainId } else { validFromChainId = null } if ( validFromTokens?.some( (token) => token?.routeSymbol === state.fromToken?.routeSymbol ) ) { validFromToken = state.fromToken } else { validFromToken = findValidToken( validFromTokens, incomingToToken?.routeSymbol, incomingToToken?.swapableType ) } if (validToChainIds?.includes(state.toChainId)) { validToChainId = state.toChainId } else { validToChainId = null } const { fromChainId, fromToken, toChainId, toToken, fromChainIds, fromTokens, toChainIds, toTokens, } = getRoutePossibilities({ fromChainId: validFromChainId, fromToken: validFromToken, toChainId: validToChainId, toToken: incomingToToken, }) state.fromChainId = fromChainId state.fromToken = fromToken state.toChainId = toChainId state.toToken = toToken state.fromChainIds = fromChainIds state.fromTokens = fromTokens state.toChainIds = toChainIds state.toTokens = toTokens }, updateDebouncedFromValue: (state, action: PayloadAction) => { state.debouncedFromValue = action.payload }, updateDebouncedToTokensFromValue: ( state, action: PayloadAction ) => { state.debouncedToTokensFromValue = action.payload }, setDeadlineMinutes: (state, action: PayloadAction) => { state.deadlineMinutes = action.payload }, setDestinationAddress: (state, action: PayloadAction
) => { state.destinationAddress = action.payload }, clearDestinationAddress: (state) => { state.destinationAddress = initialState.destinationAddress }, resetBridgeInputs: (state) => { state.fromChainId = initialState.fromChainId state.fromToken = initialState.fromToken state.toChainId = initialState.toChainId state.toToken = initialState.toToken state.debouncedFromValue = initialState.debouncedFromValue }, }, }) export const { updateDebouncedFromValue, updateDebouncedToTokensFromValue, setFromChainId, setToChainId, setFromToken, setToToken, setDeadlineMinutes, setDestinationAddress, resetBridgeInputs, clearDestinationAddress, } = bridgeSlice.actions export default bridgeSlice.reducer