@lifi/widget 4.9.0 → 4.10.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 +28 -10
- package/dist/esm/components/TokenList/TokenDetailsSheet.js +5 -8
- package/dist/esm/components/TokenList/TokenDetailsSheet.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +30 -2
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +36 -47
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js +2 -2
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/components/TokenList/tokenVerificationIcons.js +29 -0
- package/dist/esm/components/TokenList/tokenVerificationIcons.js.map +1 -0
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/usePacedValue.js +1 -1
- package/dist/esm/hooks/usePacedValue.js.map +1 -1
- package/dist/esm/hooks/useRouteExecutionMessage.d.ts.map +1 -1
- package/dist/esm/hooks/useRouteExecutionMessage.js +4 -8
- package/dist/esm/hooks/useRouteExecutionMessage.js.map +1 -1
- package/dist/esm/i18n/bn.json +567 -266
- package/dist/esm/i18n/de.json +552 -251
- package/dist/esm/i18n/en.json +12 -62
- package/dist/esm/i18n/es.json +522 -221
- package/dist/esm/i18n/fr.json +541 -240
- package/dist/esm/i18n/hi.json +592 -291
- package/dist/esm/i18n/id.json +485 -184
- package/dist/esm/i18n/it.json +546 -245
- package/dist/esm/i18n/ja.json +512 -211
- package/dist/esm/i18n/ko.json +553 -252
- package/dist/esm/i18n/pl.json +598 -297
- package/dist/esm/i18n/pt.json +513 -212
- package/dist/esm/i18n/th.json +554 -253
- package/dist/esm/i18n/tr.json +538 -237
- package/dist/esm/i18n/uk.json +514 -213
- package/dist/esm/i18n/vi.json +550 -249
- package/dist/esm/i18n/zh.json +528 -227
- package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js +70 -18
- package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
- package/dist/esm/pages/TransactionPage/utils.d.ts +3 -0
- package/dist/esm/pages/TransactionPage/utils.d.ts.map +1 -1
- package/dist/esm/pages/TransactionPage/utils.js +27 -1
- package/dist/esm/pages/TransactionPage/utils.js.map +1 -1
- package/dist/esm/shared.d.ts +2 -2
- package/dist/esm/shared.js +2 -2
- package/dist/esm/stores/routes/utils.d.ts +1 -1
- package/dist/esm/stores/routes/utils.d.ts.map +1 -1
- package/dist/esm/stores/routes/utils.js +13 -1
- package/dist/esm/stores/routes/utils.js.map +1 -1
- package/dist/esm/utils/getErrorMessage.js +4 -0
- package/dist/esm/utils/getErrorMessage.js.map +1 -1
- package/dist/esm/utils/token.js +13 -1
- package/dist/esm/utils/token.js.map +1 -1
- package/package.json +4 -4
- package/src/components/TokenList/TokenDetailsSheet.tsx +5 -9
- package/src/components/TokenList/TokenDetailsSheetContent.tsx +46 -4
- package/src/components/TokenList/TokenListItem.tsx +44 -68
- package/src/components/TokenList/VirtualizedTokenList.tsx +3 -6
- package/src/components/TokenList/tokenVerificationIcons.ts +15 -0
- package/src/components/TokenList/types.ts +3 -11
- package/src/config/version.ts +1 -1
- package/src/hooks/usePacedValue.ts +1 -1
- package/src/hooks/useRouteExecutionMessage.ts +10 -13
- package/src/pages/TransactionPage/TransactionFailedButtons.test.tsx +497 -0
- package/src/pages/TransactionPage/TransactionFailedButtons.tsx +78 -9
- package/src/pages/TransactionPage/utils.ts +81 -0
- package/src/shared.ts +1 -0
- package/src/stores/routes/utils.ts +24 -1
- package/src/utils/getErrorMessage.ts +5 -0
- package/src/utils/token.ts +48 -0
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { LiFiErrorCode, type RouteExtended } from '@lifi/sdk'
|
|
2
|
+
import { getFailedStepAction } from '../../stores/routes/utils.js'
|
|
3
|
+
import type { WidgetMode } from '../../types/widget.js'
|
|
4
|
+
import { formatTokenAmount } from '../../utils/format.js'
|
|
5
|
+
|
|
1
6
|
export const calculateValueLossPercentage = (
|
|
2
7
|
fromAmountUSD: number,
|
|
3
8
|
toAmountUSD: number,
|
|
@@ -101,3 +106,79 @@ export const getStartGates = (
|
|
|
101
106
|
['address', needsAddressConfirmation(input)],
|
|
102
107
|
['value', input.valueLossExceeded && !input.isCustomMode],
|
|
103
108
|
]
|
|
109
|
+
|
|
110
|
+
// Only these modes show the plain from/to swap form.
|
|
111
|
+
const newSwapModes: readonly (WidgetMode | undefined)[] = [
|
|
112
|
+
undefined,
|
|
113
|
+
'default',
|
|
114
|
+
'split',
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
export const isCallBundleNotFound = (route: RouteExtended): boolean =>
|
|
118
|
+
getFailedStepAction(route)?.action.error?.code ===
|
|
119
|
+
LiFiErrorCode.CallBundleNotFound
|
|
120
|
+
|
|
121
|
+
// A new swap repeats the whole route.
|
|
122
|
+
export const canStartNewSwap = ({
|
|
123
|
+
route,
|
|
124
|
+
mode,
|
|
125
|
+
swapOnly,
|
|
126
|
+
}: {
|
|
127
|
+
route: RouteExtended
|
|
128
|
+
mode: WidgetMode | undefined
|
|
129
|
+
swapOnly: boolean
|
|
130
|
+
}): boolean => {
|
|
131
|
+
const failed = getFailedStepAction(route)
|
|
132
|
+
if (!failed || !isCallBundleNotFound(route)) {
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
return (
|
|
136
|
+
failed.step === route.steps[0] &&
|
|
137
|
+
route.steps.every(
|
|
138
|
+
(step) => step === failed.step || !step.execution?.actions?.length
|
|
139
|
+
) &&
|
|
140
|
+
newSwapModes.includes(mode) &&
|
|
141
|
+
// A swap-only form requests no bridges.
|
|
142
|
+
!(swapOnly && route.fromChainId !== route.toChainId)
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface NewSwapFormValues {
|
|
147
|
+
fromChain: number
|
|
148
|
+
fromToken: string
|
|
149
|
+
fromAmount: string
|
|
150
|
+
toChain: number
|
|
151
|
+
toToken: string
|
|
152
|
+
toAddress?: string
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const getNewSwapFormValues = (
|
|
156
|
+
route: RouteExtended,
|
|
157
|
+
{
|
|
158
|
+
keepReceiver = false,
|
|
159
|
+
receiverRequired = false,
|
|
160
|
+
}: { keepReceiver?: boolean; receiverRequired?: boolean } = {}
|
|
161
|
+
): NewSwapFormValues => {
|
|
162
|
+
const receiver = route.toAddress || route.fromAddress
|
|
163
|
+
const values: NewSwapFormValues = {
|
|
164
|
+
fromChain: route.fromChainId,
|
|
165
|
+
fromToken: route.fromToken.address,
|
|
166
|
+
// The quote's amount, not a step amount trimmed to the balance: the new quote checks it.
|
|
167
|
+
fromAmount: formatTokenAmount(
|
|
168
|
+
BigInt(route.fromAmount),
|
|
169
|
+
route.fromToken.decimals
|
|
170
|
+
),
|
|
171
|
+
toChain: route.toChainId,
|
|
172
|
+
toToken: route.toToken.address,
|
|
173
|
+
}
|
|
174
|
+
if (!keepReceiver) {
|
|
175
|
+
// A required receiver stays, also when it is the sender.
|
|
176
|
+
values.toAddress =
|
|
177
|
+
receiver &&
|
|
178
|
+
(receiverRequired ||
|
|
179
|
+
receiver.toLowerCase() !== route.fromAddress?.toLowerCase())
|
|
180
|
+
? receiver
|
|
181
|
+
: ''
|
|
182
|
+
}
|
|
183
|
+
return values
|
|
184
|
+
}
|
package/src/shared.ts
CHANGED
|
@@ -114,6 +114,7 @@ export { TransactionDoneButtons } from './pages/TransactionPage/TransactionDoneB
|
|
|
114
114
|
export {
|
|
115
115
|
calculateValueLossPercentage,
|
|
116
116
|
getTokenValueLossThreshold,
|
|
117
|
+
isCallBundleNotFound,
|
|
117
118
|
} from './pages/TransactionPage/utils.js'
|
|
118
119
|
|
|
119
120
|
// ── providers ────────────────────────────────────────────────────────────────
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ExecutionAction,
|
|
3
|
+
ExecutionActionType,
|
|
4
|
+
LiFiStepExtended,
|
|
5
|
+
RouteExtended,
|
|
6
|
+
} from '@lifi/sdk'
|
|
2
7
|
import microdiff from 'microdiff'
|
|
3
8
|
|
|
4
9
|
export const isRouteDone = (route: RouteExtended): boolean => {
|
|
@@ -21,6 +26,24 @@ export const isRouteFailed = (route: RouteExtended): boolean => {
|
|
|
21
26
|
return route.steps.some((step) => step.execution?.status === 'FAILED')
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
// A step can fail before any action, so its own error then stands in.
|
|
30
|
+
export const getFailedStepAction = (
|
|
31
|
+
route: RouteExtended
|
|
32
|
+
): { step: LiFiStepExtended; action: ExecutionAction } | undefined => {
|
|
33
|
+
const step = route.steps.find((step) => step.execution?.status === 'FAILED')
|
|
34
|
+
if (!step) {
|
|
35
|
+
return undefined
|
|
36
|
+
}
|
|
37
|
+
const action = step.execution?.actions?.find(
|
|
38
|
+
(action) => action.status === 'FAILED'
|
|
39
|
+
) || {
|
|
40
|
+
status: 'FAILED',
|
|
41
|
+
type: 'EXECUTION' as ExecutionActionType,
|
|
42
|
+
error: step.execution?.error,
|
|
43
|
+
}
|
|
44
|
+
return { step, action }
|
|
45
|
+
}
|
|
46
|
+
|
|
24
47
|
export const isRouteActive = (route?: RouteExtended): boolean => {
|
|
25
48
|
if (!route) {
|
|
26
49
|
return false
|
|
@@ -130,6 +130,11 @@ export function getErrorMessage(
|
|
|
130
130
|
chainName: getChainById(step.action.fromChainId)?.name ?? '',
|
|
131
131
|
})
|
|
132
132
|
break
|
|
133
|
+
// No "remain in your wallet" suffix: the funds may already be gone.
|
|
134
|
+
case LiFiErrorCode.CallBundleNotFound:
|
|
135
|
+
title = t('error.title.callBundleNotFound')
|
|
136
|
+
message = t('error.message.callBundleNotFound')
|
|
137
|
+
break
|
|
133
138
|
default:
|
|
134
139
|
title = t('error.title.unknown')
|
|
135
140
|
if (failedAction?.txHash) {
|
package/src/utils/token.ts
CHANGED
|
@@ -280,6 +280,54 @@ export const getTokenVerificationProvider = (
|
|
|
280
280
|
: undefined
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
export type TokenVerificationBadge =
|
|
284
|
+
| 'native'
|
|
285
|
+
| 'flagged'
|
|
286
|
+
| 'verified'
|
|
287
|
+
| 'unverifiedByProvider'
|
|
288
|
+
| 'unverified'
|
|
289
|
+
|
|
290
|
+
export const getTokenVerificationBadge = (
|
|
291
|
+
token: Pick<
|
|
292
|
+
TokenWithFlags,
|
|
293
|
+
'native' | 'listed' | 'verified' | 'verificationStatus'
|
|
294
|
+
>
|
|
295
|
+
): TokenVerificationBadge | undefined => {
|
|
296
|
+
// The provider calls the native-address convention a scam on some chains.
|
|
297
|
+
if (token.native) {
|
|
298
|
+
return 'native'
|
|
299
|
+
}
|
|
300
|
+
if (token.verificationStatus === 'flagged') {
|
|
301
|
+
return 'flagged'
|
|
302
|
+
}
|
|
303
|
+
if (token.verificationStatus === 'verified') {
|
|
304
|
+
return 'verified'
|
|
305
|
+
}
|
|
306
|
+
if (token.listed || token.verified) {
|
|
307
|
+
return undefined
|
|
308
|
+
}
|
|
309
|
+
return token.verificationStatus === 'unverified'
|
|
310
|
+
? 'unverifiedByProvider'
|
|
311
|
+
: 'unverified'
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export type TokenStatusTextKey =
|
|
315
|
+
| 'tokenMetric.statusVerified'
|
|
316
|
+
| 'tokenMetric.statusFlagged'
|
|
317
|
+
| 'tokenMetric.statusUnverified'
|
|
318
|
+
|
|
319
|
+
export const getTokenStatusTextKey = (
|
|
320
|
+
token: Pick<TokenWithFlags, 'native' | 'verificationStatus'>
|
|
321
|
+
): TokenStatusTextKey => {
|
|
322
|
+
if (token.verificationStatus === 'verified') {
|
|
323
|
+
return 'tokenMetric.statusVerified'
|
|
324
|
+
}
|
|
325
|
+
if (token.verificationStatus === 'flagged' && !token.native) {
|
|
326
|
+
return 'tokenMetric.statusFlagged'
|
|
327
|
+
}
|
|
328
|
+
return 'tokenMetric.statusUnverified'
|
|
329
|
+
}
|
|
330
|
+
|
|
283
331
|
/**
|
|
284
332
|
* Hyperliquid declares Arbitrum USDC as its native token, Lighter declares
|
|
285
333
|
* Ethereum USDC. Neither is a gas token you hold there. A chain-local
|