@lifi/widget 4.8.0 → 4.9.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 (115) hide show
  1. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js +5 -2
  2. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -1
  3. package/dist/esm/components/SelectChainAndToken.js +5 -2
  4. package/dist/esm/components/SelectChainAndToken.js.map +1 -1
  5. package/dist/esm/components/SendToWallet/SendToWalletButton.js +5 -4
  6. package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
  7. package/dist/esm/components/TokenList/useTokenSelect.d.ts.map +1 -1
  8. package/dist/esm/components/TokenList/useTokenSelect.js +10 -0
  9. package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
  10. package/dist/esm/config/constants.js.map +1 -1
  11. package/dist/esm/config/version.d.ts +1 -1
  12. package/dist/esm/config/version.js +1 -1
  13. package/dist/esm/config/version.js.map +1 -1
  14. package/dist/esm/hooks/useAccountsBalancesData.js +5 -2
  15. package/dist/esm/hooks/useAccountsBalancesData.js.map +1 -1
  16. package/dist/esm/hooks/useAddressValidation.d.ts +3 -2
  17. package/dist/esm/hooks/useAddressValidation.d.ts.map +1 -1
  18. package/dist/esm/hooks/useAddressValidation.js +48 -21
  19. package/dist/esm/hooks/useAddressValidation.js.map +1 -1
  20. package/dist/esm/hooks/useGasRefuel.js +4 -1
  21. package/dist/esm/hooks/useGasRefuel.js.map +1 -1
  22. package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
  23. package/dist/esm/hooks/useRoutes.js +11 -6
  24. package/dist/esm/hooks/useRoutes.js.map +1 -1
  25. package/dist/esm/hooks/useToAddressAutoPopulate.js +6 -8
  26. package/dist/esm/hooks/useToAddressAutoPopulate.js.map +1 -1
  27. package/dist/esm/hooks/useToAddressRequirements.d.ts +3 -2
  28. package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
  29. package/dist/esm/hooks/useToAddressRequirements.js +8 -7
  30. package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
  31. package/dist/esm/hooks/useToAddressReset.js +6 -3
  32. package/dist/esm/hooks/useToAddressReset.js.map +1 -1
  33. package/dist/esm/hooks/useTokenBalance.js +2 -1
  34. package/dist/esm/hooks/useTokenBalance.js.map +1 -1
  35. package/dist/esm/hooks/useTokens.js +1 -1
  36. package/dist/esm/i18n/bn.json +2 -1
  37. package/dist/esm/i18n/de.json +2 -1
  38. package/dist/esm/i18n/en.json +2 -1
  39. package/dist/esm/i18n/es.json +2 -1
  40. package/dist/esm/i18n/fr.json +2 -1
  41. package/dist/esm/i18n/hi.json +2 -1
  42. package/dist/esm/i18n/id.json +2 -1
  43. package/dist/esm/i18n/it.json +2 -1
  44. package/dist/esm/i18n/ja.json +2 -1
  45. package/dist/esm/i18n/ko.json +2 -1
  46. package/dist/esm/i18n/pl.json +2 -1
  47. package/dist/esm/i18n/pt.json +2 -1
  48. package/dist/esm/i18n/th.json +2 -1
  49. package/dist/esm/i18n/tr.json +2 -1
  50. package/dist/esm/i18n/uk.json +2 -1
  51. package/dist/esm/i18n/vi.json +2 -1
  52. package/dist/esm/i18n/zh.json +2 -1
  53. package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js +7 -4
  54. package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js.map +1 -1
  55. package/dist/esm/pages/SendToWallet/BookmarksPage.js +35 -31
  56. package/dist/esm/pages/SendToWallet/BookmarksPage.js.map +1 -1
  57. package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js +4 -3
  58. package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js.map +1 -1
  59. package/dist/esm/pages/SendToWallet/RecentWalletsPage.js +43 -39
  60. package/dist/esm/pages/SendToWallet/RecentWalletsPage.js.map +1 -1
  61. package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js +32 -26
  62. package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js.map +1 -1
  63. package/dist/esm/pages/SendToWallet/SendToWalletPage.js +5 -10
  64. package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
  65. package/dist/esm/providers/WalletProvider/WalletProvider.d.ts.map +1 -1
  66. package/dist/esm/providers/WalletProvider/WalletProvider.js +14 -2
  67. package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
  68. package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
  69. package/dist/esm/providers/WidgetProvider/WidgetProvider.js +10 -14
  70. package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
  71. package/dist/esm/stores/bookmarks/types.d.ts +3 -0
  72. package/dist/esm/stores/bookmarks/types.d.ts.map +1 -1
  73. package/dist/esm/stores/chains/ChainOrderStore.d.ts.map +1 -1
  74. package/dist/esm/stores/chains/ChainOrderStore.js +4 -1
  75. package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
  76. package/dist/esm/stores/form/FormStore.js +3 -2
  77. package/dist/esm/stores/form/FormStore.js.map +1 -1
  78. package/dist/esm/stores/form/URLSearchParamsBuilder.js +7 -3
  79. package/dist/esm/stores/form/URLSearchParamsBuilder.js.map +1 -1
  80. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js +4 -1
  81. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js.map +1 -1
  82. package/dist/esm/utils/chainType.js +32 -1
  83. package/dist/esm/utils/chainType.js.map +1 -1
  84. package/dist/esm/utils/customReceiver.js +6 -1
  85. package/dist/esm/utils/customReceiver.js.map +1 -1
  86. package/package.json +7 -7
  87. package/src/components/AmountInputCard/AmountInputCardPair.tsx +6 -2
  88. package/src/components/SelectChainAndToken.tsx +5 -1
  89. package/src/components/SendToWallet/SendToWalletButton.tsx +13 -8
  90. package/src/components/TokenList/useTokenSelect.ts +15 -0
  91. package/src/config/constants.ts +3 -0
  92. package/src/config/version.ts +1 -1
  93. package/src/hooks/useAccountsBalancesData.ts +6 -2
  94. package/src/hooks/useAddressValidation.ts +87 -32
  95. package/src/hooks/useGasRefuel.ts +11 -1
  96. package/src/hooks/useRoutes.ts +23 -18
  97. package/src/hooks/useToAddressAutoPopulate.ts +13 -17
  98. package/src/hooks/useToAddressRequirements.ts +19 -4
  99. package/src/hooks/useToAddressReset.ts +13 -4
  100. package/src/hooks/useTokenBalance.ts +6 -1
  101. package/src/pages/SendToWallet/BookmarkAddressSheet.tsx +5 -1
  102. package/src/pages/SendToWallet/BookmarksPage.tsx +42 -52
  103. package/src/pages/SendToWallet/ConnectedWalletsPage.tsx +4 -14
  104. package/src/pages/SendToWallet/RecentWalletsPage.tsx +59 -66
  105. package/src/pages/SendToWallet/SendToConfiguredWalletPage.tsx +45 -50
  106. package/src/pages/SendToWallet/SendToWalletPage.tsx +4 -16
  107. package/src/providers/WalletProvider/WalletProvider.tsx +28 -3
  108. package/src/providers/WidgetProvider/WidgetProvider.tsx +20 -19
  109. package/src/stores/bookmarks/types.ts +3 -0
  110. package/src/stores/chains/ChainOrderStore.tsx +4 -1
  111. package/src/stores/form/FormStore.tsx +2 -0
  112. package/src/stores/form/URLSearchParamsBuilder.tsx +4 -2
  113. package/src/stores/form/getDefaultValuesFromQueryString.ts +19 -0
  114. package/src/utils/chainType.ts +73 -1
  115. package/src/utils/customReceiver.ts +36 -0
@@ -9,6 +9,7 @@ import { BottomSheet } from '../../components/BottomSheet/BottomSheet.js'
9
9
  import type { BottomSheetBase } from '../../components/BottomSheet/types.js'
10
10
  import { Input } from '../../components/Input.js'
11
11
  import { AlertMessage } from '../../components/Messages/AlertMessage.js'
12
+ import { addressInputMaxLength } from '../../config/constants.js'
12
13
  import { useAddressValidation } from '../../hooks/useAddressValidation.js'
13
14
  import type { Bookmark } from '../../stores/bookmarks/types.js'
14
15
  import { useBookmarkActions } from '../../stores/bookmarks/useBookmarkActions.js'
@@ -63,6 +64,7 @@ export const BookmarkAddressSheet = ({
63
64
  name: nameValue,
64
65
  address: validationResult.address,
65
66
  chainType: validationResult.chainType,
67
+ chainId: validationResult.chainId,
66
68
  }
67
69
  }
68
70
 
@@ -74,6 +76,7 @@ export const BookmarkAddressSheet = ({
74
76
  name: nameValue,
75
77
  address: validatedWallet.address,
76
78
  chainType: validatedWallet.chainType,
79
+ chainId: validatedWallet.chainId,
77
80
  }
78
81
  }
79
82
 
@@ -119,6 +122,7 @@ export const BookmarkAddressSheet = ({
119
122
  name: validatedBookmark.name,
120
123
  address: validatedBookmark.address,
121
124
  chainType: validatedBookmark.chainType,
125
+ chainId: validatedBookmark.chainId,
122
126
  })
123
127
  }
124
128
  }
@@ -198,7 +202,7 @@ export const BookmarkAddressSheet = ({
198
202
  context: 'long',
199
203
  })}
200
204
  maxRows={2}
201
- inputProps={{ maxLength: 128 }}
205
+ inputProps={{ maxLength: addressInputMaxLength }}
202
206
  multiline
203
207
  />
204
208
  </SendToWalletCard>
@@ -34,7 +34,7 @@ export const BookmarksPage = (): JSX.Element => {
34
34
  const listParentRef = useRef<HTMLUListElement | null>(null)
35
35
  const buttonRef = useRef<HTMLDivElement | null>(null)
36
36
  const { bookmarks } = useBookmarks()
37
- const { requiredToChainType } = useToAddressRequirements()
37
+ const { isValidReceiver } = useToAddressRequirements()
38
38
  const { addBookmark, removeBookmark, setSelectedBookmark } =
39
39
  useBookmarkActions()
40
40
  const navigate = useNavigate()
@@ -70,59 +70,49 @@ export const BookmarksPage = (): JSX.Element => {
70
70
  disablePadding
71
71
  sx={{ paddingTop: 1.5 }}
72
72
  >
73
- {bookmarks.map((bookmark) => (
74
- <ListItem key={bookmark.address} sx={{ position: 'relative' }}>
75
- <ListItemButton
76
- onClick={() => handleBookmarkSelected(bookmark)}
77
- disabled={
78
- requiredToChainType &&
79
- requiredToChainType !== bookmark.chainType
80
- }
81
- >
82
- <ListItemAvatar>
83
- <AccountAvatar
84
- chainId={defaultChainIdsByType[bookmark.chainType]}
73
+ {bookmarks.map((bookmark) => {
74
+ const disabled = !isValidReceiver(bookmark.address)
75
+ const chainId =
76
+ bookmark.chainId ?? defaultChainIdsByType[bookmark.chainType]
77
+ return (
78
+ <ListItem key={bookmark.address} sx={{ position: 'relative' }}>
79
+ <ListItemButton
80
+ onClick={() => handleBookmarkSelected(bookmark)}
81
+ disabled={disabled}
82
+ >
83
+ <ListItemAvatar>
84
+ <AccountAvatar chainId={chainId} />
85
+ </ListItemAvatar>
86
+ <ListItemText
87
+ primary={bookmark.name}
88
+ secondary={shortenAddress(bookmark.address)}
85
89
  />
86
- </ListItemAvatar>
87
- <ListItemText
88
- primary={bookmark.name}
89
- secondary={shortenAddress(bookmark.address)}
90
+ </ListItemButton>
91
+ <ContextMenu
92
+ disabled={disabled}
93
+ items={[
94
+ {
95
+ icon: <ContentCopyRounded />,
96
+ label: t('button.copyAddress'),
97
+ onClick: () =>
98
+ navigator.clipboard.writeText(bookmark.address),
99
+ },
100
+ {
101
+ icon: <OpenInNewRounded />,
102
+ label: t('button.viewOnExplorer'),
103
+ onClick: () =>
104
+ openInNewTab(getAddressLink(bookmark.address, chainId)),
105
+ },
106
+ {
107
+ icon: <DeleteOutline />,
108
+ label: t('button.delete'),
109
+ onClick: () => removeBookmark(bookmark.address),
110
+ },
111
+ ]}
90
112
  />
91
- </ListItemButton>
92
- <ContextMenu
93
- disabled={
94
- !!(
95
- requiredToChainType &&
96
- requiredToChainType !== bookmark.chainType
97
- )
98
- }
99
- items={[
100
- {
101
- icon: <ContentCopyRounded />,
102
- label: t('button.copyAddress'),
103
- onClick: () =>
104
- navigator.clipboard.writeText(bookmark.address),
105
- },
106
- {
107
- icon: <OpenInNewRounded />,
108
- label: t('button.viewOnExplorer'),
109
- onClick: () =>
110
- openInNewTab(
111
- getAddressLink(
112
- bookmark.address,
113
- defaultChainIdsByType[bookmark.chainType]
114
- )
115
- ),
116
- },
117
- {
118
- icon: <DeleteOutline />,
119
- label: t('button.delete'),
120
- onClick: () => removeBookmark(bookmark.address),
121
- },
122
- ]}
123
- />
124
- </ListItem>
125
- ))}
113
+ </ListItem>
114
+ )
115
+ })}
126
116
  {!bookmarks.length && (
127
117
  <EmptyListIndicator
128
118
  icon={<TurnedIn />}
@@ -27,7 +27,7 @@ export const ConnectedWalletsPage = (): JSX.Element => {
27
27
  const { t } = useTranslation()
28
28
  const { accounts } = useAccount()
29
29
  const { setSelectedBookmark } = useBookmarkActions()
30
- const { requiredToChainType } = useToAddressRequirements()
30
+ const { isValidReceiver } = useToAddressRequirements()
31
31
  const navigate = useNavigate()
32
32
  const { setFieldValue } = useFieldActions()
33
33
  const { getAddressLink } = useExplorer()
@@ -91,15 +91,13 @@ export const ConnectedWalletsPage = (): JSX.Element => {
91
91
  ]
92
92
  : []),
93
93
  ]
94
+ const disabled = !isValidReceiver(account.address)
94
95
 
95
96
  return (
96
97
  <ListItem key={account.address} sx={{ position: 'relative' }}>
97
98
  <ListItemButton
98
99
  onClick={() => handleWalletSelected(account)}
99
- disabled={
100
- requiredToChainType &&
101
- requiredToChainType !== account.chainType
102
- }
100
+ disabled={disabled}
103
101
  >
104
102
  <ListItemAvatar>
105
103
  <AccountAvatar chainId={account.chainId} account={account} />
@@ -109,15 +107,7 @@ export const ConnectedWalletsPage = (): JSX.Element => {
109
107
  secondary={walletAddress}
110
108
  />
111
109
  </ListItemButton>
112
- <ContextMenu
113
- items={menuItems}
114
- disabled={
115
- !!(
116
- requiredToChainType &&
117
- requiredToChainType !== account.chainType
118
- )
119
- }
120
- />
110
+ <ContextMenu items={menuItems} disabled={disabled} />
121
111
  </ListItem>
122
112
  )
123
113
  })}
@@ -35,7 +35,7 @@ export const RecentWalletsPage = (): JSX.Element => {
35
35
  const bookmarkAddressSheetRef = useRef<BottomSheetBase>(null)
36
36
  const listParentRef = useRef<HTMLUListElement | null>(null)
37
37
  const { recentWallets } = useBookmarks()
38
- const { requiredToChainType } = useToAddressRequirements()
38
+ const { isValidReceiver } = useToAddressRequirements()
39
39
  const {
40
40
  removeRecentWallet,
41
41
  addBookmark,
@@ -76,73 +76,66 @@ export const RecentWalletsPage = (): JSX.Element => {
76
76
  disablePadding
77
77
  sx={{ paddingTop: 1.5 }}
78
78
  >
79
- {recentWallets.map((recentWallet) => (
80
- <ListItem key={recentWallet.address} sx={{ position: 'relative' }}>
81
- <ListItemButton
82
- disabled={
83
- requiredToChainType &&
84
- requiredToChainType !== recentWallet.chainType
85
- }
86
- onClick={() => handleRecentSelected(recentWallet)}
87
- >
88
- <ListItemAvatar>
89
- <AccountAvatar
90
- chainId={defaultChainIdsByType[recentWallet.chainType]}
79
+ {recentWallets.map((recentWallet) => {
80
+ const disabled = !isValidReceiver(recentWallet.address)
81
+ const chainId =
82
+ recentWallet.chainId ??
83
+ defaultChainIdsByType[recentWallet.chainType]
84
+ return (
85
+ <ListItem key={recentWallet.address} sx={{ position: 'relative' }}>
86
+ <ListItemButton
87
+ disabled={disabled}
88
+ onClick={() => handleRecentSelected(recentWallet)}
89
+ >
90
+ <ListItemAvatar>
91
+ <AccountAvatar chainId={chainId} />
92
+ </ListItemAvatar>
93
+ <ListItemText
94
+ primary={
95
+ recentWallet.name || shortenAddress(recentWallet.address)
96
+ }
97
+ secondary={
98
+ recentWallet.name
99
+ ? shortenAddress(recentWallet.address)
100
+ : undefined
101
+ }
91
102
  />
92
- </ListItemAvatar>
93
- <ListItemText
94
- primary={
95
- recentWallet.name || shortenAddress(recentWallet.address)
96
- }
97
- secondary={
98
- recentWallet.name
99
- ? shortenAddress(recentWallet.address)
100
- : undefined
101
- }
102
- />
103
- </ListItemButton>
104
- <ContextMenu
105
- disabled={
106
- !!(
107
- requiredToChainType &&
108
- requiredToChainType !== recentWallet.chainType
109
- )
110
- }
111
- items={[
112
- {
113
- icon: <ContentCopyRounded />,
114
- label: t('button.copyAddress'),
115
- onClick: () =>
116
- navigator.clipboard.writeText(recentWallet.address),
117
- },
118
- {
119
- icon: <OpenInNewRounded />,
120
- label: t('button.viewOnExplorer'),
121
- onClick: () =>
122
- openInNewTab(
123
- getAddressLink(
124
- recentWallet.address,
125
- defaultChainIdsByType[recentWallet.chainType]
126
- )
127
- ),
128
- },
129
- {
130
- icon: <TurnedInNot />,
131
- label: t('button.bookmark'),
132
- onClick: () => {
133
- setBookmarkTarget(recentWallet)
134
- bookmarkAddressSheetRef.current?.open()
103
+ </ListItemButton>
104
+ <ContextMenu
105
+ disabled={disabled}
106
+ items={[
107
+ {
108
+ icon: <ContentCopyRounded />,
109
+ label: t('button.copyAddress'),
110
+ onClick: () =>
111
+ navigator.clipboard.writeText(recentWallet.address),
112
+ },
113
+ {
114
+ icon: <OpenInNewRounded />,
115
+ label: t('button.viewOnExplorer'),
116
+ onClick: () =>
117
+ openInNewTab(
118
+ getAddressLink(recentWallet.address, chainId)
119
+ ),
120
+ },
121
+ {
122
+ icon: <TurnedInNot />,
123
+ label: t('button.bookmark'),
124
+ onClick: () => {
125
+ setBookmarkTarget(recentWallet)
126
+ bookmarkAddressSheetRef.current?.open()
127
+ },
135
128
  },
136
- },
137
- {
138
- icon: <DeleteOutline />,
139
- label: t('button.delete'),
140
- onClick: () => removeRecentWallet(recentWallet.address),
141
- },
142
- ]}
143
- />
144
- </ListItem>
145
- ))}
129
+ {
130
+ icon: <DeleteOutline />,
131
+ label: t('button.delete'),
132
+ onClick: () => removeRecentWallet(recentWallet.address),
133
+ },
134
+ ]}
135
+ />
136
+ </ListItem>
137
+ )
138
+ })}
146
139
  {!recentWallets.length && (
147
140
  <EmptyListIndicator
148
141
  icon={<AccountBalanceWalletIcon />}
@@ -1,3 +1,4 @@
1
+ import { useChainTypeFromAddress } from '@lifi/widget-provider'
1
2
  import ContentCopyRounded from '@mui/icons-material/ContentCopyRounded'
2
3
  import OpenInNewRounded from '@mui/icons-material/OpenInNewRounded'
3
4
  import { List, ListItemAvatar, ListItemText } from '@mui/material'
@@ -25,7 +26,8 @@ export const SendToConfiguredWalletPage = (): JSX.Element => {
25
26
  const { t } = useTranslation()
26
27
  const navigateBack = useNavigateBack()
27
28
  const { toAddresses } = useWidgetConfig()
28
- const { requiredToChainType } = useToAddressRequirements()
29
+ const { isValidReceiver } = useToAddressRequirements()
30
+ const { getChainFromAddress } = useChainTypeFromAddress()
29
31
  const { setSelectedBookmark } = useBookmarkActions()
30
32
  const { setFieldValue } = useFieldActions()
31
33
  const { getAddressLink } = useExplorer()
@@ -53,57 +55,50 @@ export const SendToConfiguredWalletPage = (): JSX.Element => {
53
55
  disablePadding
54
56
  sx={{ paddingTop: 1.5 }}
55
57
  >
56
- {toAddresses?.map((toAddress) => (
57
- <ListItem key={toAddress.address} sx={{ position: 'relative' }}>
58
- <ListItemButton
59
- disabled={
60
- requiredToChainType &&
61
- requiredToChainType !== toAddress.chainType
62
- }
63
- onClick={() => handleCuratedSelected(toAddress)}
64
- >
65
- <ListItemAvatar>
66
- <AccountAvatar
67
- chainId={defaultChainIdsByType[toAddress.chainType]}
68
- toAddress={toAddress}
58
+ {toAddresses?.map((toAddress) => {
59
+ const disabled = !isValidReceiver(toAddress.address)
60
+ // A configured receiver has no chainId; its provider knows the chain.
61
+ const chainId =
62
+ getChainFromAddress(toAddress.address)?.chainId ??
63
+ defaultChainIdsByType[toAddress.chainType]
64
+ return (
65
+ <ListItem key={toAddress.address} sx={{ position: 'relative' }}>
66
+ <ListItemButton
67
+ disabled={disabled}
68
+ onClick={() => handleCuratedSelected(toAddress)}
69
+ >
70
+ <ListItemAvatar>
71
+ <AccountAvatar chainId={chainId} toAddress={toAddress} />
72
+ </ListItemAvatar>
73
+ <ListItemText
74
+ primary={toAddress.name || shortenAddress(toAddress.address)}
75
+ secondary={
76
+ toAddress.name
77
+ ? shortenAddress(toAddress.address)
78
+ : undefined
79
+ }
69
80
  />
70
- </ListItemAvatar>
71
- <ListItemText
72
- primary={toAddress.name || shortenAddress(toAddress.address)}
73
- secondary={
74
- toAddress.name ? shortenAddress(toAddress.address) : undefined
75
- }
81
+ </ListItemButton>
82
+ <ContextMenu
83
+ disabled={disabled}
84
+ items={[
85
+ {
86
+ icon: <ContentCopyRounded />,
87
+ label: t('button.copyAddress'),
88
+ onClick: () =>
89
+ navigator.clipboard.writeText(toAddress.address),
90
+ },
91
+ {
92
+ icon: <OpenInNewRounded />,
93
+ label: t('button.viewOnExplorer'),
94
+ onClick: () =>
95
+ openInNewTab(getAddressLink(toAddress.address, chainId)),
96
+ },
97
+ ]}
76
98
  />
77
- </ListItemButton>
78
- <ContextMenu
79
- disabled={
80
- !!(
81
- requiredToChainType &&
82
- requiredToChainType !== toAddress.chainType
83
- )
84
- }
85
- items={[
86
- {
87
- icon: <ContentCopyRounded />,
88
- label: t('button.copyAddress'),
89
- onClick: () =>
90
- navigator.clipboard.writeText(toAddress.address),
91
- },
92
- {
93
- icon: <OpenInNewRounded />,
94
- label: t('button.viewOnExplorer'),
95
- onClick: () =>
96
- openInNewTab(
97
- getAddressLink(
98
- toAddress.address,
99
- defaultChainIdsByType[toAddress.chainType]
100
- )
101
- ),
102
- },
103
- ]}
104
- />
105
- </ListItem>
106
- ))}
99
+ </ListItem>
100
+ )
101
+ })}
107
102
  </List>
108
103
  </PageContainer>
109
104
  )
@@ -12,13 +12,13 @@ import type { BottomSheetBase } from '../../components/BottomSheet/types.js'
12
12
  import { ButtonTertiary } from '../../components/ButtonTertiary.js'
13
13
  import { CardButton } from '../../components/Card/CardButton.js'
14
14
  import { AccountDeployedMessage } from '../../components/Messages/AccountDeployedMessage.js'
15
+ import { addressInputMaxLength } from '../../config/constants.js'
15
16
  import {
16
17
  AddressType,
17
18
  useAddressValidation,
18
19
  } from '../../hooks/useAddressValidation.js'
19
20
  import { useChain } from '../../hooks/useChain.js'
20
21
  import { useHeader } from '../../hooks/useHeader.js'
21
- import { useToAddressRequirements } from '../../hooks/useToAddressRequirements.js'
22
22
  import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
23
23
  import type { Bookmark } from '../../stores/bookmarks/types.js'
24
24
  import { useBookmarkActions } from '../../stores/bookmarks/useBookmarkActions.js'
@@ -57,7 +57,6 @@ export const SendToWalletPage: React.FC = () => {
57
57
  const [validatedWallet, setValidatedWallet] = useState<Bookmark>()
58
58
  const [errorMessage, setErrorMessage] = useState('')
59
59
  const { validateAddress, isValidating } = useAddressValidation()
60
- const { requiredToChainType } = useToAddressRequirements()
61
60
  const [toChainId] = useFieldValues('toChain')
62
61
  const { chain: toChain } = useChain(toChainId)
63
62
  const [isDoneButtonLoading, setIsDoneButtonLoading] = useState(false)
@@ -91,7 +90,6 @@ export const SendToWalletPage: React.FC = () => {
91
90
  setIsDoneButtonLoading(true)
92
91
  const validationResult = await validateAddress({
93
92
  value: inputAddressValue,
94
- chainType: requiredToChainType,
95
93
  chain: toChain,
96
94
  })
97
95
  setIsDoneButtonLoading(false)
@@ -100,18 +98,6 @@ export const SendToWalletPage: React.FC = () => {
100
98
  return
101
99
  }
102
100
 
103
- if (
104
- requiredToChainType &&
105
- requiredToChainType !== validationResult.chainType
106
- ) {
107
- setErrorMessage(
108
- t('error.title.walletChainTypeInvalid', {
109
- chainName: toChain?.name,
110
- })
111
- )
112
- return
113
- }
114
-
115
101
  setValidatedWallet({
116
102
  name:
117
103
  validationResult.addressType === AddressType.NameService
@@ -119,6 +105,7 @@ export const SendToWalletPage: React.FC = () => {
119
105
  : undefined,
120
106
  address: validationResult.address,
121
107
  chainType: validationResult.chainType,
108
+ chainId: validationResult.chainId,
122
109
  })
123
110
  confirmAddressSheetRef.current?.open()
124
111
  }
@@ -155,6 +142,7 @@ export const SendToWalletPage: React.FC = () => {
155
142
  : undefined,
156
143
  address: validationResult.address,
157
144
  chainType: validationResult.chainType,
145
+ chainId: validationResult.chainId,
158
146
  })
159
147
  bookmarkAddressSheetRef.current?.open()
160
148
  } else {
@@ -213,7 +201,7 @@ export const SendToWalletPage: React.FC = () => {
213
201
  placeholder={placeholder}
214
202
  aria-label={placeholder}
215
203
  maxRows={2}
216
- inputProps={{ maxLength: 128 }}
204
+ inputProps={{ maxLength: addressInputMaxLength }}
217
205
  multiline
218
206
  />
219
207
  {errorMessage ? (
@@ -1,5 +1,8 @@
1
1
  import { WalletManagementProviders } from '@lifi/wallet-management'
2
- import type { WidgetProviderProps } from '@lifi/widget-provider'
2
+ import {
3
+ useSDKProviders,
4
+ type WidgetProviderProps,
5
+ } from '@lifi/widget-provider'
3
6
  import {
4
7
  type FC,
5
8
  type JSX,
@@ -10,8 +13,15 @@ import {
10
13
  import { useTranslation } from 'react-i18next'
11
14
  import { useAvailableChains } from '../../hooks/useAvailableChains.js'
12
15
  import { useInitializeSDKProviders } from '../../hooks/useInitializeSDKProviders.js'
16
+ import {
17
+ withoutUnservedToChain,
18
+ withServedDestinationChains,
19
+ } from '../../utils/chainType.js'
13
20
  import { getConfigItemSets, isItemAllowedForSets } from '../../utils/item.js'
14
- import { useWidgetConfig } from '../WidgetProvider/WidgetProvider.js'
21
+ import {
22
+ useWidgetConfig,
23
+ WidgetContext,
24
+ } from '../WidgetProvider/WidgetProvider.js'
15
25
  import { useExternalWalletProvider } from './useExternalWalletProvider.js'
16
26
 
17
27
  interface WalletProviderProps extends PropsWithChildren {
@@ -78,5 +88,20 @@ export const WalletProvider = ({
78
88
 
79
89
  const SDKProviderInitializer: FC<PropsWithChildren> = ({ children }) => {
80
90
  useInitializeSDKProviders()
81
- return children
91
+ const config = useWidgetConfig()
92
+ const sdkProviders = useSDKProviders()
93
+ // Only below the provider components is it known which chains are served.
94
+ // Keyed on `config.chains`: the config object is new on every render.
95
+ const chains = useMemo(
96
+ () => withServedDestinationChains(config.chains, sdkProviders),
97
+ [config.chains, sdkProviders]
98
+ )
99
+ const value = useMemo(
100
+ () =>
101
+ withoutUnservedToChain(
102
+ chains === config.chains ? config : { ...config, chains }
103
+ ),
104
+ [config, chains]
105
+ )
106
+ return <WidgetContext value={value}>{children}</WidgetContext>
82
107
  }
@@ -1,6 +1,10 @@
1
1
  import type { Context } from 'react'
2
2
  import { createContext, use, useId, useMemo } from 'react'
3
3
  import { useSettingsActions } from '../../stores/settings/useSettingsActions.js'
4
+ import {
5
+ isDestinationOnlyChain,
6
+ withDestinationOnlyChains,
7
+ } from '../../utils/chainType.js'
4
8
  import {
5
9
  defaultQueryScopeKey,
6
10
  resolveQueryScopeKey,
@@ -29,33 +33,30 @@ export const WidgetProvider: React.FC<
29
33
  throw new Error('Required property "integrator" is missing.')
30
34
  }
31
35
 
36
+ // Keyed on the integrator's `chains`: the config object is new on every render.
37
+ const chains = useMemo(
38
+ () => withDestinationOnlyChains(widgetConfig.chains),
39
+ [widgetConfig.chains]
40
+ )
41
+
32
42
  const value = useMemo((): WidgetContextProps => {
33
- // Resolved once, so nothing below reads the deprecated keyPrefix.
34
- const scopeKeys = {
43
+ // Omitted, not undefined: an own undefined key resets the form field.
44
+ const { fromChain, fromToken, ...config } = widgetConfig
45
+ const value = {
46
+ ...(isDestinationOnlyChain(fromChain) ? config : widgetConfig),
47
+ chains,
48
+ // Resolved once, so nothing below reads the deprecated keyPrefix.
35
49
  storageScopeKey: resolveStorageScopeKey(widgetConfig),
36
50
  queryScopeKey: resolveQueryScopeKey(widgetConfig),
37
- }
51
+ elementId,
52
+ } as WidgetContextProps
38
53
  try {
39
- // Create widget configuration object
40
- const value = {
41
- ...widgetConfig,
42
- ...scopeKeys,
43
- elementId,
44
- } as WidgetContextProps
45
-
46
54
  // Set default settings for widget settings store
47
55
  setDefaultSettings(value)
48
-
49
- return value
50
56
  } catch (e) {
51
57
  console.warn(e)
52
- return {
53
- ...widgetConfig,
54
- ...scopeKeys,
55
- elementId,
56
- integrator: widgetConfig.integrator,
57
- }
58
58
  }
59
- }, [elementId, widgetConfig, setDefaultSettings])
59
+ return value
60
+ }, [elementId, widgetConfig, chains, setDefaultSettings])
60
61
  return <WidgetContext value={value}>{children}</WidgetContext>
61
62
  }
@@ -1,8 +1,11 @@
1
+ import type { ChainId } from '@lifi/sdk'
1
2
  import type { StoreApi, UseBoundStore } from 'zustand'
2
3
  import type { ToAddress } from '../../types/widget.js'
3
4
 
4
5
  export interface Bookmark extends ToAddress {
5
6
  isConnectedAccount?: boolean
7
+ /** Display only: set when the ecosystem's default chain rejects the address. */
8
+ chainId?: ChainId
6
9
  }
7
10
 
8
11
  export interface BookmarkProps {
@@ -80,7 +80,10 @@ export function ChainOrderStoreProvider({
80
80
 
81
81
  // Initialize the isAllNetworks with true if the tab is shown,
82
82
  // there is no config chain value and no url chain value
83
- const urlValues = getDefaultValuesFromQueryString({ buildUrl })
83
+ const urlValues = getDefaultValuesFromQueryString({
84
+ buildUrl,
85
+ chains: chainsConfig,
86
+ })
84
87
  const urlChainValue =
85
88
  key === 'from' ? urlValues.fromChain : urlValues.toChain
86
89
  const configChainValue =