ci(release): publish latest release

parent d655de01
...@@ -6,6 +6,7 @@ Monad Testnet Support - Enjoy swapping on Monad testnet by toggling to Testnet m ...@@ -6,6 +6,7 @@ Monad Testnet Support - Enjoy swapping on Monad testnet by toggling to Testnet m
Other changes: Other changes:
- Improved scrollbar behavior
- VND current support - VND current support
- Improvements to our NFT Spam reporting feature - Improvements to our NFT Spam reporting feature
- Stronger warnings when sending funds to token contracts - Stronger warnings when sending funds to token contracts
......
mobile/1.46 extension/1.16.0
\ No newline at end of file \ No newline at end of file
...@@ -11,7 +11,7 @@ import { useIsWalletUnlocked } from 'src/app/hooks/useIsWalletUnlocked' ...@@ -11,7 +11,7 @@ import { useIsWalletUnlocked } from 'src/app/hooks/useIsWalletUnlocked'
import { HideContentsWhenSidebarBecomesInactive } from 'src/app/navigation/HideContentsWhenSidebarBecomesInactive' import { HideContentsWhenSidebarBecomesInactive } from 'src/app/navigation/HideContentsWhenSidebarBecomesInactive'
import { SideBarNavigationProvider } from 'src/app/navigation/SideBarNavigationProvider' import { SideBarNavigationProvider } from 'src/app/navigation/SideBarNavigationProvider'
import { AppRoutes } from 'src/app/navigation/constants' import { AppRoutes } from 'src/app/navigation/constants'
import { subscribeToRouterState, useRouterState } from 'src/app/navigation/state' import { RouterState, subscribeToRouterState, useRouterState } from 'src/app/navigation/state'
import { focusOrCreateOnboardingTab } from 'src/app/navigation/utils' import { focusOrCreateOnboardingTab } from 'src/app/navigation/utils'
import { isOnboardedSelector } from 'src/app/utils/isOnboardedSelector' import { isOnboardedSelector } from 'src/app/utils/isOnboardedSelector'
import { Flex, SpinningLoader, styled } from 'ui/src' import { Flex, SpinningLoader, styled } from 'ui/src'
...@@ -74,8 +74,8 @@ const getAppRouteFromPathName = (pathname: string): AppRoutes | null => { ...@@ -74,8 +74,8 @@ const getAppRouteFromPathName = (pathname: string): AppRoutes | null => {
const animationVariant: Variants = { const animationVariant: Variants = {
initial: (dir: Direction) => ({ initial: (dir: Direction) => ({
x: isVertical(dir) ? 0 : dir === 'right' ? 30 : -30, x: isVertical(dir) ? 0 : dir === 'right' ? -30 : 30,
y: !isVertical(dir) ? 0 : dir === 'down' ? 15 : -15, y: !isVertical(dir) ? 0 : dir === 'down' ? -15 : 15,
opacity: 0, opacity: 0,
zIndex: 1, zIndex: 1,
}), }),
...@@ -122,8 +122,11 @@ export function WebNavigation(): JSX.Element { ...@@ -122,8 +122,11 @@ export function WebNavigation(): JSX.Element {
useEffect(() => { useEffect(() => {
// We're using subscribeToRouterState subscriber to detect, whether we will // We're using subscribeToRouterState subscriber to detect, whether we will
// navigate to another page, which will lead to the start of the animation. // navigate to another page, which will lead to the start of the animation.
subscribeToRouterState(() => { subscribeToRouterState(({ historyAction, location }: RouterState) => {
const trimmedPathname = location.pathname.replace('/', '') as AppRoutes
if (historyAction !== NavigationType.Replace && Object.values(AppRoutes).includes(trimmedPathname)) {
setIsTransitioning(true) setIsTransitioning(true)
}
}) })
}, []) }, [])
......
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Location, NavigationType, Router, createHashRouter } from 'react-router-dom' import { Location, NavigationType, Router, createHashRouter } from 'react-router-dom'
interface RouterState { export interface RouterState {
historyAction: NavigationType historyAction: NavigationType
location: Location location: Location
} }
......
...@@ -3209,9 +3209,6 @@ PODS: ...@@ -3209,9 +3209,6 @@ PODS:
- React-Core - React-Core
- RNPermissions (4.1.5): - RNPermissions (4.1.5):
- React-Core - React-Core
- RNQrGenerator (1.4.3):
- React
- ZXingObjC
- RNReanimated (3.16.7): - RNReanimated (3.16.7):
- DoubleConversion - DoubleConversion
- glog - glog
...@@ -3335,9 +3332,6 @@ PODS: ...@@ -3335,9 +3332,6 @@ PODS:
- Statsig (1.49.0) - Statsig (1.49.0)
- UIImageColors (2.1.0) - UIImageColors (2.1.0)
- Yoga (0.0.0) - Yoga (0.0.0)
- ZXingObjC (3.6.9):
- ZXingObjC/All (= 3.6.9)
- ZXingObjC/All (3.6.9)
- ZXingObjC/Core (3.6.9) - ZXingObjC/Core (3.6.9)
- ZXingObjC/OneD (3.6.9): - ZXingObjC/OneD (3.6.9):
- ZXingObjC/Core - ZXingObjC/Core
...@@ -3463,7 +3457,6 @@ DEPENDENCIES: ...@@ -3463,7 +3457,6 @@ DEPENDENCIES:
- RNImageColors (from `../../../node_modules/react-native-image-colors`) - RNImageColors (from `../../../node_modules/react-native-image-colors`)
- RNLocalize (from `../../../node_modules/react-native-localize`) - RNLocalize (from `../../../node_modules/react-native-localize`)
- RNPermissions (from `../../../node_modules/react-native-permissions`) - RNPermissions (from `../../../node_modules/react-native-permissions`)
- RNQrGenerator (from `../../../node_modules/rn-qr-generator`)
- RNReanimated (from `../../../node_modules/react-native-reanimated`) - RNReanimated (from `../../../node_modules/react-native-reanimated`)
- RNScreens (from `../../../node_modules/react-native-screens`) - RNScreens (from `../../../node_modules/react-native-screens`)
- RNSVG (from `../../../node_modules/react-native-svg`) - RNSVG (from `../../../node_modules/react-native-svg`)
...@@ -3747,8 +3740,6 @@ EXTERNAL SOURCES: ...@@ -3747,8 +3740,6 @@ EXTERNAL SOURCES:
:path: "../../../node_modules/react-native-localize" :path: "../../../node_modules/react-native-localize"
RNPermissions: RNPermissions:
:path: "../../../node_modules/react-native-permissions" :path: "../../../node_modules/react-native-permissions"
RNQrGenerator:
:path: "../../../node_modules/rn-qr-generator"
RNReanimated: RNReanimated:
:path: "../../../node_modules/react-native-reanimated" :path: "../../../node_modules/react-native-reanimated"
RNScreens: RNScreens:
...@@ -3912,7 +3903,6 @@ SPEC CHECKSUMS: ...@@ -3912,7 +3903,6 @@ SPEC CHECKSUMS:
RNImageColors: 9ac05083b52d5c350e6972650ae3ba0e556466c1 RNImageColors: 9ac05083b52d5c350e6972650ae3ba0e556466c1
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
RNPermissions: 87aac13521bea6dcb6dfd60b03ac69741ccef2b4 RNPermissions: 87aac13521bea6dcb6dfd60b03ac69741ccef2b4
RNQrGenerator: ac6a6c766e80dd3625038929ed2b13e2f3edcafb
RNReanimated: 283b723ad4ac5295f1513519c938cb6c282c508f RNReanimated: 283b723ad4ac5295f1513519c938cb6c282c508f
RNScreens: 906192367b418a8d644090d7375d4657d5a5aab0 RNScreens: 906192367b418a8d644090d7375d4657d5a5aab0
RNSVG: 7ff26379b2d1871b8571e6f9bc9630de6baf9bdf RNSVG: 7ff26379b2d1871b8571e6f9bc9630de6baf9bdf
......
...@@ -153,7 +153,6 @@ ...@@ -153,7 +153,6 @@
"redux-mock-store": "1.5.4", "redux-mock-store": "1.5.4",
"redux-persist": "6.0.0", "redux-persist": "6.0.0",
"redux-saga": "1.2.2", "redux-saga": "1.2.2",
"rn-qr-generator": "1.4.3",
"typed-redux-saga": "1.5.0", "typed-redux-saga": "1.5.0",
"uniswap": "workspace:^", "uniswap": "workspace:^",
"utilities": "workspace:^", "utilities": "workspace:^",
......
import { BarcodeScanningResult, CameraView, CameraViewProps, useCameraPermissions } from 'expo-camera' import { BarcodeScanningResult, CameraView, CameraViewProps, scanFromURLAsync, useCameraPermissions } from 'expo-camera'
import { PermissionStatus } from 'expo-modules-core' import { PermissionStatus } from 'expo-modules-core'
import { memo, useCallback, useEffect, useMemo, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
...@@ -7,7 +7,6 @@ import DeviceInfo from 'react-native-device-info' ...@@ -7,7 +7,6 @@ import DeviceInfo from 'react-native-device-info'
import { launchImageLibrary } from 'react-native-image-picker' import { launchImageLibrary } from 'react-native-image-picker'
import { FadeIn, FadeOut } from 'react-native-reanimated' import { FadeIn, FadeOut } from 'react-native-reanimated'
import { Defs, LinearGradient, Path, Rect, Stop, Svg } from 'react-native-svg' import { Defs, LinearGradient, Path, Rect, Stop, Svg } from 'react-native-svg'
import RNQRGenerator from 'rn-qr-generator'
import { DeprecatedButton, Flex, SpinningLoader, Text, ThemeName, useSporeColors } from 'ui/src' import { DeprecatedButton, Flex, SpinningLoader, Text, ThemeName, useSporeColors } from 'ui/src'
import CameraScan from 'ui/src/assets/icons/camera-scan.svg' import CameraScan from 'ui/src/assets/icons/camera-scan.svg'
import { Global, PhotoStacked } from 'ui/src/components/icons' import { Global, PhotoStacked } from 'ui/src/components/icons'
...@@ -95,25 +94,16 @@ export function QRCodeScanner(props: QRCodeScannerProps | WCScannerProps): JSX.E ...@@ -95,25 +94,16 @@ export function QRCodeScanner(props: QRCodeScannerProps | WCScannerProps): JSX.E
return return
} }
// TODO (WALL-6014): Migrate to expo-camera once Android issue is fixed const result = (await scanFromURLAsync(uri, [BarcodeType.QR]))[0]
try {
const results = await RNQRGenerator.detect({ uri })
if (results.values[0]) { if (!result) {
const data = results.values[0]
onScanCode(data)
} else {
Alert.alert(t('qrScanner.error.none'))
}
} catch (error) {
logger.error(`Cannot detect QR code in image: ${error}`, {
tags: { file: 'QRCodeScanner.tsx', function: 'onPickImageFilePress' },
})
Alert.alert(t('qrScanner.error.none')) Alert.alert(t('qrScanner.error.none'))
} finally {
setIsReadingImageFile(false) setIsReadingImageFile(false)
return
} }
}, [isReadingImageFile, onScanCode, t])
handleBarcodeScanned(result)
}, [handleBarcodeScanned, isReadingImageFile, t])
useEffect(() => { useEffect(() => {
const handlePermissionStatus = async (): Promise<void> => { const handlePermissionStatus = async (): Promise<void> => {
......
...@@ -86,7 +86,13 @@ type ProcessedRow = ...@@ -86,7 +86,13 @@ type ProcessedRow =
| { type: 'footer'; data: SectionInfo } | { type: 'footer'; data: SectionInfo }
function processSections(sections: SettingsSection[]): ProcessedRow[] { function processSections(sections: SettingsSection[]): ProcessedRow[] {
const result: ProcessedRow[] = [] const resultSize = sections.reduce((acc, section) => {
const dataLength = section.data.length
return acc + (section.subTitle ? 1 : 0) + dataLength
}, 0)
const result: ProcessedRow[] = new Array(resultSize)
let index = 0
for (const section of sections) { for (const section of sections) {
if (section.isHidden) { if (section.isHidden) {
...@@ -94,12 +100,12 @@ function processSections(sections: SettingsSection[]): ProcessedRow[] { ...@@ -94,12 +100,12 @@ function processSections(sections: SettingsSection[]): ProcessedRow[] {
} }
if (section.subTitle) { if (section.subTitle) {
result.push({ result[index++] = {
type: 'header', type: 'header',
data: { data: {
section, section,
}, },
}) }
} }
for (const data of section.data) { for (const data of section.data) {
...@@ -107,19 +113,19 @@ function processSections(sections: SettingsSection[]): ProcessedRow[] { ...@@ -107,19 +113,19 @@ function processSections(sections: SettingsSection[]): ProcessedRow[] {
continue continue
} }
result.push({ result[index++] = {
type: 'item', type: 'item',
data, data,
}) }
} }
if (section.subTitle) { if (section.subTitle) {
result.push({ result[index++] = {
type: 'footer', type: 'footer',
data: { data: {
section, section,
}, },
}) }
} }
} }
......
import React, { Dispatch, SetStateAction, useCallback, useMemo } from 'react' import React, { Dispatch, SetStateAction, useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import { DeprecatedButton } from 'ui/src' import { DeprecatedButton } from 'ui/src'
...@@ -8,7 +8,6 @@ import { selectHasDismissedLowNetworkTokenWarning } from 'uniswap/src/features/b ...@@ -8,7 +8,6 @@ import { selectHasDismissedLowNetworkTokenWarning } from 'uniswap/src/features/b
import { WalletEventName } from 'uniswap/src/features/telemetry/constants' import { WalletEventName } from 'uniswap/src/features/telemetry/constants'
import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send'
import { NativeCurrency } from 'uniswap/src/features/tokens/NativeCurrency' import { NativeCurrency } from 'uniswap/src/features/tokens/NativeCurrency'
import { ValueType, getCurrencyAmount } from 'uniswap/src/features/tokens/getCurrencyAmount'
import { useTransactionModalContext } from 'uniswap/src/features/transactions/TransactionModal/TransactionModalContext' import { useTransactionModalContext } from 'uniswap/src/features/transactions/TransactionModal/TransactionModalContext'
import { useIsBlocked } from 'uniswap/src/features/trm/hooks' import { useIsBlocked } from 'uniswap/src/features/trm/hooks'
import { TestID } from 'uniswap/src/test/fixtures/testIDs' import { TestID } from 'uniswap/src/test/fixtures/testIDs'
...@@ -35,29 +34,9 @@ export function SendFormButton({ ...@@ -35,29 +34,9 @@ export function SendFormButton({
recipient, recipient,
isMax, isMax,
derivedSendInfo: { chainId, currencyInInfo }, derivedSendInfo: { chainId, currencyInInfo },
exactAmountToken,
exactAmountFiat,
} = useSendContext() } = useSendContext()
const { walletNeedsRestore } = useTransactionModalContext() const { walletNeedsRestore } = useTransactionModalContext()
const hasValueGreaterThanZero = useMemo(() => {
if (exactAmountToken) {
return getCurrencyAmount({
value: exactAmountToken,
valueType: ValueType.Exact,
currency: currencyInInfo?.currency,
})?.greaterThan(0)
}
if (exactAmountFiat) {
return getCurrencyAmount({
value: exactAmountFiat,
valueType: ValueType.Exact,
currency: currencyInInfo?.currency,
})?.greaterThan(0)
}
return false
}, [exactAmountToken, exactAmountFiat, currencyInInfo?.currency])
const isViewOnlyWallet = account.type === AccountType.Readonly const isViewOnlyWallet = account.type === AccountType.Readonly
const { isBlocked: isActiveBlocked, isBlockedLoading: isActiveBlockedLoading } = useIsBlockedActiveAddress() const { isBlocked: isActiveBlocked, isBlockedLoading: isActiveBlockedLoading } = useIsBlockedActiveAddress()
...@@ -67,8 +46,7 @@ export function SendFormButton({ ...@@ -67,8 +46,7 @@ export function SendFormButton({
const insufficientGasFunds = warnings.warnings.some((warning) => warning.type === WarningLabel.InsufficientGasFunds) const insufficientGasFunds = warnings.warnings.some((warning) => warning.type === WarningLabel.InsufficientGasFunds)
const actionButtonDisabled = const actionButtonDisabled = !!warnings.blockingWarning || isBlocked || isBlockedLoading || walletNeedsRestore
!!warnings.blockingWarning || isBlocked || isBlockedLoading || walletNeedsRestore || !hasValueGreaterThanZero
const onPressReview = useCallback(() => { const onPressReview = useCallback(() => {
if (isViewOnlyWallet) { if (isViewOnlyWallet) {
......
...@@ -33,7 +33,7 @@ module.exports = { ...@@ -33,7 +33,7 @@ module.exports = {
// changedSince: 'master', // changedSince: 'master',
// https://github.com/facebook/jest/issues/2663#issuecomment-341384494 // https://github.com/facebook/jest/issues/2663#issuecomment-341384494
transformIgnorePatterns: [ transformIgnorePatterns: [
'node_modules/(?!(react-native|react-native-web|react-native-modal-selector|react-native-modal-datetime-picker|@storybook/react-native|@react-native-community/datetimepicker|react-native-image-colors|uuid|react-native-reanimated|react-native-safe-area-context|react-native-localize|@react-native-masked-view|statsig-js|statsig-react-native|statsig-react|@react-native|@react-native-firebase|react-native-webview|@gorhom|expo.*|d3-(array|color|format|interpolate|path|scale|shape|time-format|time)|internmap|react-native-qrcode-svg|react-native-modal|react-native-animatable|react-native-masked-view|redux-persist|react-native-url-polyfill|react-native-context-menu-view|react-native-wagmi-charts|react-native-markdown-display|react-native-redash|@walletconnect|moti|react-native-image-picker|wagmi|viem|rn-qr-generator)/)', 'node_modules/(?!(react-native|react-native-web|react-native-modal-selector|react-native-modal-datetime-picker|@storybook/react-native|@react-native-community/datetimepicker|react-native-image-colors|uuid|react-native-reanimated|react-native-safe-area-context|react-native-localize|@react-native-masked-view|statsig-js|statsig-react-native|statsig-react|@react-native|@react-native-firebase|react-native-webview|@gorhom|expo.*|d3-(array|color|format|interpolate|path|scale|shape|time-format|time)|internmap|react-native-qrcode-svg|react-native-modal|react-native-animatable|react-native-masked-view|redux-persist|react-native-url-polyfill|react-native-context-menu-view|react-native-wagmi-charts|react-native-markdown-display|react-native-redash|@walletconnect|moti|react-native-image-picker|wagmi|viem)/)',
], ],
collectCoverage: false, // only collect in CI collectCoverage: false, // only collect in CI
clearMocks: true, clearMocks: true,
......
...@@ -17,7 +17,13 @@ export type ProcessedRow = ...@@ -17,7 +17,13 @@ export type ProcessedRow =
| { type: ProcessedRowType.Footer; data: SectionRowInfo } | { type: ProcessedRowType.Footer; data: SectionRowInfo }
export function processTokenSections(sections: TokenSection[]): ProcessedRow[] { export function processTokenSections(sections: TokenSection[]): ProcessedRow[] {
const result: ProcessedRow[] = [] const resultSize = sections.reduce((acc, section) => {
const dataLength = section.data.length
return acc + (section.name ? 1 : 0) + dataLength
}, 0)
const result: ProcessedRow[] = new Array(resultSize)
let index = 0
for (const section of sections) { for (const section of sections) {
// process header // process header
...@@ -28,19 +34,19 @@ export function processTokenSections(sections: TokenSection[]): ProcessedRow[] { ...@@ -28,19 +34,19 @@ export function processTokenSections(sections: TokenSection[]): ProcessedRow[] {
name: section.name, name: section.name,
} }
result.push({ result[index++] = {
type: ProcessedRowType.Header, type: ProcessedRowType.Header,
data: { data: {
section: headerProps, section: headerProps,
}, },
}) }
// process items // process items
const tokenData = section.data const tokenData = section.data
let itemIndex = 0 let itemIndex = 0
for (const item of tokenData) { for (const item of tokenData) {
result.push({ result[index++] = {
type: ProcessedRowType.Item, type: ProcessedRowType.Item,
data: { data: {
item, item,
...@@ -49,15 +55,15 @@ export function processTokenSections(sections: TokenSection[]): ProcessedRow[] { ...@@ -49,15 +55,15 @@ export function processTokenSections(sections: TokenSection[]): ProcessedRow[] {
// expanded is not used in native :thinking: // expanded is not used in native :thinking:
expanded: false, expanded: false,
}, },
}) }
} }
result.push({ result[index++] = {
type: ProcessedRowType.Footer, type: ProcessedRowType.Footer,
data: { data: {
section: headerProps, section: headerProps,
}, },
}) }
} }
return result return result
......
...@@ -37,13 +37,15 @@ export function useCurrencyInfo( ...@@ -37,13 +37,15 @@ export function useCurrencyInfo(
if (chainId && address) { if (chainId && address) {
const commonBase = getCommonBase(chainId, isNativeCurrencyAddress(chainId, address), address) const commonBase = getCommonBase(chainId, isNativeCurrencyAddress(chainId, address), address)
if (commonBase) { if (commonBase) {
// Creating new object to avoid error "Cannot assign to read only property"
const copyCommonBase = { ...commonBase }
// Related to TODO(WEB-5111) // Related to TODO(WEB-5111)
// Some common base images are broken so this'll ensure we read from uniswap images // Some common base images are broken so this'll ensure we read from uniswap images
if (data?.token?.project?.logoUrl) { if (data?.token?.project?.logoUrl) {
commonBase.logoUrl = data.token.project.logoUrl copyCommonBase.logoUrl = data.token.project.logoUrl
} }
commonBase.currencyId = _currencyId copyCommonBase.currencyId = _currencyId
return commonBase return copyCommonBase
} }
} }
......
...@@ -39,8 +39,7 @@ export function useUSDTokenUpdater({ ...@@ -39,8 +39,7 @@ export function useUSDTokenUpdater({
return undefined return undefined
} }
const _exactAmountFiat = exactAmountFiat === '.' ? '0' : exactAmountFiat || '0' const exactAmountUSD = (parseFloat(exactAmountFiat || '0') / conversionRate).toFixed(NUM_DECIMALS_USD)
const exactAmountUSD = (parseFloat(_exactAmountFiat) / conversionRate).toFixed(NUM_DECIMALS_USD)
if (shouldUseUSDRef.current) { if (shouldUseUSDRef.current) {
const stablecoinAmount = getCurrencyAmount({ const stablecoinAmount = getCurrencyAmount({
......
...@@ -17132,7 +17132,6 @@ __metadata: ...@@ -17132,7 +17132,6 @@ __metadata:
redux-persist: 6.0.0 redux-persist: 6.0.0
redux-saga: 1.2.2 redux-saga: 1.2.2
redux-saga-test-plan: 4.0.4 redux-saga-test-plan: 4.0.4
rn-qr-generator: 1.4.3
typed-redux-saga: 1.5.0 typed-redux-saga: 1.5.0
typescript: 5.3.3 typescript: 5.3.3
uniswap: "workspace:^" uniswap: "workspace:^"
...@@ -42558,15 +42557,6 @@ __metadata: ...@@ -42558,15 +42557,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"rn-qr-generator@npm:1.4.3":
version: 1.4.3
resolution: "rn-qr-generator@npm:1.4.3"
peerDependencies:
react-native: ">=0.55"
checksum: 570ee73fbc897a6fb5e9cb69b90e5f6542c2622004921658bec467b9cd564dc2b0f0b4440e87eac740121f717bf760e873ba0977ca1f7924e364f3586b98ba82
languageName: node
linkType: hard
"roarr@npm:^2.15.3": "roarr@npm:^2.15.3":
version: 2.15.4 version: 2.15.4
resolution: "roarr@npm:2.15.4" resolution: "roarr@npm:2.15.4"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment