@lifi/widget 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -3
- package/dist/esm/App.d.ts +1 -2
- package/dist/esm/App.d.ts.map +1 -1
- package/dist/esm/AppDrawer.d.ts +1 -2
- package/dist/esm/AppDrawer.d.ts.map +1 -1
- package/dist/esm/components/ActionRow/ActionRow.d.ts +1 -2
- package/dist/esm/components/ActionRow/ActionRow.d.ts.map +1 -1
- package/dist/esm/components/AmountInput/AmountInput.style.d.ts +2 -2
- package/dist/esm/components/AmountInput/AmountInput.style.d.ts.map +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.d.ts +1 -2
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.d.ts.map +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.style.d.ts +1 -2
- package/dist/esm/components/AmountInput/PriceFormHelperText.style.d.ts.map +1 -1
- package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js +6 -2
- package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js.map +1 -1
- package/dist/esm/components/Avatar/Avatar.d.ts +1 -2
- package/dist/esm/components/Avatar/Avatar.d.ts.map +1 -1
- package/dist/esm/components/Avatar/TokenAvatar.d.ts +1 -2
- package/dist/esm/components/Avatar/TokenAvatar.d.ts.map +1 -1
- package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.d.ts +1 -2
- package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.d.ts.map +1 -1
- package/dist/esm/components/BaseTransactionButton/types.d.ts +1 -2
- package/dist/esm/components/BaseTransactionButton/types.d.ts.map +1 -1
- package/dist/esm/components/BottomSheet/BottomSheet.js +1 -0
- package/dist/esm/components/BottomSheet/BottomSheet.js.map +1 -1
- package/dist/esm/components/BottomSheet/types.d.ts +1 -2
- package/dist/esm/components/BottomSheet/types.d.ts.map +1 -1
- package/dist/esm/components/ButtonTertiary.d.ts +1 -2
- package/dist/esm/components/ButtonTertiary.d.ts.map +1 -1
- package/dist/esm/components/Card/CardIconButton.d.ts +1 -2
- package/dist/esm/components/Card/CardIconButton.d.ts.map +1 -1
- package/dist/esm/components/Card/CardTitle.d.ts +1 -2
- package/dist/esm/components/Card/CardTitle.d.ts.map +1 -1
- package/dist/esm/components/Card/InputCard.d.ts +1 -2
- package/dist/esm/components/Card/InputCard.d.ts.map +1 -1
- package/dist/esm/components/ChainSelect/ChainSelect.d.ts +1 -2
- package/dist/esm/components/ChainSelect/ChainSelect.d.ts.map +1 -1
- package/dist/esm/components/ChainSelect/ChainSelect.style.d.ts +1 -2
- package/dist/esm/components/ChainSelect/ChainSelect.style.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/ContractComponent.d.ts +1 -2
- package/dist/esm/components/ContractComponent/ContractComponent.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/ItemPrice.d.ts +2 -3
- package/dist/esm/components/ContractComponent/ItemPrice.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/NFT/NFT.d.ts +1 -2
- package/dist/esm/components/ContractComponent/NFT/NFT.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/NFT/NFTBase.d.ts +1 -2
- package/dist/esm/components/ContractComponent/NFT/NFTBase.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/NFT/types.d.ts +3 -4
- package/dist/esm/components/ContractComponent/NFT/types.d.ts.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/ExecutionStatusCard.d.ts +1 -2
- package/dist/esm/components/ExecutionStatusCard/ExecutionStatusCard.d.ts.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/StatusIcon.d.ts +1 -2
- package/dist/esm/components/ExecutionStatusCard/StatusIcon.d.ts.map +1 -1
- package/dist/esm/components/FeeBreakdownTooltip.d.ts +1 -2
- package/dist/esm/components/FeeBreakdownTooltip.d.ts.map +1 -1
- package/dist/esm/components/IconCircle/IconCircle.d.ts +1 -2
- package/dist/esm/components/IconCircle/IconCircle.d.ts.map +1 -1
- package/dist/esm/components/IconCircle/statusIcons.d.ts +1 -2
- package/dist/esm/components/IconCircle/statusIcons.d.ts.map +1 -1
- package/dist/esm/components/IconTypography.d.ts +1 -2
- package/dist/esm/components/IconTypography.d.ts.map +1 -1
- package/dist/esm/components/ListItem/ListItemButton.d.ts +1 -2
- package/dist/esm/components/ListItem/ListItemButton.d.ts.map +1 -1
- package/dist/esm/components/Messages/WarningMessages.d.ts +1 -2
- package/dist/esm/components/Messages/WarningMessages.d.ts.map +1 -1
- package/dist/esm/components/PageContainer.d.ts +2 -3
- package/dist/esm/components/PageContainer.d.ts.map +1 -1
- package/dist/esm/components/PoweredBy/PoweredBy.d.ts +1 -2
- package/dist/esm/components/PoweredBy/PoweredBy.d.ts.map +1 -1
- package/dist/esm/components/ProgressToNextUpdate.d.ts +1 -2
- package/dist/esm/components/ProgressToNextUpdate.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteCard.d.ts +1 -2
- package/dist/esm/components/RouteCard/RouteCard.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteCardSkeleton.d.ts +1 -2
- package/dist/esm/components/RouteCard/RouteCardSkeleton.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteDetails.d.ts +1 -2
- package/dist/esm/components/RouteCard/RouteDetails.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteDetails.style.d.ts +5 -6
- package/dist/esm/components/RouteCard/RouteDetails.style.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteNotFoundCard.d.ts +1 -2
- package/dist/esm/components/RouteCard/RouteNotFoundCard.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/RouteTokens.d.ts +1 -2
- package/dist/esm/components/RouteCard/RouteTokens.d.ts.map +1 -1
- package/dist/esm/components/RouteCard/types.d.ts +2 -3
- package/dist/esm/components/RouteCard/types.d.ts.map +1 -1
- package/dist/esm/components/Search/SearchInput.d.ts +1 -2
- package/dist/esm/components/Search/SearchInput.d.ts.map +1 -1
- package/dist/esm/components/SendToWallet/SendToWalletButton.d.ts +1 -2
- package/dist/esm/components/SendToWallet/SendToWalletButton.d.ts.map +1 -1
- package/dist/esm/components/Skeleton/WidgetSkeleton.d.ts +1 -2
- package/dist/esm/components/Skeleton/WidgetSkeleton.d.ts.map +1 -1
- package/dist/esm/components/StepActions/SentToWalletRow.d.ts +1 -2
- package/dist/esm/components/StepActions/SentToWalletRow.d.ts.map +1 -1
- package/dist/esm/components/StepActions/StepActionRow.style.d.ts +1 -2
- package/dist/esm/components/StepActions/StepActionRow.style.d.ts.map +1 -1
- package/dist/esm/components/StepActions/StepActionsList.d.ts +1 -2
- package/dist/esm/components/StepActions/StepActionsList.d.ts.map +1 -1
- package/dist/esm/components/StepActions/executionRows.d.ts +2 -3
- package/dist/esm/components/StepActions/executionRows.d.ts.map +1 -1
- package/dist/esm/components/Token/Token.d.ts.map +1 -1
- package/dist/esm/components/Token/Token.js +2 -4
- package/dist/esm/components/Token/Token.js.map +1 -1
- package/dist/esm/components/TokenList/RecentTokensHeader.js +44 -0
- package/dist/esm/components/TokenList/RecentTokensHeader.js.map +1 -0
- package/dist/esm/components/TokenList/RecentTokensToggle.js +36 -0
- package/dist/esm/components/TokenList/RecentTokensToggle.js.map +1 -0
- package/dist/esm/components/TokenList/RemoveRecentTokenButton.js +32 -0
- package/dist/esm/components/TokenList/RemoveRecentTokenButton.js.map +1 -0
- package/dist/esm/components/TokenList/TokenList.js +55 -5
- package/dist/esm/components/TokenList/TokenList.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +35 -19
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenList/TokenNotFound.d.ts +1 -2
- package/dist/esm/components/TokenList/TokenNotFound.d.ts.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts +1 -2
- package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js +55 -42
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/components/TokenList/types.d.ts +9 -2
- package/dist/esm/components/TokenList/types.d.ts.map +1 -1
- package/dist/esm/components/TokenList/useTokenSelect.d.ts +1 -2
- package/dist/esm/components/TokenList/useTokenSelect.d.ts.map +1 -1
- package/dist/esm/components/TokenRate/TokenRate.d.ts +1 -2
- package/dist/esm/components/TokenRate/TokenRate.d.ts.map +1 -1
- package/dist/esm/components/TransactionCard/TransactionCard.style.d.ts +2 -3
- package/dist/esm/components/TransactionCard/TransactionCard.style.d.ts.map +1 -1
- package/dist/esm/config/constants.d.ts +1 -2
- package/dist/esm/config/constants.d.ts.map +1 -1
- package/dist/esm/config/version.d.ts +2 -3
- package/dist/esm/config/version.d.ts.map +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/useAddressActivity.d.ts +1 -2
- package/dist/esm/hooks/useAddressActivity.d.ts.map +1 -1
- package/dist/esm/hooks/useAddressValidation.d.ts +2 -3
- package/dist/esm/hooks/useAddressValidation.d.ts.map +1 -1
- package/dist/esm/hooks/useAvailableChains.d.ts +1 -2
- package/dist/esm/hooks/useAvailableChains.d.ts.map +1 -1
- package/dist/esm/hooks/useChain.d.ts +1 -2
- package/dist/esm/hooks/useChain.d.ts.map +1 -1
- package/dist/esm/hooks/useContactSupport.d.ts +1 -2
- package/dist/esm/hooks/useContactSupport.d.ts.map +1 -1
- package/dist/esm/hooks/useDebouncedWatch.d.ts +1 -2
- package/dist/esm/hooks/useDebouncedWatch.d.ts.map +1 -1
- package/dist/esm/hooks/useDisplayedTokens.js +6 -4
- package/dist/esm/hooks/useDisplayedTokens.js.map +1 -1
- package/dist/esm/hooks/useExplorer.d.ts +1 -2
- package/dist/esm/hooks/useExplorer.d.ts.map +1 -1
- package/dist/esm/hooks/useHeader.d.ts +1 -2
- package/dist/esm/hooks/useHeader.d.ts.map +1 -1
- package/dist/esm/hooks/useListHeight.d.ts +1 -2
- package/dist/esm/hooks/useListHeight.d.ts.map +1 -1
- package/dist/esm/hooks/useNavigateBack.d.ts +1 -2
- package/dist/esm/hooks/useNavigateBack.d.ts.map +1 -1
- package/dist/esm/hooks/useRecentTokens.js +46 -0
- package/dist/esm/hooks/useRecentTokens.js.map +1 -0
- package/dist/esm/hooks/useRouteExecution.d.ts +1 -2
- package/dist/esm/hooks/useRouteExecution.d.ts.map +1 -1
- package/dist/esm/hooks/useRouteExecutionMessage.d.ts +1 -2
- package/dist/esm/hooks/useRouteExecutionMessage.d.ts.map +1 -1
- package/dist/esm/hooks/useRoutes.d.ts +1 -2
- package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
- package/dist/esm/hooks/useRoutes.js +7 -2
- package/dist/esm/hooks/useRoutes.js.map +1 -1
- package/dist/esm/hooks/useToAddressRequirements.d.ts +1 -2
- package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
- package/dist/esm/hooks/useToAddressRequirements.js +8 -2
- package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
- package/dist/esm/hooks/useToken.d.ts +1 -2
- package/dist/esm/hooks/useToken.d.ts.map +1 -1
- package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -2
- package/dist/esm/hooks/useTokenAddressBalance.d.ts.map +1 -1
- package/dist/esm/hooks/useTokenBalances.d.ts +3 -2
- package/dist/esm/hooks/useTokenBalances.d.ts.map +1 -1
- package/dist/esm/hooks/useTokenBalances.js +15 -9
- package/dist/esm/hooks/useTokenBalances.js.map +1 -1
- package/dist/esm/hooks/useTokenList.d.ts +1 -2
- package/dist/esm/hooks/useTokenList.d.ts.map +1 -1
- package/dist/esm/hooks/useTokenSearch.js +3 -2
- package/dist/esm/hooks/useTokenSearch.js.map +1 -1
- package/dist/esm/hooks/useTokens.js +26 -15
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/hooks/useTools.d.ts +1 -2
- package/dist/esm/hooks/useTools.d.ts.map +1 -1
- package/dist/esm/hooks/useWidgetChains.d.ts +1 -2
- package/dist/esm/hooks/useWidgetChains.d.ts.map +1 -1
- package/dist/esm/hooks/useWidgetEvents.d.ts +3 -4
- package/dist/esm/hooks/useWidgetEvents.d.ts.map +1 -1
- package/dist/esm/i18n/bn.json +4 -0
- package/dist/esm/i18n/de.json +4 -0
- package/dist/esm/i18n/en.json +4 -0
- package/dist/esm/i18n/es.json +4 -0
- package/dist/esm/i18n/fr.json +4 -0
- package/dist/esm/i18n/hi.json +4 -0
- package/dist/esm/i18n/id.json +4 -0
- package/dist/esm/i18n/it.json +4 -0
- package/dist/esm/i18n/ja.json +4 -0
- package/dist/esm/i18n/ko.json +4 -0
- package/dist/esm/i18n/pl.json +4 -0
- package/dist/esm/i18n/pt.json +4 -0
- package/dist/esm/i18n/th.json +4 -0
- package/dist/esm/i18n/tr.json +4 -0
- package/dist/esm/i18n/uk.json +4 -0
- package/dist/esm/i18n/vi.json +4 -0
- package/dist/esm/i18n/zh.json +4 -0
- package/dist/esm/pages/MainPage/MainWarningMessages.d.ts +1 -2
- package/dist/esm/pages/MainPage/MainWarningMessages.d.ts.map +1 -1
- package/dist/esm/pages/SelectChainPage/SelectChainPage.d.ts +1 -2
- package/dist/esm/pages/SelectChainPage/SelectChainPage.d.ts.map +1 -1
- package/dist/esm/pages/SelectChainPage/types.d.ts +1 -2
- package/dist/esm/pages/SelectChainPage/types.d.ts.map +1 -1
- package/dist/esm/pages/SelectTokenPage/SearchTokenInput.d.ts +1 -2
- package/dist/esm/pages/SelectTokenPage/SearchTokenInput.d.ts.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.d.ts +1 -2
- package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/ConfirmToAddressSheet.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/ConfirmToAddressSheet.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.d.ts +2 -3
- package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/ExecutionDoneCard.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/ExecutionDoneCard.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/RouteTracker.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/RouteTracker.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/StartTransactionButton.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/StartTransactionButton.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js +0 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js +0 -1
- package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionDoneButtons.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/TransactionDoneButtons.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js +38 -12
- package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionReview.js +22 -21
- package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
- package/dist/esm/pages/TransactionPage/types.d.ts +1 -2
- package/dist/esm/pages/TransactionPage/types.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/utils.d.ts +2 -3
- package/dist/esm/pages/TransactionPage/utils.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/utils.js +23 -1
- package/dist/esm/pages/TransactionPage/utils.js.map +1 -1
- package/dist/esm/providers/I18nProvider/I18nProvider.d.ts +1 -2
- package/dist/esm/providers/I18nProvider/I18nProvider.d.ts.map +1 -1
- package/dist/esm/providers/I18nProvider/types.d.ts +4 -5
- package/dist/esm/providers/I18nProvider/types.d.ts.map +1 -1
- package/dist/esm/providers/QueryClientProvider.d.ts +1 -2
- package/dist/esm/providers/QueryClientProvider.d.ts.map +1 -1
- package/dist/esm/providers/SDKClientProvider.d.ts +2 -3
- package/dist/esm/providers/SDKClientProvider.d.ts.map +1 -1
- package/dist/esm/providers/WalletProvider/WalletProvider.d.ts +1 -2
- package/dist/esm/providers/WalletProvider/WalletProvider.d.ts.map +1 -1
- package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts +2 -3
- package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
- package/dist/esm/providers/WidgetProvider/types.d.ts +2 -3
- package/dist/esm/providers/WidgetProvider/types.d.ts.map +1 -1
- package/dist/esm/stores/StoreProvider.d.ts +1 -2
- package/dist/esm/stores/StoreProvider.d.ts.map +1 -1
- package/dist/esm/stores/StoreProvider.js +10 -6
- package/dist/esm/stores/StoreProvider.js.map +1 -1
- package/dist/esm/stores/bookmarks/BookmarkStore.d.ts +1 -2
- package/dist/esm/stores/bookmarks/BookmarkStore.d.ts.map +1 -1
- package/dist/esm/stores/bookmarks/types.d.ts +5 -6
- package/dist/esm/stores/bookmarks/types.d.ts.map +1 -1
- package/dist/esm/stores/chains/ChainOrderStore.d.ts +1 -2
- package/dist/esm/stores/chains/ChainOrderStore.d.ts.map +1 -1
- package/dist/esm/stores/chains/ChainOrderStore.js +11 -5
- package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
- package/dist/esm/stores/chains/types.d.ts +1 -2
- package/dist/esm/stores/chains/types.d.ts.map +1 -1
- package/dist/esm/stores/form/types.d.ts +20 -21
- package/dist/esm/stores/form/types.d.ts.map +1 -1
- package/dist/esm/stores/form/useFieldActions.d.ts +1 -2
- package/dist/esm/stores/form/useFieldActions.d.ts.map +1 -1
- package/dist/esm/stores/form/useFieldValues.d.ts +1 -2
- package/dist/esm/stores/form/useFieldValues.d.ts.map +1 -1
- package/dist/esm/stores/header/types.d.ts +1 -2
- package/dist/esm/stores/header/types.d.ts.map +1 -1
- package/dist/esm/stores/header/useHeaderStore.d.ts +2 -3
- package/dist/esm/stores/header/useHeaderStore.d.ts.map +1 -1
- package/dist/esm/stores/inputMode/useInputModeStore.d.ts +1 -2
- package/dist/esm/stores/inputMode/useInputModeStore.d.ts.map +1 -1
- package/dist/esm/stores/recentTokens/RecentTokensStore.js +23 -0
- package/dist/esm/stores/recentTokens/RecentTokensStore.js.map +1 -0
- package/dist/esm/stores/recentTokens/createRecentTokensStore.js +54 -0
- package/dist/esm/stores/recentTokens/createRecentTokensStore.js.map +1 -0
- package/dist/esm/stores/recentTokens/utils.js +15 -0
- package/dist/esm/stores/recentTokens/utils.js.map +1 -0
- package/dist/esm/stores/routes/RouteExecutionStore.d.ts +2 -3
- package/dist/esm/stores/routes/RouteExecutionStore.d.ts.map +1 -1
- package/dist/esm/stores/routes/types.d.ts +3 -4
- package/dist/esm/stores/routes/types.d.ts.map +1 -1
- package/dist/esm/stores/routes/utils.d.ts +4 -5
- package/dist/esm/stores/routes/utils.d.ts.map +1 -1
- package/dist/esm/stores/settings/SettingsStore.d.ts +2 -3
- package/dist/esm/stores/settings/SettingsStore.d.ts.map +1 -1
- package/dist/esm/stores/settings/types.d.ts +2 -3
- package/dist/esm/stores/settings/types.d.ts.map +1 -1
- package/dist/esm/stores/types.d.ts +2 -3
- package/dist/esm/stores/types.d.ts.map +1 -1
- package/dist/esm/themes/azureLight.d.ts +1 -2
- package/dist/esm/themes/azureLight.d.ts.map +1 -1
- package/dist/esm/themes/jumper.d.ts +1 -2
- package/dist/esm/themes/jumper.d.ts.map +1 -1
- package/dist/esm/themes/palettes.d.ts +3 -4
- package/dist/esm/themes/palettes.d.ts.map +1 -1
- package/dist/esm/themes/types.d.ts +1 -0
- package/dist/esm/themes/watermelonLight.d.ts +1 -2
- package/dist/esm/themes/watermelonLight.d.ts.map +1 -1
- package/dist/esm/themes/windows95.d.ts +1 -2
- package/dist/esm/themes/windows95.d.ts.map +1 -1
- package/dist/esm/types/events.d.ts +13 -14
- package/dist/esm/types/events.d.ts.map +1 -1
- package/dist/esm/types/token.d.ts +4 -2
- package/dist/esm/types/token.d.ts.map +1 -1
- package/dist/esm/types/widget.d.ts +55 -51
- package/dist/esm/types/widget.d.ts.map +1 -1
- package/dist/esm/types/widget.js.map +1 -1
- package/dist/esm/utils/address.js +19 -0
- package/dist/esm/utils/address.js.map +1 -0
- package/dist/esm/utils/compactNumberFormatter.d.ts +1 -2
- package/dist/esm/utils/compactNumberFormatter.d.ts.map +1 -1
- package/dist/esm/utils/converters.d.ts +1 -2
- package/dist/esm/utils/converters.d.ts.map +1 -1
- package/dist/esm/utils/currencyExtendedFormatter.d.ts +1 -2
- package/dist/esm/utils/currencyExtendedFormatter.d.ts.map +1 -1
- package/dist/esm/utils/customReceiver.js +6 -1
- package/dist/esm/utils/customReceiver.js.map +1 -1
- package/dist/esm/utils/elements.d.ts +2 -3
- package/dist/esm/utils/elements.d.ts.map +1 -1
- package/dist/esm/utils/enum.d.ts +1 -2
- package/dist/esm/utils/enum.d.ts.map +1 -1
- package/dist/esm/utils/fees.d.ts +2 -3
- package/dist/esm/utils/fees.d.ts.map +1 -1
- package/dist/esm/utils/format.d.ts +8 -9
- package/dist/esm/utils/format.d.ts.map +1 -1
- package/dist/esm/utils/getPriceImpact.d.ts +1 -2
- package/dist/esm/utils/getPriceImpact.d.ts.map +1 -1
- package/dist/esm/utils/input.d.ts +1 -2
- package/dist/esm/utils/input.d.ts.map +1 -1
- package/dist/esm/utils/navigationRoutes.d.ts +2 -3
- package/dist/esm/utils/navigationRoutes.d.ts.map +1 -1
- package/dist/esm/utils/percentFormatter.d.ts +1 -2
- package/dist/esm/utils/percentFormatter.d.ts.map +1 -1
- package/dist/esm/utils/recentTokens.js +97 -0
- package/dist/esm/utils/recentTokens.js.map +1 -0
- package/dist/esm/utils/token.js +30 -4
- package/dist/esm/utils/token.js.map +1 -1
- package/dist/esm/utils/tokenList.js +18 -6
- package/dist/esm/utils/tokenList.js.map +1 -1
- package/dist/esm/utils/tokenListBands.js +85 -0
- package/dist/esm/utils/tokenListBands.js.map +1 -0
- package/dist/esm/utils/wallet.d.ts +1 -2
- package/dist/esm/utils/wallet.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/components/AmountInputCard/ReceiveAmountCard.tsx +16 -3
- package/src/components/BottomSheet/BottomSheet.tsx +3 -0
- package/src/components/Token/Token.tsx +2 -1
- package/src/components/TokenList/RecentTokensHeader.tsx +52 -0
- package/src/components/TokenList/RecentTokensToggle.tsx +45 -0
- package/src/components/TokenList/RemoveRecentTokenButton.tsx +38 -0
- package/src/components/TokenList/TokenList.tsx +92 -3
- package/src/components/TokenList/TokenListItem.tsx +15 -0
- package/src/components/TokenList/VirtualizedTokenList.tsx +84 -125
- package/src/components/TokenList/types.ts +9 -0
- package/src/config/version.ts +1 -1
- package/src/hooks/useDisplayedTokens.ts +17 -3
- package/src/hooks/useRecentTokens.ts +88 -0
- package/src/hooks/useRoutes.ts +8 -5
- package/src/hooks/useToAddressRequirements.ts +11 -5
- package/src/hooks/useTokenBalances.ts +34 -31
- package/src/hooks/useTokenSearch.ts +5 -14
- package/src/hooks/useTokens.ts +69 -27
- package/src/pages/TransactionPage/TokenValueBottomSheet.tsx +1 -1
- package/src/pages/TransactionPage/TokenVerificationBottomSheet.tsx +1 -1
- package/src/pages/TransactionPage/TransactionFailedButtons.tsx +62 -26
- package/src/pages/TransactionPage/TransactionReview.tsx +36 -37
- package/src/pages/TransactionPage/utils.ts +78 -0
- package/src/stores/StoreProvider.tsx +10 -7
- package/src/stores/chains/ChainOrderStore.test.tsx +298 -0
- package/src/stores/chains/ChainOrderStore.tsx +25 -6
- package/src/stores/recentTokens/RecentTokensStore.tsx +39 -0
- package/src/stores/recentTokens/createRecentTokensStore.ts +107 -0
- package/src/stores/recentTokens/types.ts +37 -0
- package/src/stores/recentTokens/utils.ts +18 -0
- package/src/types/token.ts +2 -0
- package/src/types/widget.ts +5 -0
- package/src/utils/address.ts +21 -0
- package/src/utils/customReceiver.ts +24 -0
- package/src/utils/recentTokens.ts +187 -0
- package/src/utils/token.ts +69 -10
- package/src/utils/tokenList.ts +41 -23
- package/src/utils/tokenListBands.ts +181 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/** @vitest-environment happy-dom */
|
|
2
|
+
|
|
3
|
+
import type { ExtendedChain } from '@lifi/sdk'
|
|
4
|
+
import { act } from 'react'
|
|
5
|
+
import { createRoot, type Root } from 'react-dom/client'
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Regression cover for JUM-1541.
|
|
10
|
+
*
|
|
11
|
+
* Mock identities must stay stable. In production this effect's dependencies
|
|
12
|
+
* are config values, so it does not re-run when a form field changes; mocks
|
|
13
|
+
* that rebuild objects each render would re-run it and prove behaviour the
|
|
14
|
+
* widget does not have.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const ETHEREUM = 1
|
|
18
|
+
const ARBITRUM = 42161
|
|
19
|
+
const POLYGON = 137
|
|
20
|
+
const SOLANA = 1151111081099710
|
|
21
|
+
|
|
22
|
+
const chain = (id: number): ExtendedChain =>
|
|
23
|
+
({ id, name: `Chain ${id}`, chainType: 'EVM' }) as unknown as ExtendedChain
|
|
24
|
+
|
|
25
|
+
let chainsConfig: { from?: { allow: number[] } } | undefined
|
|
26
|
+
let availableChains: ExtendedChain[] = []
|
|
27
|
+
let swapOnly = false
|
|
28
|
+
let fromChainConfig: number | undefined
|
|
29
|
+
|
|
30
|
+
const formValues = new Map<string, unknown>()
|
|
31
|
+
const touchedFields = new Set<string>()
|
|
32
|
+
const setFieldValue = vi.fn(
|
|
33
|
+
(key: string, value: unknown, options?: { isTouched?: boolean }) => {
|
|
34
|
+
formValues.set(key, value)
|
|
35
|
+
if (options?.isTouched === true) {
|
|
36
|
+
touchedFields.add(key)
|
|
37
|
+
} else if (options?.isTouched === false) {
|
|
38
|
+
touchedFields.delete(key)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
vi.mock('../../hooks/useChains.js', () => ({
|
|
44
|
+
useChains: () => ({ chains: availableChains }),
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
vi.mock('../../hooks/useSwapOnly.js', () => ({
|
|
48
|
+
useSwapOnly: () => swapOnly,
|
|
49
|
+
}))
|
|
50
|
+
|
|
51
|
+
// Stable identities, as production has them: `useExternalWalletProvider`
|
|
52
|
+
// memoizes and `useFieldActions` selects store methods through `useShallow`.
|
|
53
|
+
// Returning fresh objects here would put a new value in the effect's
|
|
54
|
+
// dependency array on every render and re-run it — which production does not
|
|
55
|
+
// do, and which would make these tests prove something the widget does not.
|
|
56
|
+
const externalWalletProvider = {
|
|
57
|
+
externalChainTypes: [] as string[],
|
|
58
|
+
useExternalWalletProvidersOnly: false,
|
|
59
|
+
}
|
|
60
|
+
vi.mock('../../providers/WalletProvider/useExternalWalletProvider.js', () => ({
|
|
61
|
+
useExternalWalletProvider: () => externalWalletProvider,
|
|
62
|
+
}))
|
|
63
|
+
|
|
64
|
+
vi.mock('../../providers/WidgetProvider/WidgetProvider.js', () => ({
|
|
65
|
+
useWidgetConfig: () => ({
|
|
66
|
+
chains: chainsConfig,
|
|
67
|
+
hiddenUI: undefined,
|
|
68
|
+
fromChain: fromChainConfig,
|
|
69
|
+
toChain: undefined,
|
|
70
|
+
buildUrl: true,
|
|
71
|
+
variant: 'compact',
|
|
72
|
+
}),
|
|
73
|
+
}))
|
|
74
|
+
|
|
75
|
+
const getFieldValues = (key: string) => [formValues.get(key)]
|
|
76
|
+
const isTouched = (key: string) => touchedFields.has(key)
|
|
77
|
+
const fieldActions = { setFieldValue, getFieldValues, isTouched }
|
|
78
|
+
vi.mock('../form/useFieldActions.js', () => ({
|
|
79
|
+
useFieldActions: () => fieldActions,
|
|
80
|
+
}))
|
|
81
|
+
|
|
82
|
+
const { ChainOrderStoreProvider, useChainOrderStore } = await import(
|
|
83
|
+
'./ChainOrderStore.js'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
/** What `selectAllNetworks` does to the form: clear the field, as touched. */
|
|
87
|
+
const clickAllNetworks = (key: 'from' | 'to') => {
|
|
88
|
+
formValues.set(`${key}Chain`, '')
|
|
89
|
+
touchedFields.add(`${key}Chain`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let fromIsAllNetworks: boolean | undefined
|
|
93
|
+
|
|
94
|
+
const StoreHandle = (): null => {
|
|
95
|
+
fromIsAllNetworks = useChainOrderStore((state) => state.fromIsAllNetworks)
|
|
96
|
+
return null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let root: Root
|
|
100
|
+
|
|
101
|
+
const render = () => {
|
|
102
|
+
act(() => {
|
|
103
|
+
root.render(
|
|
104
|
+
<ChainOrderStoreProvider namePrefix="test">
|
|
105
|
+
<StoreHandle />
|
|
106
|
+
</ChainOrderStoreProvider>
|
|
107
|
+
)
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const fromChainWrites = () =>
|
|
112
|
+
setFieldValue.mock.calls.filter(([key]) => key === 'fromChain')
|
|
113
|
+
|
|
114
|
+
const toChainWrites = () =>
|
|
115
|
+
setFieldValue.mock.calls.filter(([key]) => key === 'toChain')
|
|
116
|
+
|
|
117
|
+
/** An integrator that derives `chains` from form state rebuilds it on every write. */
|
|
118
|
+
const rebuildHostConfig = () => {
|
|
119
|
+
chainsConfig = { ...chainsConfig }
|
|
120
|
+
render()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
;(
|
|
125
|
+
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }
|
|
126
|
+
).IS_REACT_ACT_ENVIRONMENT = true
|
|
127
|
+
window.history.replaceState({}, '', '/')
|
|
128
|
+
window.localStorage.clear()
|
|
129
|
+
formValues.clear()
|
|
130
|
+
touchedFields.clear()
|
|
131
|
+
setFieldValue.mockClear()
|
|
132
|
+
chainsConfig = undefined
|
|
133
|
+
swapOnly = false
|
|
134
|
+
fromChainConfig = undefined
|
|
135
|
+
availableChains = [chain(ETHEREUM), chain(ARBITRUM)]
|
|
136
|
+
fromIsAllNetworks = undefined
|
|
137
|
+
root = createRoot(document.createElement('div'))
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
afterEach(() => {
|
|
141
|
+
act(() => root.unmount())
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
describe('ChainOrderStoreProvider', () => {
|
|
145
|
+
it('starts on "All networks" when nothing names a chain', () => {
|
|
146
|
+
render()
|
|
147
|
+
|
|
148
|
+
expect(fromIsAllNetworks).toBe(true)
|
|
149
|
+
expect(fromChainWrites()).toHaveLength(0)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('starts off "All networks" when a deep link named a chain', () => {
|
|
153
|
+
// How the widget learns this when the config carries nothing.
|
|
154
|
+
window.history.replaceState({}, '', `/?fromChain=${ARBITRUM}`)
|
|
155
|
+
formValues.set('fromChain', ARBITRUM)
|
|
156
|
+
render()
|
|
157
|
+
|
|
158
|
+
expect(fromIsAllNetworks).toBe(false)
|
|
159
|
+
expect(fromChainWrites()).toHaveLength(0)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('starts off "All networks" when the config names a chain', () => {
|
|
163
|
+
fromChainConfig = POLYGON
|
|
164
|
+
render()
|
|
165
|
+
|
|
166
|
+
expect(fromIsAllNetworks).toBe(false)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('does not put a chain back after the user chooses "All networks"', () => {
|
|
170
|
+
// jumper-frontend seeds its config from the URL, so a deep link arrives
|
|
171
|
+
// as a config chain as well as a form value and a query param.
|
|
172
|
+
fromChainConfig = ARBITRUM
|
|
173
|
+
formValues.set('fromChain', ARBITRUM)
|
|
174
|
+
window.history.replaceState({}, '', `/?fromChain=${ARBITRUM}`)
|
|
175
|
+
render()
|
|
176
|
+
expect(fromIsAllNetworks).toBe(false)
|
|
177
|
+
|
|
178
|
+
clickAllNetworks('from')
|
|
179
|
+
setFieldValue.mockClear()
|
|
180
|
+
|
|
181
|
+
// jumper-frontend rebuilds `chains` from form state, so clearing the
|
|
182
|
+
// field re-runs the effect on that same commit — while the config and the
|
|
183
|
+
// query string still name Arbitrum.
|
|
184
|
+
chainsConfig = { ...chainsConfig }
|
|
185
|
+
render()
|
|
186
|
+
|
|
187
|
+
expect(fromIsAllNetworks).toBe(true)
|
|
188
|
+
expect(fromChainWrites()).toHaveLength(0)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('fills an empty chain when the "All networks" tab is withdrawn', () => {
|
|
192
|
+
render()
|
|
193
|
+
expect(fromChainWrites()).toHaveLength(0)
|
|
194
|
+
|
|
195
|
+
// An allow-list of one chain withdraws the tab, so this side needs a
|
|
196
|
+
// fallback.
|
|
197
|
+
chainsConfig = { from: { allow: [ARBITRUM] } }
|
|
198
|
+
setFieldValue.mockClear()
|
|
199
|
+
render()
|
|
200
|
+
|
|
201
|
+
expect(fromIsAllNetworks).toBe(false)
|
|
202
|
+
expect(fromChainWrites()).toHaveLength(1)
|
|
203
|
+
expect(fromChainWrites()[0][1]).toBe(ARBITRUM)
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
describe('ChainOrderStoreProvider in swap-only modes', () => {
|
|
208
|
+
beforeEach(() => {
|
|
209
|
+
swapOnly = true
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
const pickSource = (chainId: number) => {
|
|
213
|
+
window.history.replaceState({}, '', `/?fromChain=${chainId}`)
|
|
214
|
+
formValues.set('fromChain', chainId)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// The destination used to flip on every host rebuild until React threw #185.
|
|
218
|
+
it('does not alternate the destination while the source is on "All networks"', () => {
|
|
219
|
+
const destinations: unknown[] = []
|
|
220
|
+
render()
|
|
221
|
+
destinations.push(formValues.get('toChain'))
|
|
222
|
+
for (let rebuild = 0; rebuild < 4; rebuild++) {
|
|
223
|
+
rebuildHostConfig()
|
|
224
|
+
destinations.push(formValues.get('toChain'))
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
expect(fromIsAllNetworks).toBe(true)
|
|
228
|
+
expect(destinations).toEqual(Array(5).fill(ETHEREUM))
|
|
229
|
+
expect(toChainWrites()).toHaveLength(1)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('fills an empty destination from the source, not from the chain order', () => {
|
|
233
|
+
pickSource(ARBITRUM)
|
|
234
|
+
render()
|
|
235
|
+
|
|
236
|
+
expect(formValues.get('toChain')).toBe(ARBITRUM)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it('moves a stale destination onto the source', () => {
|
|
240
|
+
pickSource(ARBITRUM)
|
|
241
|
+
formValues.set('toChain', ETHEREUM)
|
|
242
|
+
render()
|
|
243
|
+
|
|
244
|
+
expect(formValues.get('toChain')).toBe(ARBITRUM)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('stops writing the destination once it matches the source', () => {
|
|
248
|
+
pickSource(ARBITRUM)
|
|
249
|
+
render()
|
|
250
|
+
expect(formValues.get('toChain')).toBe(ARBITRUM)
|
|
251
|
+
setFieldValue.mockClear()
|
|
252
|
+
|
|
253
|
+
rebuildHostConfig()
|
|
254
|
+
rebuildHostConfig()
|
|
255
|
+
|
|
256
|
+
expect(toChainWrites()).toHaveLength(0)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('keeps the destination when the source goes back to "All networks"', () => {
|
|
260
|
+
pickSource(ARBITRUM)
|
|
261
|
+
render()
|
|
262
|
+
expect(formValues.get('toChain')).toBe(ARBITRUM)
|
|
263
|
+
clickAllNetworks('from')
|
|
264
|
+
setFieldValue.mockClear()
|
|
265
|
+
|
|
266
|
+
rebuildHostConfig()
|
|
267
|
+
rebuildHostConfig()
|
|
268
|
+
|
|
269
|
+
expect(formValues.get('toChain')).toBe(ARBITRUM)
|
|
270
|
+
expect(toChainWrites()).toHaveLength(0)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('treats a zero source as no source', () => {
|
|
274
|
+
formValues.set('fromChain', 0)
|
|
275
|
+
render()
|
|
276
|
+
rebuildHostConfig()
|
|
277
|
+
|
|
278
|
+
expect(formValues.get('toChain')).toBe(ETHEREUM)
|
|
279
|
+
expect(toChainWrites()).toHaveLength(1)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// The list can shrink under a destination, e.g. when the integrator narrows `chains`.
|
|
283
|
+
it('replaces a destination the chain list does not offer while there is no source', () => {
|
|
284
|
+
swapOnly = false
|
|
285
|
+
availableChains = [chain(ETHEREUM), chain(ARBITRUM), chain(SOLANA)]
|
|
286
|
+
formValues.set('toChain', SOLANA)
|
|
287
|
+
render()
|
|
288
|
+
expect(formValues.get('toChain')).toBe(SOLANA)
|
|
289
|
+
|
|
290
|
+
swapOnly = true
|
|
291
|
+
availableChains = [chain(ETHEREUM), chain(ARBITRUM)]
|
|
292
|
+
render()
|
|
293
|
+
rebuildHostConfig()
|
|
294
|
+
|
|
295
|
+
expect(formValues.get('toChain')).toBe(ETHEREUM)
|
|
296
|
+
expect(toChainWrites()).toHaveLength(1)
|
|
297
|
+
})
|
|
298
|
+
})
|
|
@@ -30,7 +30,7 @@ export function ChainOrderStoreProvider({
|
|
|
30
30
|
} = useWidgetConfig()
|
|
31
31
|
const storeRef = useRef<ChainOrderStore>(null)
|
|
32
32
|
const { chains } = useChains()
|
|
33
|
-
const { setFieldValue, getFieldValues } = useFieldActions()
|
|
33
|
+
const { setFieldValue, getFieldValues, isTouched } = useFieldActions()
|
|
34
34
|
const swapOnly = useSwapOnly()
|
|
35
35
|
const { variant } = useWidgetConfig()
|
|
36
36
|
const { externalChainTypes, useExternalWalletProvidersOnly } =
|
|
@@ -85,15 +85,30 @@ export function ChainOrderStoreProvider({
|
|
|
85
85
|
key === 'from' ? urlValues.fromChain : urlValues.toChain
|
|
86
86
|
const configChainValue =
|
|
87
87
|
key === 'from' ? fromChainConfig : toChainConfig
|
|
88
|
+
|
|
89
|
+
// A touched, empty chain field was cleared deliberately — "All
|
|
90
|
+
// networks". It has to outrank the two values above, because both
|
|
91
|
+
// still name the chain the page was opened on at that moment: the
|
|
92
|
+
// query string is rewritten a commit later, and an integrator that
|
|
93
|
+
// seeds its config from the URL never rewrites it.
|
|
94
|
+
const [chainValue] = getFieldValues(`${key}Chain`)
|
|
95
|
+
const clearedForAllNetworks = !chainValue && isTouched(`${key}Chain`)
|
|
96
|
+
|
|
88
97
|
const initialIsAllNetworks =
|
|
89
|
-
showAllNetworks &&
|
|
98
|
+
showAllNetworks &&
|
|
99
|
+
(clearedForAllNetworks || (!configChainValue && !urlChainValue))
|
|
90
100
|
storeRef.current?.getState().setIsAllNetworks(initialIsAllNetworks, key)
|
|
91
101
|
storeRef.current?.getState().setShowAllNetworks(showAllNetworks, key)
|
|
92
102
|
|
|
93
|
-
//
|
|
103
|
+
// Copying an empty source would alternate with the fallback below.
|
|
94
104
|
if (isSwapTo) {
|
|
95
105
|
const [fromChainValue] = getFieldValues('fromChain')
|
|
96
|
-
|
|
106
|
+
if (fromChainValue) {
|
|
107
|
+
if (fromChainValue !== chainValue) {
|
|
108
|
+
setFieldValue('toChain', fromChainValue)
|
|
109
|
+
}
|
|
110
|
+
return
|
|
111
|
+
}
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
// When "All Networks" is active, don't auto-select a chain from the
|
|
@@ -104,8 +119,11 @@ export function ChainOrderStoreProvider({
|
|
|
104
119
|
return
|
|
105
120
|
}
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
// With no source to follow, drop a destination the list no longer offers.
|
|
123
|
+
const keepsChain =
|
|
124
|
+
chainValue &&
|
|
125
|
+
(!isSwapTo || filteredChains.some((chain) => chain.id === chainValue))
|
|
126
|
+
if (keepsChain) {
|
|
109
127
|
return
|
|
110
128
|
}
|
|
111
129
|
|
|
@@ -130,6 +148,7 @@ export function ChainOrderStoreProvider({
|
|
|
130
148
|
chainsConfig,
|
|
131
149
|
externalChainTypes,
|
|
132
150
|
getFieldValues,
|
|
151
|
+
isTouched,
|
|
133
152
|
setFieldValue,
|
|
134
153
|
useExternalWalletProvidersOnly,
|
|
135
154
|
variant,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Context, createContext, use, useRef } from 'react'
|
|
2
|
+
import { useShallow } from 'zustand/shallow'
|
|
3
|
+
import type { PersistStoreProviderProps } from '../types.js'
|
|
4
|
+
import { createRecentTokensStore } from './createRecentTokensStore.js'
|
|
5
|
+
import type { RecentTokensState, RecentTokensStore } from './types.js'
|
|
6
|
+
|
|
7
|
+
const RecentTokensStoreContext: Context<RecentTokensStore | null> =
|
|
8
|
+
createContext<RecentTokensStore | null>(null)
|
|
9
|
+
|
|
10
|
+
export const RecentTokensStoreProvider: React.FC<PersistStoreProviderProps> = ({
|
|
11
|
+
children,
|
|
12
|
+
...props
|
|
13
|
+
}) => {
|
|
14
|
+
const storeRef = useRef<RecentTokensStore>(null)
|
|
15
|
+
|
|
16
|
+
if (!storeRef.current) {
|
|
17
|
+
storeRef.current = createRecentTokensStore(props)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<RecentTokensStoreContext value={storeRef.current}>
|
|
22
|
+
{children}
|
|
23
|
+
</RecentTokensStoreContext>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function useRecentTokensStore<T>(
|
|
28
|
+
selector: (store: RecentTokensState) => T
|
|
29
|
+
): T {
|
|
30
|
+
const useStore = use(RecentTokensStoreContext)
|
|
31
|
+
|
|
32
|
+
if (!useStore) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`You forgot to wrap your component in <${RecentTokensStoreProvider.name}>.`
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return useStore(useShallow(selector))
|
|
39
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { StoreApi, UseBoundStore } from 'zustand'
|
|
2
|
+
import { create } from 'zustand'
|
|
3
|
+
import { persist } from 'zustand/middleware'
|
|
4
|
+
import type { PersistStoreProps } from '../types.js'
|
|
5
|
+
import type {
|
|
6
|
+
RecentToken,
|
|
7
|
+
RecentTokensProps,
|
|
8
|
+
RecentTokensState,
|
|
9
|
+
} from './types.js'
|
|
10
|
+
import { getTokenKey } from './utils.js'
|
|
11
|
+
|
|
12
|
+
const recentTokensLimit = 10
|
|
13
|
+
|
|
14
|
+
const isStoredRecentToken = (value: unknown): value is RecentToken => {
|
|
15
|
+
const token = value as Partial<RecentToken> | null
|
|
16
|
+
return (
|
|
17
|
+
typeof token === 'object' &&
|
|
18
|
+
token !== null &&
|
|
19
|
+
typeof token.chainId === 'number' &&
|
|
20
|
+
typeof token.address === 'string' &&
|
|
21
|
+
typeof token.symbol === 'string' &&
|
|
22
|
+
typeof token.name === 'string' &&
|
|
23
|
+
typeof token.decimals === 'number' &&
|
|
24
|
+
(token.logoURI === undefined || typeof token.logoURI === 'string') &&
|
|
25
|
+
(token.flagged === undefined || typeof token.flagged === 'boolean')
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The key lives on the integrator's origin, so its content is untrusted.
|
|
30
|
+
const sanitizeRecentTokens = (stored: unknown): RecentToken[] => {
|
|
31
|
+
if (!Array.isArray(stored)) {
|
|
32
|
+
return []
|
|
33
|
+
}
|
|
34
|
+
const seen = new Set<string>()
|
|
35
|
+
const recentTokens: RecentToken[] = []
|
|
36
|
+
for (const token of stored) {
|
|
37
|
+
if (!isStoredRecentToken(token)) {
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
const key = getTokenKey(token.chainId, token.address)
|
|
41
|
+
if (!seen.has(key)) {
|
|
42
|
+
seen.add(key)
|
|
43
|
+
recentTokens.push(token)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return recentTokens.slice(0, recentTokensLimit)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const createRecentTokensStore = ({
|
|
50
|
+
namePrefix,
|
|
51
|
+
}: PersistStoreProps): UseBoundStore<StoreApi<RecentTokensState>> =>
|
|
52
|
+
create<RecentTokensState>()(
|
|
53
|
+
persist(
|
|
54
|
+
(set, get) => ({
|
|
55
|
+
recentTokens: [],
|
|
56
|
+
addRecentToken: (token) => {
|
|
57
|
+
const key = getTokenKey(token.chainId, token.address)
|
|
58
|
+
set((state) => ({
|
|
59
|
+
recentTokens: [
|
|
60
|
+
token,
|
|
61
|
+
...state.recentTokens.filter(
|
|
62
|
+
(t) => getTokenKey(t.chainId, t.address) !== key
|
|
63
|
+
),
|
|
64
|
+
].slice(0, recentTokensLimit),
|
|
65
|
+
}))
|
|
66
|
+
},
|
|
67
|
+
removeRecentToken: (chainId, address) => {
|
|
68
|
+
const key = getTokenKey(chainId, address)
|
|
69
|
+
set((state) => ({
|
|
70
|
+
recentTokens: state.recentTokens.filter(
|
|
71
|
+
(t) => getTokenKey(t.chainId, t.address) !== key
|
|
72
|
+
),
|
|
73
|
+
}))
|
|
74
|
+
},
|
|
75
|
+
clearRecentTokens: (entries) =>
|
|
76
|
+
set((state) => {
|
|
77
|
+
const removed = new Set(
|
|
78
|
+
entries.map((e) => getTokenKey(e.chainId, e.address))
|
|
79
|
+
)
|
|
80
|
+
return {
|
|
81
|
+
recentTokens: state.recentTokens.filter(
|
|
82
|
+
(t) => !removed.has(getTokenKey(t.chainId, t.address))
|
|
83
|
+
),
|
|
84
|
+
}
|
|
85
|
+
}),
|
|
86
|
+
isRecentToken: (chainId, address) => {
|
|
87
|
+
const key = getTokenKey(chainId, address)
|
|
88
|
+
return get().recentTokens.some(
|
|
89
|
+
(t) => getTokenKey(t.chainId, t.address) === key
|
|
90
|
+
)
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
{
|
|
94
|
+
name: `${namePrefix || 'li.fi'}-recent-tokens`,
|
|
95
|
+
version: 0,
|
|
96
|
+
partialize: (state) => ({
|
|
97
|
+
recentTokens: state.recentTokens,
|
|
98
|
+
}),
|
|
99
|
+
merge: (persisted, current) => ({
|
|
100
|
+
...current,
|
|
101
|
+
recentTokens: sanitizeRecentTokens(
|
|
102
|
+
(persisted as Partial<RecentTokensProps> | undefined)?.recentTokens
|
|
103
|
+
),
|
|
104
|
+
}),
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { StoreApi } from 'zustand'
|
|
2
|
+
import type { UseBoundStoreWithEqualityFn } from 'zustand/traditional'
|
|
3
|
+
|
|
4
|
+
export interface RecentToken {
|
|
5
|
+
chainId: number
|
|
6
|
+
/** The token's own casing. Compared case-insensitively with chainId. */
|
|
7
|
+
address: string
|
|
8
|
+
symbol: string
|
|
9
|
+
name: string
|
|
10
|
+
decimals: number
|
|
11
|
+
logoURI?: string
|
|
12
|
+
flagged?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Compared case-insensitively. */
|
|
16
|
+
export interface RecentTokenId {
|
|
17
|
+
chainId: number
|
|
18
|
+
address: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RecentTokensProps {
|
|
22
|
+
recentTokens: RecentToken[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RecentTokensActions {
|
|
26
|
+
addRecentToken: (token: RecentToken) => void
|
|
27
|
+
removeRecentToken: (chainId: number, address: string) => void
|
|
28
|
+
/** Removes exactly these entries, never one outside the band's scope. */
|
|
29
|
+
clearRecentTokens: (entries: RecentTokenId[]) => void
|
|
30
|
+
isRecentToken: (chainId: number, address: string) => boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type RecentTokensState = RecentTokensProps & RecentTokensActions
|
|
34
|
+
|
|
35
|
+
export type RecentTokensStore = UseBoundStoreWithEqualityFn<
|
|
36
|
+
StoreApi<RecentTokensState>
|
|
37
|
+
>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TokenAmount } from '../../types/token.js'
|
|
2
|
+
import type { RecentToken } from './types.js'
|
|
3
|
+
|
|
4
|
+
export const getTokenKey = (chainId: number, address: string): string =>
|
|
5
|
+
`${chainId}-${address.toLowerCase()}`
|
|
6
|
+
|
|
7
|
+
// No price, and no verdict but a flag: a stale "verified" would hide a warning.
|
|
8
|
+
export const toRecentToken = (token: TokenAmount): RecentToken => ({
|
|
9
|
+
// Plain-JS configs can pass a string chainId or null fields; hydration rejects both.
|
|
10
|
+
chainId: Number(token.chainId),
|
|
11
|
+
// Keep the casing: the form and the selected check compare it exactly.
|
|
12
|
+
address: token.address,
|
|
13
|
+
symbol: token.symbol,
|
|
14
|
+
name: token.name ?? '',
|
|
15
|
+
decimals: token.decimals,
|
|
16
|
+
logoURI: token.logoURI ?? undefined,
|
|
17
|
+
flagged: token.verificationStatus === 'flagged' || undefined,
|
|
18
|
+
})
|
package/src/types/token.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface TokenFlags {
|
|
|
8
8
|
featured?: boolean
|
|
9
9
|
popular?: boolean
|
|
10
10
|
pinned?: boolean
|
|
11
|
+
/** A copy promoted into the "Recent searches" band. */
|
|
12
|
+
recent?: boolean
|
|
11
13
|
verified?: boolean
|
|
12
14
|
native?: boolean
|
|
13
15
|
/** Came from the main token list rather than from a search. */
|
package/src/types/widget.ts
CHANGED
|
@@ -156,6 +156,11 @@ export interface HiddenUIConfig {
|
|
|
156
156
|
*/
|
|
157
157
|
lowAddressActivityConfirmation?: boolean
|
|
158
158
|
poweredBy?: boolean
|
|
159
|
+
/**
|
|
160
|
+
* Hide the "Recent searches" section in the token select view.
|
|
161
|
+
* @default false
|
|
162
|
+
*/
|
|
163
|
+
recentSearches?: boolean
|
|
159
164
|
reverseTokensButton?: boolean
|
|
160
165
|
routeCardPriceImpact?: boolean
|
|
161
166
|
routeTokenDescription?: boolean
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ChainType } from '@lifi/sdk'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* True when a token search query is a contract address rather than free text.
|
|
5
|
+
* `getChainTypeFromTokenAddress` asks the configured providers' own
|
|
6
|
+
* `isTokenAddress` (see `useChainTypeFromAddress`), so it covers the token
|
|
7
|
+
* identifier of every ecosystem. Two consequences follow. `bitcoin` stays a
|
|
8
|
+
* name search, because the Bitcoin provider implements no token check. And an
|
|
9
|
+
* ecosystem is not detected unless the host configures its provider from
|
|
10
|
+
* `@lifi/sdk` 4.7.0 or later, even when its chains are listed.
|
|
11
|
+
*/
|
|
12
|
+
export const isAddressQuery = (
|
|
13
|
+
query: string | undefined,
|
|
14
|
+
getChainTypeFromTokenAddress: (address: string) => ChainType | undefined
|
|
15
|
+
): boolean => {
|
|
16
|
+
const value = query?.trim()
|
|
17
|
+
if (!value) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
return getChainTypeFromTokenAddress(value) !== undefined
|
|
21
|
+
}
|
|
@@ -5,3 +5,27 @@ export const isCustomReceiverUnsupported = (
|
|
|
5
5
|
fromChainType?: ChainType,
|
|
6
6
|
toChainType?: ChainType
|
|
7
7
|
): boolean => fromChainType === ChainType.STL && toChainType === ChainType.STL
|
|
8
|
+
|
|
9
|
+
export interface CustomReceiverBlockedArgs {
|
|
10
|
+
fromChainType?: ChainType
|
|
11
|
+
toChainType?: ChainType
|
|
12
|
+
toAddress?: string
|
|
13
|
+
signerAddress?: string
|
|
14
|
+
receiverRequired?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const isCustomReceiverBlocked = ({
|
|
18
|
+
fromChainType,
|
|
19
|
+
toChainType,
|
|
20
|
+
toAddress,
|
|
21
|
+
signerAddress,
|
|
22
|
+
receiverRequired,
|
|
23
|
+
}: CustomReceiverBlockedArgs): boolean => {
|
|
24
|
+
if (!isCustomReceiverUnsupported(fromChainType, toChainType)) {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
if (!toAddress) {
|
|
28
|
+
return Boolean(receiverRequired)
|
|
29
|
+
}
|
|
30
|
+
return toAddress.toLowerCase() !== signerAddress?.toLowerCase()
|
|
31
|
+
}
|