@lifi/widget 4.6.0 → 4.7.1
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 +2 -3
- package/dist/esm/hooks/useExplorer.d.ts.map +1 -1
- package/dist/esm/hooks/useExplorer.js +7 -3
- package/dist/esm/hooks/useExplorer.js.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/SendToWallet/BookmarksPage.js +2 -1
- package/dist/esm/pages/SendToWallet/BookmarksPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js +2 -1
- package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/RecentWalletsPage.js +2 -1
- package/dist/esm/pages/SendToWallet/RecentWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js +2 -1
- package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js.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/TransactionDetailsPage/TransactionDetailsPage.js +2 -1
- package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/TransferIdCard.js +2 -1
- package/dist/esm/pages/TransactionDetailsPage/TransferIdCard.js.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/shared.d.ts +2 -1
- package/dist/esm/shared.js +2 -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/url.d.ts +5 -0
- package/dist/esm/utils/url.d.ts.map +1 -0
- package/dist/esm/utils/url.js +17 -0
- package/dist/esm/utils/url.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/useExplorer.test.tsx +106 -0
- package/src/hooks/useExplorer.ts +11 -5
- 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/SendToWallet/BookmarksPage.tsx +3 -3
- package/src/pages/SendToWallet/ConnectedWalletsPage.tsx +3 -3
- package/src/pages/SendToWallet/RecentWalletsPage.tsx +3 -3
- package/src/pages/SendToWallet/SendToConfiguredWalletPage.tsx +3 -3
- package/src/pages/TransactionDetailsPage/TransactionDetailsPage.tsx +5 -5
- package/src/pages/TransactionDetailsPage/TransferIdCard.tsx +2 -1
- 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/shared.ts +1 -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
- package/src/utils/url.ts +17 -0
|
@@ -20,9 +20,12 @@ import { ConfirmToAddressSheet } from './ConfirmToAddressSheet.js'
|
|
|
20
20
|
import { StartTransactionButton } from './StartTransactionButton.js'
|
|
21
21
|
import { TokenValueBottomSheet } from './TokenValueBottomSheet.js'
|
|
22
22
|
import { TokenVerificationBottomSheet } from './TokenVerificationBottomSheet.js'
|
|
23
|
+
import type { StartGate } from './utils.js'
|
|
23
24
|
import {
|
|
24
25
|
calculateValueLossPercentage,
|
|
26
|
+
getStartGates,
|
|
25
27
|
getTokenValueLossThreshold,
|
|
28
|
+
openNextGate,
|
|
26
29
|
} from './utils.js'
|
|
27
30
|
|
|
28
31
|
interface TransactionReviewProps {
|
|
@@ -74,7 +77,6 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
|
|
|
74
77
|
})
|
|
75
78
|
}
|
|
76
79
|
tokenValueBottomSheetRef.current?.close()
|
|
77
|
-
flaggedTokenSheetRef.current?.close()
|
|
78
80
|
executeRoute()
|
|
79
81
|
setFieldValue('fromAmount', '')
|
|
80
82
|
if (mode === 'custom') {
|
|
@@ -86,49 +88,46 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
|
|
|
86
88
|
})
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
// rather than executing, so accepting it does not skip the others.
|
|
91
|
-
const handleStartAfterTokenCheck = () => {
|
|
92
|
-
if (
|
|
93
|
-
toAddress &&
|
|
94
|
-
!hasActivity &&
|
|
95
|
-
!isLoadingAddressActivity &&
|
|
96
|
-
isActivityAddressFetched &&
|
|
97
|
-
!hiddenUI?.lowAddressActivityConfirmation
|
|
98
|
-
) {
|
|
99
|
-
confirmToAddressSheetRef.current?.open()
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
91
|
+
const startGates = (() => {
|
|
103
92
|
const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
93
|
+
return getStartGates({
|
|
94
|
+
flaggedTokenCount: flaggedTokens.length,
|
|
95
|
+
toAddress,
|
|
96
|
+
hasActivity,
|
|
97
|
+
isLoadingAddressActivity,
|
|
98
|
+
isActivityAddressFetched,
|
|
99
|
+
confirmationHidden: Boolean(hiddenUI?.lowAddressActivityConfirmation),
|
|
100
|
+
valueLossExceeded: getTokenValueLossThreshold(
|
|
101
|
+
Number.parseFloat(route.fromAmountUSD),
|
|
102
|
+
Number.parseFloat(route.toAmountUSD),
|
|
103
|
+
gasCostUSD,
|
|
104
|
+
feeCostUSD
|
|
105
|
+
),
|
|
106
|
+
isCustomMode: mode === 'custom',
|
|
107
|
+
})
|
|
108
|
+
})()
|
|
109
|
+
|
|
110
|
+
const openGate = (after?: StartGate) =>
|
|
111
|
+
openNextGate(
|
|
112
|
+
startGates,
|
|
113
|
+
{
|
|
114
|
+
flagged: () => flaggedTokenSheetRef.current?.open(),
|
|
115
|
+
address: () => confirmToAddressSheetRef.current?.open(),
|
|
116
|
+
value: () => tokenValueBottomSheetRef.current?.open(),
|
|
117
|
+
},
|
|
118
|
+
handleExecuteRoute,
|
|
119
|
+
after
|
|
111
120
|
)
|
|
112
|
-
if (tokenValueLossThresholdExceeded && mode !== 'custom') {
|
|
113
|
-
tokenValueBottomSheetRef.current?.open()
|
|
114
|
-
} else {
|
|
115
|
-
handleExecuteRoute()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
121
|
|
|
119
|
-
const handleStartClick = () =>
|
|
120
|
-
if (flaggedTokens.length) {
|
|
121
|
-
flaggedTokenSheetRef.current?.open()
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
handleStartAfterTokenCheck()
|
|
125
|
-
}
|
|
122
|
+
const handleStartClick = () => openGate()
|
|
126
123
|
|
|
127
124
|
const handleFlaggedTokensContinue = () => {
|
|
128
125
|
flaggedTokenSheetRef.current?.close()
|
|
129
|
-
|
|
126
|
+
openGate('flagged')
|
|
130
127
|
}
|
|
131
128
|
|
|
129
|
+
const handleConfirmToAddressContinue = () => openGate('address')
|
|
130
|
+
|
|
132
131
|
const getButtonText = (): string => {
|
|
133
132
|
switch (mode) {
|
|
134
133
|
case 'custom':
|
|
@@ -180,7 +179,7 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
|
|
|
180
179
|
{!hiddenUI?.lowAddressActivityConfirmation ? (
|
|
181
180
|
<ConfirmToAddressSheet
|
|
182
181
|
ref={confirmToAddressSheetRef}
|
|
183
|
-
onContinue={
|
|
182
|
+
onContinue={handleConfirmToAddressContinue}
|
|
184
183
|
toAddress={toAddress!}
|
|
185
184
|
toChainId={route.toChainId!}
|
|
186
185
|
/>
|
|
@@ -23,3 +23,81 @@ export const getTokenValueLossThreshold = (
|
|
|
23
23
|
}
|
|
24
24
|
return toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) < 0.9
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
interface AddressGateInput {
|
|
28
|
+
toAddress: string | undefined
|
|
29
|
+
hasActivity: boolean | undefined
|
|
30
|
+
isLoadingAddressActivity: boolean
|
|
31
|
+
isActivityAddressFetched: boolean
|
|
32
|
+
confirmationHidden: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const needsAddressConfirmation = ({
|
|
36
|
+
toAddress,
|
|
37
|
+
hasActivity,
|
|
38
|
+
isLoadingAddressActivity,
|
|
39
|
+
isActivityAddressFetched,
|
|
40
|
+
confirmationHidden,
|
|
41
|
+
}: AddressGateInput): boolean =>
|
|
42
|
+
Boolean(
|
|
43
|
+
toAddress &&
|
|
44
|
+
!hasActivity &&
|
|
45
|
+
!isLoadingAddressActivity &&
|
|
46
|
+
isActivityAddressFetched &&
|
|
47
|
+
!confirmationHidden
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
export type RetryGate = 'address' | 'value'
|
|
51
|
+
|
|
52
|
+
export const getRetryGates = (
|
|
53
|
+
input: AddressGateInput & {
|
|
54
|
+
valueLossExceeded: boolean
|
|
55
|
+
isCustomMode: boolean
|
|
56
|
+
}
|
|
57
|
+
): readonly (readonly [gate: RetryGate, needed: boolean])[] => [
|
|
58
|
+
['address', needsAddressConfirmation(input)],
|
|
59
|
+
['value', input.valueLossExceeded && !input.isCustomMode],
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
/** Ordering lives here so no sheet decides what follows it — that is how gates came to be skipped. */
|
|
63
|
+
export const nextGate = <T extends string>(
|
|
64
|
+
gates: readonly (readonly [gate: T, needed: boolean])[],
|
|
65
|
+
after?: T
|
|
66
|
+
): T | undefined => {
|
|
67
|
+
if (!after) {
|
|
68
|
+
return gates.find(([, needed]) => needed)?.[0]
|
|
69
|
+
}
|
|
70
|
+
const index = gates.findIndex(([gate]) => gate === after)
|
|
71
|
+
if (index < 0) {
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
return gates.slice(index + 1).find(([, needed]) => needed)?.[0]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const openNextGate = <T extends string>(
|
|
78
|
+
gates: readonly (readonly [gate: T, needed: boolean])[],
|
|
79
|
+
open: Record<T, () => void>,
|
|
80
|
+
done: () => void,
|
|
81
|
+
after?: T
|
|
82
|
+
): void => {
|
|
83
|
+
const gate = nextGate(gates, after)
|
|
84
|
+
if (gate) {
|
|
85
|
+
open[gate]()
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
done()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type StartGate = 'flagged' | 'address' | 'value'
|
|
92
|
+
|
|
93
|
+
export const getStartGates = (
|
|
94
|
+
input: AddressGateInput & {
|
|
95
|
+
flaggedTokenCount: number
|
|
96
|
+
valueLossExceeded: boolean
|
|
97
|
+
isCustomMode: boolean
|
|
98
|
+
}
|
|
99
|
+
): readonly (readonly [gate: StartGate, needed: boolean])[] => [
|
|
100
|
+
['flagged', input.flaggedTokenCount > 0],
|
|
101
|
+
['address', needsAddressConfirmation(input)],
|
|
102
|
+
['value', input.valueLossExceeded && !input.isCustomMode],
|
|
103
|
+
]
|
package/src/shared.ts
CHANGED
|
@@ -188,4 +188,5 @@ export {
|
|
|
188
188
|
export { getPriceImpact } from './utils/getPriceImpact.js'
|
|
189
189
|
export { fitInputText } from './utils/input.js'
|
|
190
190
|
export { navigationRoutes } from './utils/navigationRoutes.js'
|
|
191
|
+
export { isHttpUrl, openInNewTab } from './utils/url.js'
|
|
191
192
|
export { shortenAddress } from './utils/wallet.js'
|
|
@@ -6,6 +6,7 @@ import { FormStoreProvider } from './form/FormStore.js'
|
|
|
6
6
|
import { HeaderStoreProvider } from './header/useHeaderStore.js'
|
|
7
7
|
import { NavigationTabsStoreProvider } from './navigationTabs/useNavigationTabsStore.js'
|
|
8
8
|
import { PinnedTokensStoreProvider } from './pinnedTokens/PinnedTokensStore.js'
|
|
9
|
+
import { RecentTokensStoreProvider } from './recentTokens/RecentTokensStore.js'
|
|
9
10
|
import { RouteExecutionStoreProvider } from './routes/RouteExecutionStore.js'
|
|
10
11
|
|
|
11
12
|
export const StoreProvider: React.FC<PropsWithChildren<WidgetConfigProps>> = ({
|
|
@@ -18,13 +19,15 @@ export const StoreProvider: React.FC<PropsWithChildren<WidgetConfigProps>> = ({
|
|
|
18
19
|
<HeaderStoreProvider namePrefix={config?.keyPrefix}>
|
|
19
20
|
<BookmarkStoreProvider namePrefix={config?.keyPrefix}>
|
|
20
21
|
<PinnedTokensStoreProvider namePrefix={config?.keyPrefix}>
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
<RecentTokensStoreProvider namePrefix={config?.keyPrefix}>
|
|
23
|
+
<FormStoreProvider formRef={formRef}>
|
|
24
|
+
<ChainOrderStoreProvider namePrefix={config?.keyPrefix}>
|
|
25
|
+
<RouteExecutionStoreProvider namePrefix={config?.keyPrefix}>
|
|
26
|
+
{children}
|
|
27
|
+
</RouteExecutionStoreProvider>
|
|
28
|
+
</ChainOrderStoreProvider>
|
|
29
|
+
</FormStoreProvider>
|
|
30
|
+
</RecentTokensStoreProvider>
|
|
28
31
|
</PinnedTokensStoreProvider>
|
|
29
32
|
</BookmarkStoreProvider>
|
|
30
33
|
</HeaderStoreProvider>
|
|
@@ -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
|
+
}
|