@lifi/widget
Version:
LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.
126 lines (114 loc) • 4.29 kB
text/typescript
import { useCallback } from 'react'
import { useToAddressAutoPopulate } from '../../hooks/useToAddressAutoPopulate.js'
import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
import { useChainOrderStore } from '../../stores/chains/ChainOrderStore.js'
import type { FormType } from '../../stores/form/types.js'
import { FormKeyHelper } from '../../stores/form/types.js'
import { useFieldActions } from '../../stores/form/useFieldActions.js'
import { useSplitSubvariantStore } from '../../stores/settings/useSplitSubvariantStore.js'
import { WidgetEvent } from '../../types/events.js'
import type { DisabledUI } from '../../types/widget.js'
import { isItemAllowed } from '../../utils/item.js'
export const useTokenSelect = (formType: FormType, onClick?: () => void) => {
const { subvariant, disabledUI, chains: chainsConfig } = useWidgetConfig()
const splitSubvariant = useSplitSubvariantStore((store) => store.state)
const emitter = useWidgetEvents()
const { setFieldValue, getFieldValues } = useFieldActions()
const autoPopulateToAddress = useToAddressAutoPopulate()
const setChain = useChainOrderStore((state) => state.setChain)
const tokenKey = FormKeyHelper.getTokenKey(formType)
return useCallback(
(tokenAddress: string, chainId?: number) => {
setFieldValue(tokenKey, tokenAddress, { isDirty: true, isTouched: true })
const selectedChainId =
chainId ?? getFieldValues(FormKeyHelper.getChainKey(formType))[0]
// Set chain again to trigger URL builder update
setFieldValue(FormKeyHelper.getChainKey(formType), selectedChainId, {
isDirty: true,
isTouched: true,
})
const amountKey = FormKeyHelper.getAmountKey(formType)
if (!disabledUI?.includes(amountKey as DisabledUI)) {
setFieldValue(amountKey, '')
}
const oppositeFormType = formType === 'from' ? 'to' : 'from'
const [
selectedOppositeTokenAddress,
selectedOppositeChainId,
selectedToAddress,
] = getFieldValues(
FormKeyHelper.getTokenKey(oppositeFormType),
FormKeyHelper.getChainKey(oppositeFormType),
'toAddress'
)
// TODO: remove when we enable same chain/token transfers
const isSameTokenTransfer =
selectedOppositeTokenAddress === tokenAddress &&
selectedOppositeChainId === selectedChainId
const isBridgeToSameChain =
subvariant === 'split' &&
splitSubvariant === 'bridge' &&
selectedOppositeChainId === selectedChainId
if (
(isSameTokenTransfer || isBridgeToSameChain) &&
subvariant !== 'custom'
) {
setFieldValue(FormKeyHelper.getTokenKey(oppositeFormType), '', {
isDirty: true,
isTouched: true,
})
}
// If no opposite token is selected, synchronize the opposite chain
// to match the currently selected chain (if allowed)
if (
!selectedOppositeTokenAddress &&
selectedChainId &&
isItemAllowed(selectedChainId, chainsConfig?.[oppositeFormType])
) {
setFieldValue(
FormKeyHelper.getChainKey(oppositeFormType),
selectedChainId,
{
isDirty: true,
isTouched: true,
}
)
setChain(selectedChainId, oppositeFormType)
}
// Automatically populate toAddress field if bridging across ecosystems and compatible wallet is connected
autoPopulateToAddress({
formType,
selectedToAddress,
selectedChainId,
selectedOppositeChainId,
selectedOppositeTokenAddress,
})
const eventToEmit =
formType === 'from'
? WidgetEvent.SourceChainTokenSelected
: WidgetEvent.DestinationChainTokenSelected
if (selectedChainId) {
emitter.emit(eventToEmit, {
chainId: selectedChainId,
tokenAddress,
})
}
onClick?.()
},
[
autoPopulateToAddress,
disabledUI,
emitter,
formType,
getFieldValues,
onClick,
setChain,
setFieldValue,
subvariant,
splitSubvariant,
tokenKey,
chainsConfig,
]
)
}