Skip to content

Commit d655de0

Browse files
ci(release): publish latest release
1 parent 1088b81 commit d655de0

File tree

1,017 files changed

+38195
-43562
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,017 files changed

+38195
-43562
lines changed

.nvmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v22.13.1
1+
v18.16.0

CODEOWNERS

-1
This file was deleted.

RELEASE

+9-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
1-
IPFS hash of the deployment:
2-
- CIDv0: `QmY1KGrtefyx6c622uKgMsF3wdgcHrctuPjx6FKEXtbTaU`
3-
- CIDv1: `bafybeiepudn33fn7she525pbbiq6vlylmo4ujkvbrzdbkxud5qevpnddxu`
1+
We are back with some new updates! Here’s the latest:
42

5-
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
3+
Last release we introduced Unichain support! Now, enjoy faster swap speeds, more onramp options, and more token data.
64

7-
You can also access the Uniswap Interface from an IPFS gateway.
8-
**BEWARE**: The Uniswap interface uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported.
9-
**You should always use an IPFS gateway that enforces origin separation**, or our hosted deployment of the latest release at [app.uniswap.org](https://app.uniswap.org).
10-
Your Uniswap settings are never remembered across different URLs.
11-
12-
IPFS gateways:
13-
- https://bafybeiepudn33fn7she525pbbiq6vlylmo4ujkvbrzdbkxud5qevpnddxu.ipfs.dweb.link/
14-
- [ipfs://QmY1KGrtefyx6c622uKgMsF3wdgcHrctuPjx6FKEXtbTaU/](ipfs://QmY1KGrtefyx6c622uKgMsF3wdgcHrctuPjx6FKEXtbTaU/)
15-
16-
### 5.75.2 (2025-03-06)
17-
18-
19-
### Bug Fixes
20-
21-
* **web:** ensure that tick spacing is a whole number (#17038) 5acf938
5+
Monad Testnet Support - Enjoy swapping on Monad testnet by toggling to Testnet mode in settings
226

7+
Other changes:
238

9+
- VND current support
10+
- Improvements to our NFT Spam reporting feature
11+
- Stronger warnings when sending funds to token contracts
12+
- New icon for the Buy/Sell button on the homepage
13+
- Various bug fixes and performance improvements

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
web/5.75.2
1+
mobile/1.46

apps/extension/.eslintrc.js

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
const rulesDirPlugin = require('eslint-plugin-rulesdir')
2-
rulesDirPlugin.RULES_DIR = '../../packages/uniswap/eslint_rules'
3-
41
module.exports = {
52
root: true,
6-
extends: ['@uniswap/eslint-config/native-app'],
7-
plugins: ['rulesdir'],
3+
extends: ['@uniswap/eslint-config/native'],
84
ignorePatterns: [
95
'node_modules',
106
'dist',
@@ -24,7 +20,6 @@ module.exports = {
2420
ecmaVersion: 2018,
2521
sourceType: 'module',
2622
},
27-
rules: {},
2823
overrides: [
2924
{
3025
files: ['src/assets/index.ts', 'src/contentScript/index.tsx'],
@@ -43,21 +38,6 @@ module.exports = {
4338
],
4439
},
4540
},
46-
{
47-
files: ['**/contentScript/injected.ts'],
48-
rules: {
49-
'no-restricted-syntax': [
50-
'error',
51-
{
52-
selector: 'CallExpression[callee.object.name="logger"][callee.property.name!=/^(debug)$/]',
53-
message:
54-
'Only logger.debug is allowed in this file. Please handle errors and info logs explicitly using ErrorLog and InfoLog message passing.',
55-
},
56-
],
57-
},
58-
},
5941
],
60-
rules: {
61-
'rulesdir/i18n': 'error',
62-
},
42+
rules: {},
6343
}

apps/extension/package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"browserslist": "last 2 chrome versions",
55
"dependencies": {
66
"@apollo/client": "3.10.4",
7+
"@datadog/browser-logs": "5.20.0",
8+
"@datadog/browser-rum": "5.23.3",
79
"@ethersproject/providers": "5.7.2",
810
"@metamask/rpc-errors": "6.2.1",
911
"@reduxjs/toolkit": "1.9.3",
@@ -12,11 +14,10 @@
1214
"@types/uuid": "9.0.1",
1315
"@uniswap/analytics-events": "2.41.0",
1416
"@uniswap/uniswapx-sdk": "3.0.0-beta.3",
15-
"@uniswap/universal-router-sdk": "4.19.0",
16-
"@uniswap/v3-sdk": "3.24.1",
17-
"@uniswap/v4-sdk": "1.20.0",
17+
"@uniswap/universal-router-sdk": "4.17.0",
18+
"@uniswap/v3-sdk": "3.24.0",
19+
"@uniswap/v4-sdk": "1.19.2",
1820
"dotenv-webpack": "8.0.1",
19-
"eslint-plugin-rulesdir": "0.2.2",
2021
"ethers": "5.7.2",
2122
"eventemitter3": "5.0.1",
2223
"framer-motion": "10.17.6",

apps/extension/src/app/apollo.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ApolloProvider } from '@apollo/client'
22
import { PropsWithChildren } from 'react'
33
import { localStorage } from 'redux-persist-webextension-storage'
44
import { getReduxStore } from 'src/store/store'
5-
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
5+
// eslint-disable-next-line no-restricted-imports
66
import { usePersistedApolloClient } from 'wallet/src/data/apollo/usePersistedApolloClient'
77

88
// Extension local storage has 10 MB limit, so we want to be very careful to leave enough space for the redux store + any other data that we might want to store in local storage

apps/extension/src/app/components/Trace/TraceUserProperties.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useAppFiatCurrencyInfo } from 'uniswap/src/features/fiatCurrency/hooks'
55
import { useCurrentLanguage } from 'uniswap/src/features/language/hooks'
66
import { useHideSmallBalancesSetting, useHideSpamTokensSetting } from 'uniswap/src/features/settings/hooks'
77
import { ExtensionUserPropertyName, setUserProperty } from 'uniswap/src/features/telemetry/user'
8-
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
8+
// eslint-disable-next-line no-restricted-imports
99
import { analytics } from 'utilities/src/telemetry/analytics/analytics'
1010
import { useGatingUserPropertyUsernames } from 'wallet/src/features/gating/userPropertyHooks'
1111
import { useActiveAccount, useSignerAccounts, useViewOnlyAccounts } from 'wallet/src/features/wallet/hooks'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Flex } from 'ui/src'
2+
import { LoadingSpinnerInner, LoadingSpinnerOuter } from 'ui/src/components/icons'
3+
4+
const SPINNER_HEIGHT = 80
5+
6+
export function LoadingSpinner(): JSX.Element {
7+
return (
8+
<>
9+
<Flex height={SPINNER_HEIGHT} position="relative" width={80}>
10+
<Flex bottom={0} left={0} position="absolute" right={0} top={0}>
11+
<LoadingSpinnerOuter color="$DEP_brandedAccentSoft" size={80} />
12+
</Flex>
13+
<Flex
14+
bottom={0}
15+
left={0}
16+
position="absolute"
17+
right={0}
18+
style={{ animation: `spin ${SPIN_SPEED_MS}ms linear infinite` }}
19+
top={0}
20+
>
21+
<LoadingSpinnerInner color="$accent1" size={80} />
22+
</Flex>
23+
</Flex>
24+
</>
25+
)
26+
}
27+
28+
const SPIN_SPEED_MS = 1000

apps/extension/src/app/components/loading/SkeletonBox.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@ export function SkeletonBox({
1212
height: number | string
1313
borderRadius?: string
1414
}): JSX.Element {
15-
// eslint-disable-next-line react/forbid-elements
1615
return <div className="skeleton-box" style={{ width, height, borderRadius }} />
1716
}

apps/extension/src/app/core/PopupApp.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { syncAppWithDeviceLanguage } from 'uniswap/src/features/settings/slice'
1616
import Trace from 'uniswap/src/features/telemetry/Trace'
1717
import { ElementName } from 'uniswap/src/features/telemetry/constants'
1818
import { ExtensionScreens } from 'uniswap/src/types/screens/extension'
19-
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks/useTestnetModeForLoggingAndAnalytics'
19+
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks'
2020

2121
const router = createHashRouter([
2222
{
@@ -80,6 +80,7 @@ function PopupContent(): JSX.Element {
8080
width="100%"
8181
onPress={async () => {
8282
if (windowIdNumber) {
83+
// eslint-disable-next-line security/detect-non-literal-fs-filename
8384
await chrome.sidePanel.open({ tabId: tabIdNumber, windowId: windowIdNumber })
8485
window.close()
8586
}

apps/extension/src/app/core/SidebarApp.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import { isDevEnv } from 'utilities/src/environment/env'
4545
import { logger } from 'utilities/src/logger/logger'
4646
import { ONE_SECOND_MS } from 'utilities/src/time/time'
4747
import { useInterval } from 'utilities/src/time/timing'
48-
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks/useTestnetModeForLoggingAndAnalytics'
48+
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks'
4949

5050
const router = createHashRouter([
5151
{

apps/extension/src/app/core/StatsigProvider.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { useEffect, useState } from 'react'
2+
import { initializeDatadog } from 'src/app/datadog'
23
import { getStatsigEnvironmentTier } from 'src/app/version'
34
import Statsig from 'statsig-js' // Use JS package for browser
45
import { config } from 'uniswap/src/config'
56
import { uniswapUrls } from 'uniswap/src/constants/urls'
67
import { StatsigCustomAppValue } from 'uniswap/src/features/gating/constants'
78
import { StatsigOptions, StatsigProvider, StatsigUser } from 'uniswap/src/features/gating/sdk/statsig'
8-
import { initializeDatadog } from 'uniswap/src/utils/datadog'
99
import { getUniqueId } from 'utilities/src/device/getUniqueId'
1010
import { useAsyncData } from 'utilities/src/react/hooks'
1111

apps/extension/src/app/core/UnitagClaimApp.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { Flex } from 'ui/src'
2525
import { UnitagUpdaterContextProvider } from 'uniswap/src/features/unitags/context'
2626
import { logger } from 'utilities/src/logger/logger'
2727
import { usePrevious } from 'utilities/src/react/hooks'
28-
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks/useTestnetModeForLoggingAndAnalytics'
28+
import { useTestnetModeForLoggingAndAnalytics } from 'wallet/src/features/testnetMode/hooks'
2929
import { useAccountAddressFromUrlWithThrow } from 'wallet/src/features/wallet/hooks'
3030

3131
const router = createHashRouter([

apps/extension/src/app/datadog.ts

+134
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
import { datadogLogs } from '@datadog/browser-logs'
2+
import { RumEvent, datadogRum } from '@datadog/browser-rum'
3+
import { getDatadogEnvironment } from 'src/app/version'
4+
import { config } from 'uniswap/src/config'
5+
import {
6+
DatadogIgnoredErrorsConfigKey,
7+
DatadogIgnoredErrorsValType,
8+
DatadogSessionSampleRateKey,
9+
DatadogSessionSampleRateValType,
10+
DynamicConfigs,
11+
} from 'uniswap/src/features/gating/configs'
12+
import { Experiments } from 'uniswap/src/features/gating/experiments'
13+
import { WALLET_FEATURE_FLAG_NAMES } from 'uniswap/src/features/gating/flags'
14+
import { getDynamicConfigValue } from 'uniswap/src/features/gating/hooks'
15+
import { Statsig } from 'uniswap/src/features/gating/sdk/statsig'
16+
import { getUniqueId } from 'utilities/src/device/getUniqueId'
17+
import { datadogEnabled, localDevDatadogEnabled } from 'utilities/src/environment/constants'
18+
import { logger } from 'utilities/src/logger/logger'
19+
20+
// In case Statsig is not available
21+
const EXTENSION_DEFAULT_DATADOG_SESSION_SAMPLE_RATE = 10 // percent
22+
123
export const enum DatadogAppNameTag {
224
Sidebar = 'sidebar',
325
Onboarding = 'onboarding',
@@ -6,3 +28,115 @@ export const enum DatadogAppNameTag {
628
Popup = 'popup',
729
UnitagClaim = 'unitag-claim',
830
}
31+
32+
function beforeSend(event: RumEvent): boolean {
33+
// otherwise DataDog will ignore error events
34+
event.view.url = event.view.url.replace(/^chrome-extension:\/\/[a-z]{32}\//i, '')
35+
if (event.error && event.type === 'error') {
36+
if (event.error.source === 'console') {
37+
return false
38+
}
39+
const ignoredErrors = getDynamicConfigValue<
40+
DynamicConfigs.DatadogIgnoredErrors,
41+
DatadogIgnoredErrorsConfigKey,
42+
DatadogIgnoredErrorsValType
43+
>(DynamicConfigs.DatadogIgnoredErrors, DatadogIgnoredErrorsConfigKey.Errors, [])
44+
45+
const ignoredError = ignoredErrors.find(({ messageContains }) => event.error?.message.includes(messageContains))
46+
if (ignoredError && Math.random() > ignoredError.sampleRate) {
47+
return false
48+
}
49+
50+
Object.defineProperty(event.error, 'stack', {
51+
value: event.error.stack?.replace(/chrome-extension:\/\/[a-z]{32}/gi, ''),
52+
writable: false,
53+
configurable: true,
54+
})
55+
}
56+
57+
return true
58+
}
59+
60+
export async function initializeDatadog(appName: string): Promise<void> {
61+
if (!datadogEnabled) {
62+
return
63+
}
64+
65+
const sessionSampleRate = getDynamicConfigValue<
66+
DynamicConfigs.DatadogSessionSampleRate,
67+
DatadogSessionSampleRateKey,
68+
DatadogSessionSampleRateValType
69+
>(
70+
DynamicConfigs.DatadogSessionSampleRate,
71+
DatadogSessionSampleRateKey.Rate,
72+
EXTENSION_DEFAULT_DATADOG_SESSION_SAMPLE_RATE,
73+
)
74+
75+
const sharedDatadogConfig = {
76+
clientToken: config.datadogClientToken,
77+
service: `extension-${getDatadogEnvironment()}`,
78+
env: getDatadogEnvironment(),
79+
version: process.env.VERSION,
80+
trackingConsent: undefined,
81+
}
82+
83+
datadogRum.init({
84+
...sharedDatadogConfig,
85+
applicationId: config.datadogProjectId,
86+
sessionSampleRate: localDevDatadogEnabled ? 100 : sessionSampleRate,
87+
sessionReplaySampleRate: 0,
88+
trackResources: true,
89+
trackLongTasks: true,
90+
trackUserInteractions: true,
91+
enablePrivacyForActionName: true,
92+
beforeSend,
93+
})
94+
95+
// According to the Datadog RUM documentation:
96+
// https://docs.datadoghq.com/real_user_monitoring/browser/setup/client?tab=rum#access-internal-context
97+
// datadogRum.init() seems to be synchronous and internal context is immediately available.
98+
// Local testing confirms this behavior, explaining why no "onInitialization" callback is needed.
99+
const internalContext = datadogRum.getInternalContext()
100+
const sessionIsSampled = internalContext?.session_id !== undefined
101+
102+
// we do not want to log anything if session is not sampled
103+
if (sessionIsSampled) {
104+
datadogLogs.init({
105+
...sharedDatadogConfig,
106+
site: 'datadoghq.com',
107+
forwardErrorsToLogs: false,
108+
})
109+
logger.setWalletDatadogEnabled(true)
110+
}
111+
112+
try {
113+
const userId = await getUniqueId()
114+
datadogRum.setUser({
115+
id: userId,
116+
})
117+
} catch (e) {
118+
logger.error(e, {
119+
tags: { file: 'datadog.ts', function: 'initializeDatadog' },
120+
})
121+
}
122+
123+
datadogRum.setGlobalContextProperty('app', appName)
124+
125+
for (const [_, flagKey] of WALLET_FEATURE_FLAG_NAMES.entries()) {
126+
datadogRum.addFeatureFlagEvaluation(
127+
// Datadog has a limited set of accepted symbols in feature flags
128+
// https://docs.datadoghq.com/real_user_monitoring/guide/setup-feature-flag-data-collection/?tab=reactnative#feature-flag-naming
129+
flagKey.replaceAll('-', '_'),
130+
Statsig.checkGateWithExposureLoggingDisabled(flagKey),
131+
)
132+
}
133+
134+
for (const experiment of Object.values(Experiments)) {
135+
datadogRum.addFeatureFlagEvaluation(
136+
// Datadog has a limited set of accepted symbols in feature flags
137+
// https://docs.datadoghq.com/real_user_monitoring/guide/setup-feature-flag-data-collection/?tab=reactnative#feature-flag-naming
138+
`experiment_${experiment.replaceAll('-', '_')}`,
139+
Statsig.getExperimentWithExposureLoggingDisabled(experiment).getGroupName(),
140+
)
141+
}
142+
}

apps/extension/src/app/features/accounts/AccountSwitcherScreen.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ export function AccountSwitcherScreen(): JSX.Element {
188188
<Flex gap="$spacing16" pb="$spacing4" pt="$spacing8" px="$spacing12">
189189
<AddressDisplay
190190
showCopy
191-
centered
192191
address={activeAddress}
193192
captionVariant="body3"
194193
direction="column"

0 commit comments

Comments
 (0)