@lifi/widget 4.5.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.
Files changed (522) hide show
  1. package/README.md +26 -3
  2. package/dist/esm/App.d.ts +1 -2
  3. package/dist/esm/App.d.ts.map +1 -1
  4. package/dist/esm/AppDrawer.d.ts +1 -2
  5. package/dist/esm/AppDrawer.d.ts.map +1 -1
  6. package/dist/esm/AppDrawer.js +2 -1
  7. package/dist/esm/AppDrawer.js.map +1 -1
  8. package/dist/esm/components/ActionRow/ActionRow.d.ts +1 -2
  9. package/dist/esm/components/ActionRow/ActionRow.d.ts.map +1 -1
  10. package/dist/esm/components/AmountInput/AmountInput.js +13 -7
  11. package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
  12. package/dist/esm/components/AmountInput/AmountInput.style.d.ts +2 -2
  13. package/dist/esm/components/AmountInput/AmountInput.style.d.ts.map +1 -1
  14. package/dist/esm/components/AmountInput/AmountInputEndAdornment.d.ts +1 -2
  15. package/dist/esm/components/AmountInput/AmountInputEndAdornment.d.ts.map +1 -1
  16. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +2 -13
  17. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  18. package/dist/esm/components/AmountInput/PriceFormHelperText.style.d.ts +1 -2
  19. package/dist/esm/components/AmountInput/PriceFormHelperText.style.d.ts.map +1 -1
  20. package/dist/esm/components/AmountInputCard/PercentageChips.js +2 -13
  21. package/dist/esm/components/AmountInputCard/PercentageChips.js.map +1 -1
  22. package/dist/esm/components/AmountInputCard/PercentageChips.style.js +1 -1
  23. package/dist/esm/components/AmountInputCard/PercentageChips.style.js.map +1 -1
  24. package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js +6 -2
  25. package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js.map +1 -1
  26. package/dist/esm/components/AmountInputCard/SendAmountCard.js +13 -6
  27. package/dist/esm/components/AmountInputCard/SendAmountCard.js.map +1 -1
  28. package/dist/esm/components/Avatar/Avatar.d.ts +1 -2
  29. package/dist/esm/components/Avatar/Avatar.d.ts.map +1 -1
  30. package/dist/esm/components/Avatar/TokenAvatar.d.ts +1 -2
  31. package/dist/esm/components/Avatar/TokenAvatar.d.ts.map +1 -1
  32. package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.d.ts +1 -2
  33. package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.d.ts.map +1 -1
  34. package/dist/esm/components/BaseTransactionButton/types.d.ts +1 -2
  35. package/dist/esm/components/BaseTransactionButton/types.d.ts.map +1 -1
  36. package/dist/esm/components/BottomSheet/BottomSheet.js +1 -0
  37. package/dist/esm/components/BottomSheet/BottomSheet.js.map +1 -1
  38. package/dist/esm/components/BottomSheet/types.d.ts +1 -2
  39. package/dist/esm/components/BottomSheet/types.d.ts.map +1 -1
  40. package/dist/esm/components/ButtonTertiary.d.ts +1 -2
  41. package/dist/esm/components/ButtonTertiary.d.ts.map +1 -1
  42. package/dist/esm/components/Card/CardIconButton.d.ts +1 -2
  43. package/dist/esm/components/Card/CardIconButton.d.ts.map +1 -1
  44. package/dist/esm/components/Card/CardTitle.d.ts +1 -2
  45. package/dist/esm/components/Card/CardTitle.d.ts.map +1 -1
  46. package/dist/esm/components/Card/InputCard.d.ts +1 -2
  47. package/dist/esm/components/Card/InputCard.d.ts.map +1 -1
  48. package/dist/esm/components/ChainSelect/ChainSelect.d.ts +1 -2
  49. package/dist/esm/components/ChainSelect/ChainSelect.d.ts.map +1 -1
  50. package/dist/esm/components/ChainSelect/ChainSelect.style.d.ts +1 -2
  51. package/dist/esm/components/ChainSelect/ChainSelect.style.d.ts.map +1 -1
  52. package/dist/esm/components/Chains/AllChainsAvatar.js +7 -1
  53. package/dist/esm/components/Chains/AllChainsAvatar.js.map +1 -1
  54. package/dist/esm/components/ContractComponent/ContractComponent.d.ts +1 -2
  55. package/dist/esm/components/ContractComponent/ContractComponent.d.ts.map +1 -1
  56. package/dist/esm/components/ContractComponent/ItemPrice.d.ts +2 -3
  57. package/dist/esm/components/ContractComponent/ItemPrice.d.ts.map +1 -1
  58. package/dist/esm/components/ContractComponent/NFT/NFT.d.ts +1 -2
  59. package/dist/esm/components/ContractComponent/NFT/NFT.d.ts.map +1 -1
  60. package/dist/esm/components/ContractComponent/NFT/NFTBase.d.ts +1 -2
  61. package/dist/esm/components/ContractComponent/NFT/NFTBase.d.ts.map +1 -1
  62. package/dist/esm/components/ContractComponent/NFT/types.d.ts +3 -4
  63. package/dist/esm/components/ContractComponent/NFT/types.d.ts.map +1 -1
  64. package/dist/esm/components/Dialog/Dialog.js +2 -1
  65. package/dist/esm/components/Dialog/Dialog.js.map +1 -1
  66. package/dist/esm/components/ExecutionStatusCard/ExecutionStatusCard.d.ts +1 -2
  67. package/dist/esm/components/ExecutionStatusCard/ExecutionStatusCard.d.ts.map +1 -1
  68. package/dist/esm/components/ExecutionStatusCard/StatusIcon.d.ts +1 -2
  69. package/dist/esm/components/ExecutionStatusCard/StatusIcon.d.ts.map +1 -1
  70. package/dist/esm/components/Expansion/Expansion.js +4 -3
  71. package/dist/esm/components/Expansion/Expansion.js.map +1 -1
  72. package/dist/esm/components/FeeBreakdownTooltip.d.ts +1 -2
  73. package/dist/esm/components/FeeBreakdownTooltip.d.ts.map +1 -1
  74. package/dist/esm/components/Header/SettingsButton.js +2 -1
  75. package/dist/esm/components/Header/SettingsButton.js.map +1 -1
  76. package/dist/esm/components/IconCircle/IconCircle.d.ts +1 -2
  77. package/dist/esm/components/IconCircle/IconCircle.d.ts.map +1 -1
  78. package/dist/esm/components/IconCircle/IconCircle.js +2 -1
  79. package/dist/esm/components/IconCircle/IconCircle.js.map +1 -1
  80. package/dist/esm/components/IconCircle/statusIcons.d.ts +1 -2
  81. package/dist/esm/components/IconCircle/statusIcons.d.ts.map +1 -1
  82. package/dist/esm/components/IconTypography.d.ts +1 -2
  83. package/dist/esm/components/IconTypography.d.ts.map +1 -1
  84. package/dist/esm/components/ListItem/ListItemButton.d.ts +1 -2
  85. package/dist/esm/components/ListItem/ListItemButton.d.ts.map +1 -1
  86. package/dist/esm/components/Messages/UnsupportedToAddressMessage.js +27 -0
  87. package/dist/esm/components/Messages/UnsupportedToAddressMessage.js.map +1 -0
  88. package/dist/esm/components/Messages/WarningMessages.d.ts +1 -2
  89. package/dist/esm/components/Messages/WarningMessages.d.ts.map +1 -1
  90. package/dist/esm/components/Messages/WarningMessages.js +2 -0
  91. package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
  92. package/dist/esm/components/Messages/useMessageQueue.js +6 -1
  93. package/dist/esm/components/Messages/useMessageQueue.js.map +1 -1
  94. package/dist/esm/components/PageContainer.d.ts +2 -3
  95. package/dist/esm/components/PageContainer.d.ts.map +1 -1
  96. package/dist/esm/components/PoweredBy/PoweredBy.d.ts +1 -2
  97. package/dist/esm/components/PoweredBy/PoweredBy.d.ts.map +1 -1
  98. package/dist/esm/components/ProgressToNextUpdate.d.ts +1 -2
  99. package/dist/esm/components/ProgressToNextUpdate.d.ts.map +1 -1
  100. package/dist/esm/components/RouteCard/RouteCard.d.ts +1 -2
  101. package/dist/esm/components/RouteCard/RouteCard.d.ts.map +1 -1
  102. package/dist/esm/components/RouteCard/RouteCardSkeleton.d.ts +1 -2
  103. package/dist/esm/components/RouteCard/RouteCardSkeleton.d.ts.map +1 -1
  104. package/dist/esm/components/RouteCard/RouteDetails.d.ts +1 -2
  105. package/dist/esm/components/RouteCard/RouteDetails.d.ts.map +1 -1
  106. package/dist/esm/components/RouteCard/RouteDetails.js +2 -1
  107. package/dist/esm/components/RouteCard/RouteDetails.js.map +1 -1
  108. package/dist/esm/components/RouteCard/RouteDetails.style.d.ts +5 -6
  109. package/dist/esm/components/RouteCard/RouteDetails.style.d.ts.map +1 -1
  110. package/dist/esm/components/RouteCard/RouteNotFoundCard.d.ts +1 -2
  111. package/dist/esm/components/RouteCard/RouteNotFoundCard.d.ts.map +1 -1
  112. package/dist/esm/components/RouteCard/RouteTokens.d.ts +1 -2
  113. package/dist/esm/components/RouteCard/RouteTokens.d.ts.map +1 -1
  114. package/dist/esm/components/RouteCard/types.d.ts +2 -3
  115. package/dist/esm/components/RouteCard/types.d.ts.map +1 -1
  116. package/dist/esm/components/Routes/LimitOrderRoutes.js +2 -2
  117. package/dist/esm/components/Routes/LimitOrderRoutes.js.map +1 -1
  118. package/dist/esm/components/Routes/RoutesContent.js +2 -2
  119. package/dist/esm/components/Routes/RoutesContent.js.map +1 -1
  120. package/dist/esm/components/Search/SearchInput.d.ts +1 -2
  121. package/dist/esm/components/Search/SearchInput.d.ts.map +1 -1
  122. package/dist/esm/components/SendToWallet/SendToWalletButton.d.ts +1 -2
  123. package/dist/esm/components/SendToWallet/SendToWalletButton.d.ts.map +1 -1
  124. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js +2 -2
  125. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js.map +1 -1
  126. package/dist/esm/components/Skeleton/WidgetSkeleton.d.ts +1 -2
  127. package/dist/esm/components/Skeleton/WidgetSkeleton.d.ts.map +1 -1
  128. package/dist/esm/components/Skeleton/WidgetSkeleton.js +2 -1
  129. package/dist/esm/components/Skeleton/WidgetSkeleton.js.map +1 -1
  130. package/dist/esm/components/Step/StepActions.js +18 -16
  131. package/dist/esm/components/Step/StepActions.js.map +1 -1
  132. package/dist/esm/components/StepActions/SentToWalletRow.d.ts +1 -2
  133. package/dist/esm/components/StepActions/SentToWalletRow.d.ts.map +1 -1
  134. package/dist/esm/components/StepActions/StepActionRow.js +2 -1
  135. package/dist/esm/components/StepActions/StepActionRow.js.map +1 -1
  136. package/dist/esm/components/StepActions/StepActionRow.style.d.ts +1 -2
  137. package/dist/esm/components/StepActions/StepActionRow.style.d.ts.map +1 -1
  138. package/dist/esm/components/StepActions/StepActionsList.d.ts +1 -2
  139. package/dist/esm/components/StepActions/StepActionsList.d.ts.map +1 -1
  140. package/dist/esm/components/StepActions/executionRows.d.ts +2 -3
  141. package/dist/esm/components/StepActions/executionRows.d.ts.map +1 -1
  142. package/dist/esm/components/Switch.js +1 -1
  143. package/dist/esm/components/Switch.js.map +1 -1
  144. package/dist/esm/components/Tabs/Tabs.style.js +4 -2
  145. package/dist/esm/components/Tabs/Tabs.style.js.map +1 -1
  146. package/dist/esm/components/Token/Token.d.ts.map +1 -1
  147. package/dist/esm/components/Token/Token.js +2 -4
  148. package/dist/esm/components/Token/Token.js.map +1 -1
  149. package/dist/esm/components/TokenList/RecentTokensHeader.js +44 -0
  150. package/dist/esm/components/TokenList/RecentTokensHeader.js.map +1 -0
  151. package/dist/esm/components/TokenList/RecentTokensToggle.js +36 -0
  152. package/dist/esm/components/TokenList/RecentTokensToggle.js.map +1 -0
  153. package/dist/esm/components/TokenList/RemoveRecentTokenButton.js +32 -0
  154. package/dist/esm/components/TokenList/RemoveRecentTokenButton.js.map +1 -0
  155. package/dist/esm/components/TokenList/TokenList.js +55 -5
  156. package/dist/esm/components/TokenList/TokenList.js.map +1 -1
  157. package/dist/esm/components/TokenList/TokenListItem.js +81 -27
  158. package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
  159. package/dist/esm/components/TokenList/TokenNotFound.d.ts +1 -2
  160. package/dist/esm/components/TokenList/TokenNotFound.d.ts.map +1 -1
  161. package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts +1 -2
  162. package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts.map +1 -1
  163. package/dist/esm/components/TokenList/VirtualizedTokenList.js +63 -37
  164. package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
  165. package/dist/esm/components/TokenList/types.d.ts +9 -2
  166. package/dist/esm/components/TokenList/types.d.ts.map +1 -1
  167. package/dist/esm/components/TokenList/useTokenSelect.d.ts +1 -2
  168. package/dist/esm/components/TokenList/useTokenSelect.d.ts.map +1 -1
  169. package/dist/esm/components/TokenRate/TokenRate.d.ts +1 -2
  170. package/dist/esm/components/TokenRate/TokenRate.d.ts.map +1 -1
  171. package/dist/esm/components/TokenRate/TokenRate.js +2 -1
  172. package/dist/esm/components/TokenRate/TokenRate.js.map +1 -1
  173. package/dist/esm/components/TransactionCard/ActiveTransactionCard.js +22 -21
  174. package/dist/esm/components/TransactionCard/ActiveTransactionCard.js.map +1 -1
  175. package/dist/esm/components/TransactionCard/TransactionCard.style.d.ts +2 -3
  176. package/dist/esm/components/TransactionCard/TransactionCard.style.d.ts.map +1 -1
  177. package/dist/esm/config/constants.d.ts +1 -2
  178. package/dist/esm/config/constants.d.ts.map +1 -1
  179. package/dist/esm/config/version.d.ts +2 -3
  180. package/dist/esm/config/version.d.ts.map +1 -1
  181. package/dist/esm/config/version.js +1 -1
  182. package/dist/esm/config/version.js.map +1 -1
  183. package/dist/esm/hooks/timer/time.js +2 -2
  184. package/dist/esm/hooks/timer/time.js.map +1 -1
  185. package/dist/esm/hooks/useAddressActivity.d.ts +1 -2
  186. package/dist/esm/hooks/useAddressActivity.d.ts.map +1 -1
  187. package/dist/esm/hooks/useAddressValidation.d.ts +2 -3
  188. package/dist/esm/hooks/useAddressValidation.d.ts.map +1 -1
  189. package/dist/esm/hooks/useAvailableChains.d.ts +1 -2
  190. package/dist/esm/hooks/useAvailableChains.d.ts.map +1 -1
  191. package/dist/esm/hooks/useAvailableChains.js +2 -1
  192. package/dist/esm/hooks/useAvailableChains.js.map +1 -1
  193. package/dist/esm/hooks/useChain.d.ts +1 -2
  194. package/dist/esm/hooks/useChain.d.ts.map +1 -1
  195. package/dist/esm/hooks/useContactSupport.d.ts +1 -2
  196. package/dist/esm/hooks/useContactSupport.d.ts.map +1 -1
  197. package/dist/esm/hooks/useDebouncedWatch.d.ts +1 -2
  198. package/dist/esm/hooks/useDebouncedWatch.d.ts.map +1 -1
  199. package/dist/esm/hooks/useDisplayedTokens.js +6 -4
  200. package/dist/esm/hooks/useDisplayedTokens.js.map +1 -1
  201. package/dist/esm/hooks/useExplorer.d.ts +1 -2
  202. package/dist/esm/hooks/useExplorer.d.ts.map +1 -1
  203. package/dist/esm/hooks/useExplorer.js +4 -0
  204. package/dist/esm/hooks/useExplorer.js.map +1 -1
  205. package/dist/esm/hooks/useFlaggedTokenGuard.js +28 -0
  206. package/dist/esm/hooks/useFlaggedTokenGuard.js.map +1 -0
  207. package/dist/esm/hooks/useGasSufficiency.js +3 -1
  208. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  209. package/dist/esm/hooks/useHeader.d.ts +1 -2
  210. package/dist/esm/hooks/useHeader.d.ts.map +1 -1
  211. package/dist/esm/hooks/useListHeight.d.ts +1 -2
  212. package/dist/esm/hooks/useListHeight.d.ts.map +1 -1
  213. package/dist/esm/hooks/useMaxSendAmount.js +15 -0
  214. package/dist/esm/hooks/useMaxSendAmount.js.map +1 -0
  215. package/dist/esm/hooks/useNavigateBack.d.ts +1 -2
  216. package/dist/esm/hooks/useNavigateBack.d.ts.map +1 -1
  217. package/dist/esm/hooks/usePacedRouteExecution.js +3 -2
  218. package/dist/esm/hooks/usePacedRouteExecution.js.map +1 -1
  219. package/dist/esm/hooks/useRecentTokens.js +46 -0
  220. package/dist/esm/hooks/useRecentTokens.js.map +1 -0
  221. package/dist/esm/hooks/useRouteExecution.d.ts +1 -2
  222. package/dist/esm/hooks/useRouteExecution.d.ts.map +1 -1
  223. package/dist/esm/hooks/useRouteExecutionMessage.d.ts +1 -2
  224. package/dist/esm/hooks/useRouteExecutionMessage.d.ts.map +1 -1
  225. package/dist/esm/hooks/useRouteExecutionMessage.js +3 -2
  226. package/dist/esm/hooks/useRouteExecutionMessage.js.map +1 -1
  227. package/dist/esm/hooks/useRoutes.d.ts +1 -2
  228. package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
  229. package/dist/esm/hooks/useRoutes.js +8 -1
  230. package/dist/esm/hooks/useRoutes.js.map +1 -1
  231. package/dist/esm/hooks/useToAddressRequirements.d.ts +3 -2
  232. package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
  233. package/dist/esm/hooks/useToAddressRequirements.js +13 -1
  234. package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
  235. package/dist/esm/hooks/useToken.d.ts +1 -2
  236. package/dist/esm/hooks/useToken.d.ts.map +1 -1
  237. package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -2
  238. package/dist/esm/hooks/useTokenAddressBalance.d.ts.map +1 -1
  239. package/dist/esm/hooks/useTokenBalances.d.ts +3 -2
  240. package/dist/esm/hooks/useTokenBalances.d.ts.map +1 -1
  241. package/dist/esm/hooks/useTokenBalances.js +19 -8
  242. package/dist/esm/hooks/useTokenBalances.js.map +1 -1
  243. package/dist/esm/hooks/useTokenBalancesQueries.js +29 -28
  244. package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -1
  245. package/dist/esm/hooks/useTokenList.d.ts +1 -2
  246. package/dist/esm/hooks/useTokenList.d.ts.map +1 -1
  247. package/dist/esm/hooks/useTokenSearch.js +5 -6
  248. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  249. package/dist/esm/hooks/useTokens.js +40 -25
  250. package/dist/esm/hooks/useTokens.js.map +1 -1
  251. package/dist/esm/hooks/useTools.d.ts +1 -2
  252. package/dist/esm/hooks/useTools.d.ts.map +1 -1
  253. package/dist/esm/hooks/useWideVariant.js +2 -1
  254. package/dist/esm/hooks/useWideVariant.js.map +1 -1
  255. package/dist/esm/hooks/useWidgetChains.d.ts +1 -2
  256. package/dist/esm/hooks/useWidgetChains.d.ts.map +1 -1
  257. package/dist/esm/hooks/useWidgetEvents.d.ts +3 -4
  258. package/dist/esm/hooks/useWidgetEvents.d.ts.map +1 -1
  259. package/dist/esm/i18n/bn.json +7 -1
  260. package/dist/esm/i18n/de.json +7 -1
  261. package/dist/esm/i18n/en.json +16 -3
  262. package/dist/esm/i18n/es.json +7 -1
  263. package/dist/esm/i18n/fr.json +7 -1
  264. package/dist/esm/i18n/hi.json +7 -1
  265. package/dist/esm/i18n/id.json +7 -1
  266. package/dist/esm/i18n/it.json +7 -1
  267. package/dist/esm/i18n/ja.json +7 -1
  268. package/dist/esm/i18n/ko.json +7 -1
  269. package/dist/esm/i18n/pl.json +7 -1
  270. package/dist/esm/i18n/pt.json +7 -1
  271. package/dist/esm/i18n/th.json +7 -1
  272. package/dist/esm/i18n/tr.json +7 -1
  273. package/dist/esm/i18n/uk.json +7 -1
  274. package/dist/esm/i18n/vi.json +7 -1
  275. package/dist/esm/i18n/zh.json +7 -1
  276. package/dist/esm/pages/MainPage/MainPage.js +2 -1
  277. package/dist/esm/pages/MainPage/MainPage.js.map +1 -1
  278. package/dist/esm/pages/MainPage/MainWarningMessages.d.ts +1 -2
  279. package/dist/esm/pages/MainPage/MainWarningMessages.d.ts.map +1 -1
  280. package/dist/esm/pages/MainPage/ReviewButton.js +2 -2
  281. package/dist/esm/pages/MainPage/ReviewButton.js.map +1 -1
  282. package/dist/esm/pages/RoutesPage/RoutesPage.js +2 -2
  283. package/dist/esm/pages/RoutesPage/RoutesPage.js.map +1 -1
  284. package/dist/esm/pages/SelectChainPage/SelectChainPage.d.ts +1 -2
  285. package/dist/esm/pages/SelectChainPage/SelectChainPage.d.ts.map +1 -1
  286. package/dist/esm/pages/SelectChainPage/SelectChainPage.js +13 -12
  287. package/dist/esm/pages/SelectChainPage/SelectChainPage.js.map +1 -1
  288. package/dist/esm/pages/SelectChainPage/types.d.ts +1 -2
  289. package/dist/esm/pages/SelectChainPage/types.d.ts.map +1 -1
  290. package/dist/esm/pages/SelectEnabledToolsPage.js +8 -5
  291. package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
  292. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.d.ts +1 -2
  293. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.d.ts.map +1 -1
  294. package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js +2 -1
  295. package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js.map +1 -1
  296. package/dist/esm/pages/SettingsPage/SmallBalanceFilterSettings.js +2 -1
  297. package/dist/esm/pages/SettingsPage/SmallBalanceFilterSettings.js.map +1 -1
  298. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.d.ts +1 -2
  299. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.d.ts.map +1 -1
  300. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.js +2 -1
  301. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.js.map +1 -1
  302. package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js +2 -1
  303. package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js.map +1 -1
  304. package/dist/esm/pages/TransactionPage/ConfirmToAddressSheet.d.ts +1 -2
  305. package/dist/esm/pages/TransactionPage/ConfirmToAddressSheet.d.ts.map +1 -1
  306. package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.d.ts +2 -3
  307. package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.d.ts.map +1 -1
  308. package/dist/esm/pages/TransactionPage/ExecutionDoneCard.d.ts +1 -2
  309. package/dist/esm/pages/TransactionPage/ExecutionDoneCard.d.ts.map +1 -1
  310. package/dist/esm/pages/TransactionPage/RouteTracker.d.ts +1 -2
  311. package/dist/esm/pages/TransactionPage/RouteTracker.d.ts.map +1 -1
  312. package/dist/esm/pages/TransactionPage/StartTransactionButton.d.ts +1 -2
  313. package/dist/esm/pages/TransactionPage/StartTransactionButton.d.ts.map +1 -1
  314. package/dist/esm/pages/TransactionPage/StartTransactionButton.js +4 -3
  315. package/dist/esm/pages/TransactionPage/StartTransactionButton.js.map +1 -1
  316. package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.d.ts +1 -2
  317. package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.d.ts.map +1 -1
  318. package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js +0 -1
  319. package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js.map +1 -1
  320. package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js +63 -0
  321. package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js.map +1 -0
  322. package/dist/esm/pages/TransactionPage/TransactionDoneButtons.d.ts +1 -2
  323. package/dist/esm/pages/TransactionPage/TransactionDoneButtons.d.ts.map +1 -1
  324. package/dist/esm/pages/TransactionPage/TransactionExecutionContent.js +19 -16
  325. package/dist/esm/pages/TransactionPage/TransactionExecutionContent.js.map +1 -1
  326. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js +38 -10
  327. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
  328. package/dist/esm/pages/TransactionPage/TransactionReview.js +32 -9
  329. package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
  330. package/dist/esm/pages/TransactionPage/types.d.ts +1 -2
  331. package/dist/esm/pages/TransactionPage/types.d.ts.map +1 -1
  332. package/dist/esm/pages/TransactionPage/utils.d.ts +2 -3
  333. package/dist/esm/pages/TransactionPage/utils.d.ts.map +1 -1
  334. package/dist/esm/pages/TransactionPage/utils.js +23 -1
  335. package/dist/esm/pages/TransactionPage/utils.js.map +1 -1
  336. package/dist/esm/providers/I18nProvider/I18nProvider.d.ts +1 -2
  337. package/dist/esm/providers/I18nProvider/I18nProvider.d.ts.map +1 -1
  338. package/dist/esm/providers/I18nProvider/I18nProvider.js +37 -36
  339. package/dist/esm/providers/I18nProvider/I18nProvider.js.map +1 -1
  340. package/dist/esm/providers/I18nProvider/types.d.ts +4 -5
  341. package/dist/esm/providers/I18nProvider/types.d.ts.map +1 -1
  342. package/dist/esm/providers/QueryClientProvider.d.ts +1 -2
  343. package/dist/esm/providers/QueryClientProvider.d.ts.map +1 -1
  344. package/dist/esm/providers/SDKClientProvider.d.ts +2 -3
  345. package/dist/esm/providers/SDKClientProvider.d.ts.map +1 -1
  346. package/dist/esm/providers/ThemeProvider/ThemeProvider.js +2 -1
  347. package/dist/esm/providers/ThemeProvider/ThemeProvider.js.map +1 -1
  348. package/dist/esm/providers/WalletProvider/WalletProvider.d.ts +1 -2
  349. package/dist/esm/providers/WalletProvider/WalletProvider.d.ts.map +1 -1
  350. package/dist/esm/providers/WalletProvider/WalletProvider.js +10 -9
  351. package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
  352. package/dist/esm/providers/WalletProvider/useExternalWalletProvider.js +7 -3
  353. package/dist/esm/providers/WalletProvider/useExternalWalletProvider.js.map +1 -1
  354. package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts +2 -3
  355. package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
  356. package/dist/esm/providers/WidgetProvider/types.d.ts +2 -3
  357. package/dist/esm/providers/WidgetProvider/types.d.ts.map +1 -1
  358. package/dist/esm/stores/StoreProvider.d.ts +1 -2
  359. package/dist/esm/stores/StoreProvider.d.ts.map +1 -1
  360. package/dist/esm/stores/StoreProvider.js +10 -6
  361. package/dist/esm/stores/StoreProvider.js.map +1 -1
  362. package/dist/esm/stores/bookmarks/BookmarkStore.d.ts +1 -2
  363. package/dist/esm/stores/bookmarks/BookmarkStore.d.ts.map +1 -1
  364. package/dist/esm/stores/bookmarks/types.d.ts +5 -6
  365. package/dist/esm/stores/bookmarks/types.d.ts.map +1 -1
  366. package/dist/esm/stores/chains/ChainOrderStore.d.ts +1 -2
  367. package/dist/esm/stores/chains/ChainOrderStore.d.ts.map +1 -1
  368. package/dist/esm/stores/chains/ChainOrderStore.js +11 -5
  369. package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
  370. package/dist/esm/stores/chains/types.d.ts +1 -2
  371. package/dist/esm/stores/chains/types.d.ts.map +1 -1
  372. package/dist/esm/stores/form/types.d.ts +20 -21
  373. package/dist/esm/stores/form/types.d.ts.map +1 -1
  374. package/dist/esm/stores/form/useFieldActions.d.ts +1 -2
  375. package/dist/esm/stores/form/useFieldActions.d.ts.map +1 -1
  376. package/dist/esm/stores/form/useFieldValues.d.ts +1 -2
  377. package/dist/esm/stores/form/useFieldValues.d.ts.map +1 -1
  378. package/dist/esm/stores/header/types.d.ts +1 -2
  379. package/dist/esm/stores/header/types.d.ts.map +1 -1
  380. package/dist/esm/stores/header/useHeaderStore.d.ts +2 -3
  381. package/dist/esm/stores/header/useHeaderStore.d.ts.map +1 -1
  382. package/dist/esm/stores/inputMode/useInputModeStore.d.ts +1 -2
  383. package/dist/esm/stores/inputMode/useInputModeStore.d.ts.map +1 -1
  384. package/dist/esm/stores/recentTokens/RecentTokensStore.js +23 -0
  385. package/dist/esm/stores/recentTokens/RecentTokensStore.js.map +1 -0
  386. package/dist/esm/stores/recentTokens/createRecentTokensStore.js +54 -0
  387. package/dist/esm/stores/recentTokens/createRecentTokensStore.js.map +1 -0
  388. package/dist/esm/stores/recentTokens/utils.js +15 -0
  389. package/dist/esm/stores/recentTokens/utils.js.map +1 -0
  390. package/dist/esm/stores/routes/RouteExecutionStore.d.ts +2 -3
  391. package/dist/esm/stores/routes/RouteExecutionStore.d.ts.map +1 -1
  392. package/dist/esm/stores/routes/types.d.ts +3 -4
  393. package/dist/esm/stores/routes/types.d.ts.map +1 -1
  394. package/dist/esm/stores/routes/useRouteExecutionIndicator.js +4 -3
  395. package/dist/esm/stores/routes/useRouteExecutionIndicator.js.map +1 -1
  396. package/dist/esm/stores/routes/utils.d.ts +4 -5
  397. package/dist/esm/stores/routes/utils.d.ts.map +1 -1
  398. package/dist/esm/stores/settings/SettingsStore.d.ts +2 -3
  399. package/dist/esm/stores/settings/SettingsStore.d.ts.map +1 -1
  400. package/dist/esm/stores/settings/types.d.ts +2 -3
  401. package/dist/esm/stores/settings/types.d.ts.map +1 -1
  402. package/dist/esm/stores/types.d.ts +2 -3
  403. package/dist/esm/stores/types.d.ts.map +1 -1
  404. package/dist/esm/themes/azureLight.d.ts +1 -2
  405. package/dist/esm/themes/azureLight.d.ts.map +1 -1
  406. package/dist/esm/themes/jumper.d.ts +1 -2
  407. package/dist/esm/themes/jumper.d.ts.map +1 -1
  408. package/dist/esm/themes/palettes.d.ts +3 -4
  409. package/dist/esm/themes/palettes.d.ts.map +1 -1
  410. package/dist/esm/themes/types.d.ts +1 -0
  411. package/dist/esm/themes/watermelonLight.d.ts +1 -2
  412. package/dist/esm/themes/watermelonLight.d.ts.map +1 -1
  413. package/dist/esm/themes/windows95.d.ts +1 -2
  414. package/dist/esm/themes/windows95.d.ts.map +1 -1
  415. package/dist/esm/types/events.d.ts +13 -14
  416. package/dist/esm/types/events.d.ts.map +1 -1
  417. package/dist/esm/types/token.d.ts +6 -1
  418. package/dist/esm/types/token.d.ts.map +1 -1
  419. package/dist/esm/types/widget.d.ts +55 -51
  420. package/dist/esm/types/widget.d.ts.map +1 -1
  421. package/dist/esm/types/widget.js.map +1 -1
  422. package/dist/esm/utils/address.js +19 -0
  423. package/dist/esm/utils/address.js.map +1 -0
  424. package/dist/esm/utils/compactNumberFormatter.d.ts +1 -2
  425. package/dist/esm/utils/compactNumberFormatter.d.ts.map +1 -1
  426. package/dist/esm/utils/compactNumberFormatter.js +1 -3
  427. package/dist/esm/utils/compactNumberFormatter.js.map +1 -1
  428. package/dist/esm/utils/converters.d.ts +1 -2
  429. package/dist/esm/utils/converters.d.ts.map +1 -1
  430. package/dist/esm/utils/currencyExtendedFormatter.d.ts +1 -2
  431. package/dist/esm/utils/currencyExtendedFormatter.d.ts.map +1 -1
  432. package/dist/esm/utils/customReceiver.js +12 -0
  433. package/dist/esm/utils/customReceiver.js.map +1 -0
  434. package/dist/esm/utils/elements.d.ts +2 -3
  435. package/dist/esm/utils/elements.d.ts.map +1 -1
  436. package/dist/esm/utils/enum.d.ts +1 -2
  437. package/dist/esm/utils/enum.d.ts.map +1 -1
  438. package/dist/esm/utils/fees.d.ts +2 -3
  439. package/dist/esm/utils/fees.d.ts.map +1 -1
  440. package/dist/esm/utils/format.d.ts +8 -9
  441. package/dist/esm/utils/format.d.ts.map +1 -1
  442. package/dist/esm/utils/gas.js +24 -0
  443. package/dist/esm/utils/gas.js.map +1 -0
  444. package/dist/esm/utils/getErrorMessage.js +0 -1
  445. package/dist/esm/utils/getErrorMessage.js.map +1 -1
  446. package/dist/esm/utils/getPriceImpact.d.ts +1 -2
  447. package/dist/esm/utils/getPriceImpact.d.ts.map +1 -1
  448. package/dist/esm/utils/input.d.ts +1 -2
  449. package/dist/esm/utils/input.d.ts.map +1 -1
  450. package/dist/esm/utils/limitOrder.js +1 -1
  451. package/dist/esm/utils/limitOrder.js.map +1 -1
  452. package/dist/esm/utils/navigationRoutes.d.ts +2 -3
  453. package/dist/esm/utils/navigationRoutes.d.ts.map +1 -1
  454. package/dist/esm/utils/percentFormatter.d.ts +1 -2
  455. package/dist/esm/utils/percentFormatter.d.ts.map +1 -1
  456. package/dist/esm/utils/recentTokens.js +97 -0
  457. package/dist/esm/utils/recentTokens.js.map +1 -0
  458. package/dist/esm/utils/token.js +50 -7
  459. package/dist/esm/utils/token.js.map +1 -1
  460. package/dist/esm/utils/tokenList.js +54 -25
  461. package/dist/esm/utils/tokenList.js.map +1 -1
  462. package/dist/esm/utils/tokenListBands.js +85 -0
  463. package/dist/esm/utils/tokenListBands.js.map +1 -0
  464. package/dist/esm/utils/wallet.d.ts +1 -2
  465. package/dist/esm/utils/wallet.d.ts.map +1 -1
  466. package/package.json +15 -15
  467. package/src/components/AmountInput/AmountInputEndAdornment.tsx +2 -21
  468. package/src/components/AmountInputCard/PercentageChips.tsx +2 -18
  469. package/src/components/AmountInputCard/ReceiveAmountCard.tsx +16 -3
  470. package/src/components/BottomSheet/BottomSheet.tsx +3 -0
  471. package/src/components/Chains/AllChainsAvatar.tsx +7 -1
  472. package/src/components/Messages/UnsupportedToAddressMessage.tsx +24 -0
  473. package/src/components/Messages/WarningMessages.tsx +3 -0
  474. package/src/components/Messages/useMessageQueue.ts +9 -0
  475. package/src/components/Routes/LimitOrderRoutes.tsx +5 -2
  476. package/src/components/Routes/RoutesContent.tsx +5 -2
  477. package/src/components/SendToWallet/SendToWalletExpandButton.tsx +2 -1
  478. package/src/components/Token/Token.tsx +2 -1
  479. package/src/components/TokenList/RecentTokensHeader.tsx +52 -0
  480. package/src/components/TokenList/RecentTokensToggle.tsx +45 -0
  481. package/src/components/TokenList/RemoveRecentTokenButton.tsx +38 -0
  482. package/src/components/TokenList/TokenList.tsx +92 -3
  483. package/src/components/TokenList/TokenListItem.tsx +83 -9
  484. package/src/components/TokenList/VirtualizedTokenList.tsx +86 -103
  485. package/src/components/TokenList/types.ts +13 -0
  486. package/src/config/version.ts +1 -1
  487. package/src/hooks/useAvailableChains.ts +1 -0
  488. package/src/hooks/useDisplayedTokens.ts +17 -3
  489. package/src/hooks/useExplorer.ts +2 -0
  490. package/src/hooks/useFlaggedTokenGuard.ts +33 -0
  491. package/src/hooks/useGasSufficiency.ts +9 -1
  492. package/src/hooks/useMaxSendAmount.ts +21 -0
  493. package/src/hooks/useRecentTokens.ts +88 -0
  494. package/src/hooks/useRoutes.ts +10 -0
  495. package/src/hooks/useToAddressRequirements.ts +23 -1
  496. package/src/hooks/useTokenBalances.ts +38 -19
  497. package/src/hooks/useTokenSearch.ts +6 -19
  498. package/src/hooks/useTokens.ts +97 -40
  499. package/src/pages/MainPage/ReviewButton.tsx +6 -2
  500. package/src/pages/RoutesPage/RoutesPage.tsx +5 -2
  501. package/src/pages/TransactionPage/TokenValueBottomSheet.tsx +1 -1
  502. package/src/pages/TransactionPage/TokenVerificationBottomSheet.tsx +93 -0
  503. package/src/pages/TransactionPage/TransactionFailedButtons.tsx +62 -26
  504. package/src/pages/TransactionPage/TransactionReview.tsx +51 -25
  505. package/src/pages/TransactionPage/utils.ts +78 -0
  506. package/src/providers/WalletProvider/useExternalWalletProvider.ts +9 -1
  507. package/src/stores/StoreProvider.tsx +10 -7
  508. package/src/stores/chains/ChainOrderStore.test.tsx +298 -0
  509. package/src/stores/chains/ChainOrderStore.tsx +25 -6
  510. package/src/stores/recentTokens/RecentTokensStore.tsx +39 -0
  511. package/src/stores/recentTokens/createRecentTokensStore.ts +107 -0
  512. package/src/stores/recentTokens/types.ts +37 -0
  513. package/src/stores/recentTokens/utils.ts +18 -0
  514. package/src/types/token.ts +8 -3
  515. package/src/types/widget.ts +5 -0
  516. package/src/utils/address.ts +21 -0
  517. package/src/utils/customReceiver.ts +31 -0
  518. package/src/utils/gas.ts +41 -0
  519. package/src/utils/recentTokens.ts +187 -0
  520. package/src/utils/token.ts +122 -19
  521. package/src/utils/tokenList.ts +60 -14
  522. package/src/utils/tokenListBands.ts +181 -0
@@ -8,6 +8,7 @@ import { Card } from '../../components/Card/Card.js'
8
8
  import { WarningMessages } from '../../components/Messages/WarningMessages.js'
9
9
  import { RouteTokens } from '../../components/RouteCard/RouteTokens.js'
10
10
  import { useAddressActivity } from '../../hooks/useAddressActivity.js'
11
+ import { useFlaggedTokenGuard } from '../../hooks/useFlaggedTokenGuard.js'
11
12
  import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
12
13
  import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
13
14
  import { useFieldActions } from '../../stores/form/useFieldActions.js'
@@ -18,9 +19,13 @@ import { navigationRoutes } from '../../utils/navigationRoutes.js'
18
19
  import { ConfirmToAddressSheet } from './ConfirmToAddressSheet.js'
19
20
  import { StartTransactionButton } from './StartTransactionButton.js'
20
21
  import { TokenValueBottomSheet } from './TokenValueBottomSheet.js'
22
+ import { TokenVerificationBottomSheet } from './TokenVerificationBottomSheet.js'
23
+ import type { StartGate } from './utils.js'
21
24
  import {
22
25
  calculateValueLossPercentage,
26
+ getStartGates,
23
27
  getTokenValueLossThreshold,
28
+ openNextGate,
24
29
  } from './utils.js'
25
30
 
26
31
  interface TransactionReviewProps {
@@ -44,6 +49,8 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
44
49
  const tokenValueBottomSheetRef = useRef<BottomSheetBase>(null)
45
50
  const confirmToAddressSheetRef = useRef<BottomSheetBase>(null)
46
51
 
52
+ const { flaggedTokens, flaggedTokenSheetRef } = useFlaggedTokenGuard(route)
53
+
47
54
  const {
48
55
  toAddress,
49
56
  hasActivity,
@@ -81,34 +88,46 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
81
88
  })
82
89
  }
83
90
 
84
- const handleStartClick = () => {
85
- if (
86
- toAddress &&
87
- !hasActivity &&
88
- !isLoadingAddressActivity &&
89
- isActivityAddressFetched &&
90
- !hiddenUI?.lowAddressActivityConfirmation
91
- ) {
92
- confirmToAddressSheetRef.current?.open()
93
- return
94
- }
95
-
91
+ const startGates = (() => {
96
92
  const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)
97
- const fromAmountUSD = Number.parseFloat(route.fromAmountUSD)
98
- const toAmountUSD = Number.parseFloat(route.toAmountUSD)
99
- const tokenValueLossThresholdExceeded = getTokenValueLossThreshold(
100
- fromAmountUSD,
101
- toAmountUSD,
102
- gasCostUSD,
103
- feeCostUSD
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
104
120
  )
105
- if (tokenValueLossThresholdExceeded && mode !== 'custom') {
106
- tokenValueBottomSheetRef.current?.open()
107
- } else {
108
- handleExecuteRoute()
109
- }
121
+
122
+ const handleStartClick = () => openGate()
123
+
124
+ const handleFlaggedTokensContinue = () => {
125
+ flaggedTokenSheetRef.current?.close()
126
+ openGate('flagged')
110
127
  }
111
128
 
129
+ const handleConfirmToAddressContinue = () => openGate('address')
130
+
112
131
  const getButtonText = (): string => {
113
132
  switch (mode) {
114
133
  case 'custom':
@@ -150,10 +169,17 @@ export const TransactionReview: React.FC<TransactionReviewProps> = ({
150
169
  onContinue={handleExecuteRoute}
151
170
  />
152
171
  ) : null}
172
+ {flaggedTokens.length ? (
173
+ <TokenVerificationBottomSheet
174
+ ref={flaggedTokenSheetRef}
175
+ tokens={flaggedTokens}
176
+ onContinue={handleFlaggedTokensContinue}
177
+ />
178
+ ) : null}
153
179
  {!hiddenUI?.lowAddressActivityConfirmation ? (
154
180
  <ConfirmToAddressSheet
155
181
  ref={confirmToAddressSheetRef}
156
- onContinue={handleExecuteRoute}
182
+ onContinue={handleConfirmToAddressContinue}
157
183
  toAddress={toAddress!}
158
184
  toChainId={route.toChainId!}
159
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
+ ]
@@ -3,6 +3,7 @@ import {
3
3
  useBitcoinContext,
4
4
  useEthereumContext,
5
5
  useSolanaContext,
6
+ useStellarContext,
6
7
  useSuiContext,
7
8
  useTronContext,
8
9
  } from '@lifi/widget-provider'
@@ -21,6 +22,7 @@ const internalChainTypes = [
21
22
  ChainType.UTXO,
22
23
  ChainType.MVM,
23
24
  ChainType.TVM,
25
+ ChainType.STL,
24
26
  ]
25
27
 
26
28
  export function useExternalWalletProvider(): ExternalWalletProvider {
@@ -30,6 +32,7 @@ export function useExternalWalletProvider(): ExternalWalletProvider {
30
32
  const { isExternalContext: hasExternalBitcoinContext } = useBitcoinContext()
31
33
  const { isExternalContext: hasExternalSuiContext } = useSuiContext()
32
34
  const { isExternalContext: hasExternalTronContext } = useTronContext()
35
+ const { isExternalContext: hasExternalStellarContext } = useStellarContext()
33
36
  const data = useMemo(() => {
34
37
  const providers: ChainType[] = []
35
38
  if (hasExternalEthereumContext) {
@@ -47,12 +50,16 @@ export function useExternalWalletProvider(): ExternalWalletProvider {
47
50
  if (hasExternalTronContext) {
48
51
  providers.push(ChainType.TVM)
49
52
  }
53
+ if (hasExternalStellarContext) {
54
+ providers.push(ChainType.STL)
55
+ }
50
56
  const hasExternalProvider =
51
57
  hasExternalEthereumContext ||
52
58
  hasExternalSolanaContext ||
53
59
  hasExternalBitcoinContext ||
54
60
  hasExternalSuiContext ||
55
- hasExternalTronContext
61
+ hasExternalTronContext ||
62
+ hasExternalStellarContext
56
63
 
57
64
  const useExternalWalletProvidersOnly =
58
65
  hasExternalProvider &&
@@ -71,6 +78,7 @@ export function useExternalWalletProvider(): ExternalWalletProvider {
71
78
  hasExternalBitcoinContext,
72
79
  hasExternalSuiContext,
73
80
  hasExternalTronContext,
81
+ hasExternalStellarContext,
74
82
  walletConfig?.usePartialWalletManagement,
75
83
  walletConfig?.forceInternalWalletManagement,
76
84
  ])
@@ -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
- <FormStoreProvider formRef={formRef}>
22
- <ChainOrderStoreProvider namePrefix={config?.keyPrefix}>
23
- <RouteExecutionStoreProvider namePrefix={config?.keyPrefix}>
24
- {children}
25
- </RouteExecutionStoreProvider>
26
- </ChainOrderStoreProvider>
27
- </FormStoreProvider>
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 && !configChainValue && !urlChainValue
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
- // If swap only, set the to chain to the from chain
103
+ // Copying an empty source would alternate with the fallback below.
94
104
  if (isSwapTo) {
95
105
  const [fromChainValue] = getFieldValues('fromChain')
96
- setFieldValue('toChain', fromChainValue)
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
- const [chainValue] = getFieldValues(`${key}Chain`)
108
- if (chainValue) {
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
+ }