ci(release): publish latest release

parent 4df1f115
IPFS hash of the deployment:
- CIDv0: `QmX4W6sgCHYCcR4SxeJVbZnj5N1GXR2ERPJomoBjVSbZVZ`
- CIDv1: `bafybeiebsyucxoiaieyyktifwl7glbepaklj4tncplc3rvssq55rpl553a`
- CIDv0: `QmSyV4dNhjeqsxaKHkFZyqyLKGaqBUkgr5fb1FDZN24yY5`
- CIDv1: `bafybeice3zkknbq42szpbonaebytodvjc7rddzz3v5rc4hd6wjts6t2usi`
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
......@@ -10,118 +10,21 @@ You can also access the Uniswap Interface from an IPFS gateway.
Your Uniswap settings are never remembered across different URLs.
IPFS gateways:
- https://bafybeiebsyucxoiaieyyktifwl7glbepaklj4tncplc3rvssq55rpl553a.ipfs.dweb.link/
- https://bafybeiebsyucxoiaieyyktifwl7glbepaklj4tncplc3rvssq55rpl553a.ipfs.cf-ipfs.com/
- [ipfs://QmX4W6sgCHYCcR4SxeJVbZnj5N1GXR2ERPJomoBjVSbZVZ/](ipfs://QmX4W6sgCHYCcR4SxeJVbZnj5N1GXR2ERPJomoBjVSbZVZ/)
- https://bafybeice3zkknbq42szpbonaebytodvjc7rddzz3v5rc4hd6wjts6t2usi.ipfs.dweb.link/
- https://bafybeice3zkknbq42szpbonaebytodvjc7rddzz3v5rc4hd6wjts6t2usi.ipfs.cf-ipfs.com/
- [ipfs://QmSyV4dNhjeqsxaKHkFZyqyLKGaqBUkgr5fb1FDZN24yY5/](ipfs://QmSyV4dNhjeqsxaKHkFZyqyLKGaqBUkgr5fb1FDZN24yY5/)
## 5.13.0 (2024-02-27)
## 5.14.0 (2024-02-27)
### Features
* **web:** [info] Add Bottom Bar to PDP mWeb (#6444) edd221d
* **web:** [info] add tvl and volume % change to PDP query (#6453) 3054897
* **web:** [info] add warning label to swap modal on PDP page (#6398) f7bacf9
* **web:** [info] candlestick data integration and fallback refactor (#6510) 1136e54
* **web:** [info] candlestick tooltip (#6355) fbb184f
* **web:** [info] Connect PDP data to our BE (#6357) 45a32d6
* **web:** [info] Connect PDP Volume Chart to real data (#6455) 3c7fa86
* **web:** [info] Integrate BE Pool TX queries (#6424) d2df578
* **web:** [info] Migrate Explore and TDP TX tables to our GQL BE (#6502) b674b85
* **web:** [info] pdp loading states (#6504) 57c0279
* **web:** [info] Sortable Token Explore Table Headers (#6435) f0e95d0
* **web:** [info] TDP chart loading states (#6450) d45a2e7
* **web:** [info] use custom PDP seo page title (#6422) f2e6552
* **web:** [info] use dropdown bottom sheet in smaller screens (#6452) 0177aaa
* **web:** [info] Use real price data for PDP Price Chart (#6457) 9493135
* **web:** [info] Various mWeb polish (#6549) 97e313e
* **web:** [uni-tags] adding username to send (#6358) 507bffc
* **web:** [uni-tags] improve Web3Status and account drawer header (#6454) 0c57325
* **web:** [uni-tags] update banner copy and responsive styles (#6401) b8445de
* **web:** add Explore and TDP chart staleness checks (#6458) 71cac56
* **web:** add gas estimate to limits dialog (#6233) 6689ae4
* **web:** add more analytics for limits (#6475) 14de73d
* **web:** Add more limits analytics events (#6496) 1bc5245
* **web:** Add off chain order type to trade events and swap tab click event (#6417) 3ad9ce0
* **web:** add price change speedbump to limit form (#6447) 1f855b5
* **web:** change input currency from LimitPriceInputPanel (#6250) 8313cb9
* **web:** fix limit status updating (#6363) 727de8b
* **web:** handle remote open limits (#6407) 519dbb9
* **web:** invert limit price preset button adjustments (#6518) c93f355
* **web:** mv limits cta to activity tab (#6532) e34eb1c
* **web:** pending states for cancelling limits (#6360) 1a3f5b9
* **web:** redesign limits menu rows (#6575) 11ac692
* **web:** Set default quote currency in limits price display based on stablecoin (#6456) 4b5a48a
* **web:** sync url to swap tab (#6432) ffb2d8c
* **web:** transaction details for insufficient liquidity (#6531) 8d85c98
* **web:** Update progress indicator step titles for limit orders (#6470) 090248e
* **web:** update TOS last updated to 2/16/2024 (#6550) 533b087
* **web:** Use GQL Token Data for Pool Token Logos (#6505) 00e6504
* **web:** add disclaimer to limits review modal (#6597) f1cb196
### Bug Fixes
* **web:** [info] add tooltip for turnover on token table (#6507) 50ea4f5
* **web:** [info] block explorer icon not showing dark mode TDP (#6557) f0ca33d
* **web:** [info] explore table mobile hover (#6512) 7abb6f7
* **web:** [info] fix extralong numbers on explore chart section (#6524) db5bbdc
* **web:** [info] fix translations for chart type selector (#6533) ee54af9
* **web:** [info] flickering volume bars (#6581) 60582ac
* **web:** [info] hide chart y-axis on smaller screen (#6506) c64a8f4
* **web:** [info] knock out a bunch of high-pri polish tasks (#6305) e5d0797
* **web:** [info] make return to top clickable again (#6559) 6d65932
* **web:** [info] MOOREE polish (#6486) 0a5b22f
* **web:** [info] more polish (#6434) 41ca7ea
* **web:** [info] pdp matching tdp (#6501) fb8ec9d
* **web:** [info] Prevent infinite loading for fully loaded tables (#6394) 4233a2f
* **web:** [info] pull decimal data for gql tokens (#6558) 3d9a336
* **web:** [info] Show explorer icon in PDP Links in darkmode (#6584) 8bd04e5
* **web:** [info] Show PDP balances on mWeb (#6585) aee363f
* **web:** [info] Show TDP Bottom Bar at exactly 1024px (#6576) d04dd12
* **web:** [limits] empty transaction details with ETH (#6519) 8c1532d
* **web:** [limits] fix transaction details text to match design (#6534) dc4dbd3
* **web:** [limits] making market button the same as percentage (#6516) 6f417c9
* **web:** [limits] update order confirmation flow (#6490) 0966070
* **web:** [uni-tags] inline banner height, icon size, pfp (#6538) 67b10ab
* **web:** align swap box and action buttons (#6497) 7c846bc
* **web:** chain switching search params (#6491) 6c88199
* **web:** chain switching search params (#6491) (#6514) f10d64e
* **web:** Change auction period secs to 0 (#6589) eab18eb
* **web:** clear limits form when submitting a limit (#6515) 9bab70b
* **web:** color code buy/sell on TDP tx table (#6498) eaafcb6
* **web:** convert backend timestamp from sec to ms for X orders (#6540) 4161221
* **web:** de-crowd the swap header bar (#6546) b0fd755
* **web:** disable test and update gql schema (#6517) e3aa751
* **web:** disable text select on the $ in the send form (#6433) 2a9ba50
* **web:** division by zero error in limits menu (#6561) 3190502
* **web:** do not truncate token symbols (#6495) 3f3b28b
* **web:** enable limits for all tokens (#6485) ee6fd22
* **web:** fix cancelation confirmation modal for limit orders (#6583) 8565065
* **web:** fix limit tab breaking after switching to l2s (#6554) 15f2d32
* **web:** ignore touchmove on charts (#6500) 51c7d32
* **web:** invert displayed custom price adjustment to match presets (#6560) a9fbe5c
* **web:** layout bug in token selector (#6484) a4e2de1
* **web:** limit form styling nits (#6253) ca34460
* **web:** limiting max decimals in input (#6446) df01d65
* **web:** limits menu styling nits (#6254) a83faa5
* **web:** lint error in useCurrentPriceAdjustment (#6492) cd1e011
* **web:** long pool name overlap (#6503) 78d4d8c
* **web:** minor design nits for limits (#6522) 450366a
* **web:** Misc. design fixes to Token Detail Page (#6565) 7146990
* **web:** open limits menu button bug (#6389) 7cdcc98
* **web:** revert - clear limits form when submitting a limit (#6515) (#6528) 52ef6fd
* **web:** setState error from LimitForm (#6249) df2aca3
* **web:** stacked tvl rendering overlap (#6573) f090a13
* **web:** styling fixes for limits flow (#6525) 72ed86b
* **web:** swap header<>url navigation bug (#6513) ad8d8d9
* **web:** swap z-indexing (#6499) 1573567
* **web:** truncate currency amount to decimals when parsing (#6586) 2a891d9
* **web:** Use local activities if GraphQL assetActivities query returns nothing (#6494) 137b253
### Code Refactoring
* **web:** [info] tdp provider pattern (#6385) 5c52db7
* **web:** [info] use tdp context in subcomponents (#6400) 99bbedc
* **web:** fix expiry line item (#6596) 7225ae9
* **web:** use page chain for liquidity chart (#6582) 4e89b28
web/5.13.0
\ No newline at end of file
web/5.14.0
\ No newline at end of file
......@@ -57,6 +57,7 @@ import {
v55Schema,
v56Schema,
v57Schema,
v58Schema,
v5Schema,
v6Schema,
v7Schema,
......@@ -1299,4 +1300,11 @@ describe('Redux state migrations', () => {
expect(v58.behaviorHistory.hasSkippedUnitagPrompt).toBe(false)
})
it('migrates from v58 to 59', () => {
const v58Stub = { ...v58Schema }
const v59 = migrations[59](v58Stub)
expect(v59.behaviorHistory.hasCompletedUnitagsIntroModal).toBe(false)
})
})
......@@ -793,4 +793,15 @@ export const migrations = {
return newState
},
59: function addCompletedUnitagsIntroBoolean(state: any) {
const newState = { ...state }
newState.behaviorHistory = {
...state.behaviorHistory,
hasCompletedUnitagsIntroModal: false,
}
return newState
},
}
......@@ -287,6 +287,7 @@ export function AccountSwitcher({ onClose }: { onClose: () => void }): JSX.Eleme
horizontalGap="$spacing8"
showViewOnlyBadge={isViewOnly}
size={spacing.spacing60 - spacing.spacing4}
variant="subheading1"
/>
<Flex px="$spacing24">
<Button
......
......@@ -243,6 +243,7 @@ exports[`AccountSwitcher renders correctly 1`] = `
{
"alignItems": "center",
"flexDirection": "row",
"gap": 4,
"justifyContent": "center",
}
}
......
......@@ -435,6 +435,13 @@ export const v58Schema = {
},
}
export const v59Schema = {
...v58Schema,
behaviorHistory: {
...v58Schema.behaviorHistory,
hasCompletedUnitagsIntroModal: false,
},
}
// TODO: [MOB-201] use function with typed output when API reducers are removed from rootReducer
// export const getSchema = (): RootState => v0Schema
export const getSchema = (): typeof v57Schema => v57Schema
......@@ -75,7 +75,7 @@ export const persistConfig = {
key: 'root',
storage: reduxStorage,
whitelist,
version: 58,
version: 59,
migrate: createMigrate(migrations),
}
......
......@@ -154,6 +154,10 @@ function getMetamaskAddress(uri: string): Nullable<string> {
// format is scantastic://<uri>
function getScantasticAddress(uri: string): Nullable<string> {
if (!uri.startsWith('scantastic://')) {
return null
}
const uriParts = uri.split('://')
if (uriParts.length < 2) {
......
......@@ -386,6 +386,7 @@ exports[`AccountList renders without error 1`] = `
{
"alignItems": "center",
"flexDirection": "row",
"gap": 4,
"justifyContent": "center",
}
}
......
......@@ -127,7 +127,7 @@ const ChoosePhotoOption = ({ type }: { type: PhotoAction }): JSX.Element => {
<Text
color={type === PhotoAction.RemovePhoto ? '$statusCritical' : '$neutral1'}
numberOfLines={1}
variant="body1">
variant="buttonLabel2">
{type === PhotoAction.BrowseCameraRoll && t('Choose from camera roll')}
{type === PhotoAction.BrowseNftsList && t('Choose an NFT')}
{type === PhotoAction.RemovePhoto && t('Remove profile picture')}
......
......@@ -2,8 +2,9 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard, StyleProp, ViewStyle } from 'react-native'
import { useAppDispatch } from 'src/app/hooks'
import { navigate } from 'src/app/navigation/rootNavigation'
import { openModal } from 'src/features/modals/modalSlice'
import { Screens } from 'src/screens/Screens'
import { Screens, UnitagScreens } from 'src/screens/Screens'
import {
Flex,
Image,
......@@ -15,8 +16,10 @@ import {
} from 'ui/src'
import { UNITAGS_BANNER_VERTICAL_DARK, UNITAGS_BANNER_VERTICAL_LIGHT } from 'ui/src/assets'
import { borderRadii, iconSizes, spacing } from 'ui/src/theme'
import { selectHasCompletedUnitagsIntroModal } from 'wallet/src/features/behaviorHistory/selectors'
import { setHasSkippedUnitagPrompt } from 'wallet/src/features/behaviorHistory/slice'
import { UNITAG_SUFFIX_NO_LEADING_DOT } from 'wallet/src/features/unitags/constants'
import { useAppSelector } from 'wallet/src/state'
import { sendWalletAnalyticsEvent } from 'wallet/src/telemetry'
import { ElementName, ModalName, UnitagEventName } from 'wallet/src/telemetry/constants'
......@@ -38,6 +41,8 @@ export function UnitagBanner({
const { fullWidth } = useDeviceDimensions()
const isDarkMode = useIsDarkMode()
const colors = useSporeColors()
const hasCompletedUnitagsIntroModal = useAppSelector(selectHasCompletedUnitagsIntroModal)
const imageWidth = compact
? COMPACT_IMAGE_SCREEN_WIDTH_PROPORTION * fullWidth
: IMAGE_SCREEN_WIDTH_PROPORTION * fullWidth
......@@ -50,7 +55,18 @@ export function UnitagBanner({
action: 'claim',
entryPoint: analyticsEntryPoint,
})
dispatch(openModal({ name: ModalName.UnitagsIntro, initialState: { address, entryPoint } }))
if (hasCompletedUnitagsIntroModal) {
navigate(Screens.UnitagStack, {
screen: UnitagScreens.ClaimUnitag,
params: {
entryPoint,
address,
},
})
} else {
dispatch(openModal({ name: ModalName.UnitagsIntro, initialState: { address, entryPoint } }))
}
}
const onPressMaybeLater = (): void => {
......@@ -77,12 +93,12 @@ export function UnitagBanner({
alignContent="space-between"
backgroundColor={compact ? '$surface2' : '$background'}
borderColor="$surface3"
borderRadius="$rounded16"
borderRadius="$rounded20"
borderWidth={compact ? undefined : '$spacing1'}
mt="$spacing12"
overflow="hidden"
pl="$spacing16"
py="$spacing16"
py="$spacing12"
shadowColor="$neutral3"
shadowOpacity={0.4}
shadowRadius="$spacing4">
......@@ -134,7 +150,7 @@ export function UnitagBanner({
}}
testID={ElementName.Cancel}
onPress={onPressMaybeLater}>
<Text color="$neutral3" variant="buttonLabel4">
<Text color="$neutral2" variant="buttonLabel4">
{t('Maybe later')}
</Text>
</TouchableArea>
......
......@@ -22,7 +22,9 @@ export function UnitagProfilePicture({
<Flex
shrink
backgroundColor="$surface1"
borderColor="$surface1"
borderRadius="$roundedFull"
borderWidth={2}
height={size}
overflow="hidden"
shadowColor="$neutral3"
......
......@@ -24,15 +24,15 @@ export const UnitagWithProfilePicture = ({
backgroundColor="$surface1"
borderRadius="$rounded32"
px="$spacing12"
py="$spacing16"
py="$spacing8"
shadowColor="$neutral3"
shadowOpacity={0.4}
shadowRadius="$spacing4"
transform={[{ rotateZ: '-2deg' }]}
zIndex="$popover">
<Text color="$accent1" variant="buttonLabel1">
<Text color="$accent1" variant="subheading1">
{unitag}
<Text color="$neutral2" variant="buttonLabel1">
<Text color="$neutral3" variant="subheading1">
{UNITAG_SUFFIX}
</Text>
</Text>
......
......@@ -12,6 +12,7 @@ import { Button, Flex, GeneratedIcon, Icons, Image, Text, useIsDarkMode } from '
import { UNITAGS_INTRO_BANNER_DARK, UNITAGS_INTRO_BANNER_LIGHT } from 'ui/src/assets'
import { iconSizes } from 'ui/src/theme'
import { BottomSheetModal } from 'wallet/src/components/modals/BottomSheetModal'
import { setHasCompletedUnitagsIntroModal } from 'wallet/src/features/behaviorHistory/slice'
import { sendWalletAnalyticsEvent } from 'wallet/src/telemetry'
import { ModalName } from 'wallet/src/telemetry/constants'
......@@ -31,6 +32,8 @@ export function UnitagsIntroModal(): JSX.Element {
if (!entryPoint) {
throw new Error('Missing entry point in UnitagsIntroModal')
}
appDispatch(setHasCompletedUnitagsIntroModal(true))
navigate(Screens.UnitagStack, {
screen: UnitagScreens.ClaimUnitag,
params: {
......
......@@ -207,7 +207,7 @@ exports[`GenericImportForm renders a placeholder when there is no value 1`] = `
{
"color": "#FC72FF",
"fontFamily": "Basel-Medium",
"fontSize": 13,
"fontSize": 15,
"fontWeight": "500",
"lineHeight": 16,
}
......
......@@ -25,7 +25,7 @@ exports[`renders trait card 1`] = `
{
"color": "#7D7D7D",
"fontFamily": "Basel-Medium",
"fontSize": 13,
"fontSize": 15,
"fontWeight": "500",
"lineHeight": 16,
}
......
......@@ -13,7 +13,6 @@ type OnboardingScreenProps = {
subtitle?: string
title: string
paddingTop?: SpaceTokens
childrenGap?: SpaceTokens
}
export function SafeKeyboardOnboardingScreen({
......
......@@ -9,7 +9,7 @@ import { UnitagProfilePicture } from 'src/components/unitags/UnitagProfilePictur
import { SafeKeyboardOnboardingScreen } from 'src/features/onboarding/SafeKeyboardOnboardingScreen'
import { UnitagName } from 'src/features/unitags/UnitagName'
import { OnboardingScreens, Screens, UnitagScreens } from 'src/screens/Screens'
import { Button, Flex, Icons, Text, useSporeColors } from 'ui/src'
import { Button, Flex, Icons, Text, useIsDarkMode, useSporeColors } from 'ui/src'
import { fonts, iconSizes, imageSizes, spacing } from 'ui/src/theme'
import { ChainId } from 'wallet/src/constants/chains'
import { useENSName } from 'wallet/src/features/ens/api'
......@@ -39,6 +39,7 @@ export function ChooseProfilePictureScreen({
const colors = useSporeColors()
const { data: ensName } = useENSName(address, ChainId.Mainnet)
const claimUnitag = useClaimUnitag()
const isDarkMode = useIsDarkMode()
const [imageUri, setImageUri] = useState<string>()
const [showModal, setShowModal] = useState(false)
......@@ -116,24 +117,23 @@ export function ChooseProfilePictureScreen({
'Upload your own or stick with your unique Unicon. You can always change this later.'
)}
title={t('Choose a profile photo')}>
<Flex centered gap="$spacing20" mt="$spacing48">
<Flex onPress={avatarSelectionHandler}>
<Flex centered gap="$spacing20" mt="$spacing24">
<Flex mt="$spacing48" onPress={avatarSelectionHandler}>
<Flex px="$spacing4">
<ProfilePicture address={address} imageUri={imageUri} />
</Flex>
<Flex
backgroundColor="$surface1"
borderRadius="$roundedFull"
bottom={-spacing.spacing4}
bottom={-spacing.spacing2}
p="$spacing4"
position="absolute"
right={-spacing.spacing4}>
right={-spacing.spacing2}>
<Flex
backgroundColor="$neutral2"
borderColor="$surface1"
backgroundColor={isDarkMode ? '$neutral3' : '$neutral2'}
borderRadius="$roundedFull"
borderWidth="$spacing4"
p="$spacing8">
<Icons.PencilDetailed color="$surface1" size={iconSizes.icon16} />
p={8}>
<Icons.Pen color={isDarkMode ? '$neutral1' : '$surface1'} size={iconSizes.icon16} />
</Flex>
</Flex>
</Flex>
......
......@@ -23,7 +23,6 @@ import {
useSporeColors,
} from 'ui/src'
import { ENS_LOGO } from 'ui/src/assets'
import InfoCircle from 'ui/src/assets/icons/info-circle.svg'
import { fonts, iconSizes, imageSizes, spacing } from 'ui/src/theme'
import { logger } from 'utilities/src/logger/logger'
import { ONE_SECOND_MS } from 'utilities/src/time/time'
......@@ -255,6 +254,7 @@ export function ClaimUnitagScreen({ navigation, route }: Props): JSX.Element {
<Flex
centered
gap="$spacing16"
mt="$spacing24"
onLayout={(event): void => {
onLayout(event)
onSetFontSize(inputPlaceholder + UNITAG_SUFFIX_CHARS_ONLY)
......@@ -331,7 +331,7 @@ export function ClaimUnitagScreen({ navigation, route }: Props): JSX.Element {
Keyboard.dismiss()
setShowInfoModal(true)
}}>
<InfoCircle color={colors.neutral2.get()} height={20} width={20} />
<Icons.InfoCircleFilled color={colors.neutral3.get()} size="$icon.20" />
</TouchableArea>
</AnimatedFlex>
{canClaimUnitagNameError && unitagToCheck === unitagInputValue && (
......
......@@ -141,7 +141,7 @@ export const HeartElement = (): JSX.Element => {
<Flex
borderRadius="$rounded12"
p="$spacing8"
style={{ backgroundColor: opacify(20, colors.red200) }}
style={{ backgroundColor: colors.red50 }}
transform={[{ rotateZ: '-4deg' }]}>
<HeartIcon color={colors.red300} height={iconSizes.icon20} width={iconSizes.icon20} />
</Flex>
......
......@@ -350,7 +350,7 @@ export function EditUnitagProfileScreen({
mx="$spacing16"
position="absolute"
onPress={avatarSelectionHandler}>
<Flex backgroundColor="$surface1" borderRadius="$roundedFull" p="$spacing2">
<Flex backgroundColor="$surface1" borderRadius="$roundedFull">
<UnitagProfilePicture
address={address}
size={iconSizes.icon70}
......@@ -370,7 +370,7 @@ export function EditUnitagProfileScreen({
p={6}>
<Icons.Pen
color={isDarkMode ? '$neutral1' : '$surface1'}
size={iconSizes.icon12}
size={iconSizes.icon16}
/>
</Flex>
</Flex>
......
......@@ -67,6 +67,7 @@ export function UnitagConfirmationScreen({
<Flex centered grow>
<AnimatePresence exitBeforeEnter>
<AnimateInOrder
key="outerCircle"
enterStyle={{ opacity: 0, scale: 0.5 }}
exitStyle={{ opacity: 0, scale: 0.5 }}
index={1}
......@@ -80,6 +81,7 @@ export function UnitagConfirmationScreen({
/>
</AnimateInOrder>
<AnimateInOrder
key="innerCircle"
enterStyle={{ opacity: 0, scale: 0.5 }}
exitStyle={{ opacity: 0, scale: 0.5 }}
index={2}
......@@ -102,7 +104,7 @@ export function UnitagConfirmationScreen({
{element}
</AnimateInOrder>
))}
<AnimateInOrder hapticOnEnter index={12}>
<AnimateInOrder key="unitag" hapticOnEnter index={12}>
<UnitagWithProfilePicture
address={address}
profilePictureUri={profilePictureUri}
......
import { Flex, Icons, Text } from 'ui/src'
import { fonts, iconSizes } from 'ui/src/theme'
import { fonts, spacing } from 'ui/src/theme'
export function UnitagName({
name,
......@@ -35,8 +35,8 @@ export function UnitagName({
enterStyle={animateIcon ? { opacity: 0, scale: 0.8, x: 20 } : undefined}
exitStyle={animateIcon ? { opacity: 0, scale: 0.8, x: -20 } : undefined}
position="absolute"
right={-iconSizes.icon8}
top={-iconSizes.icon8}>
right={-spacing.spacing4}
top={-spacing.spacing4}>
<Icons.Unitag size="$icon.24" />
</Flex>
</Flex>
......
......@@ -59,7 +59,7 @@ function useLineItem(details: OffchainOrderLineItemProps): LineItemData | undefi
case OffchainOrderLineItemType.EXPIRY:
return {
Label: () => <Trans>Expiry</Trans>,
Value: () => <span>{formatTimestamp(details.order.expiry)}</span>,
Value: () => <span>{details.order.expiry && formatTimestamp(details.order.expiry * 1000)}</span>,
}
case OffchainOrderLineItemType.NETWORK_COST:
return {
......
......@@ -1046,9 +1046,7 @@ exports[`OrderContent should render without error, open order 1`] = `
<div
class="c6 c20 css-142zc9n"
>
<span>
Mock Date
</span>
<span />
</div>
</div>
<div
......
......@@ -25,7 +25,7 @@ import { PositionInfo } from './cache'
type ContractMap<T extends BaseContract> = { [key: number]: T }
// Constructs a chain-to-contract map, using the wallet's provider when available
function useContractMultichain<T extends BaseContract>(
export function useContractMultichain<T extends BaseContract>(
addressMap: AddressMap,
ABI: any,
chainIds?: ChainId[]
......
import { ChartHoverData, ChartModel, ChartModelParams } from 'components/Charts/ChartModel'
import { ISeriesApi, UTCTimestamp } from 'lightweight-charts'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { ChainId, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { FeeAmount, Pool, TICK_SPACINGS, TickMath, tickToPrice } from '@uniswap/v3-sdk'
import { BigNumber } from 'ethers/lib/ethers'
import { TickProcessed, usePoolActiveLiquidity } from 'hooks/usePoolTickData'
......@@ -221,14 +221,16 @@ export function useLiquidityBarData({
tokenB,
feeTier,
isReversed,
chainId,
}: {
tokenA: Token
tokenB: Token
feeTier: FeeAmount
isReversed: boolean
chainId: ChainId
}) {
const { formatNumber, formatPrice } = useFormatter()
const activePoolData = usePoolActiveLiquidity(tokenA, tokenB, feeTier)
const activePoolData = usePoolActiveLiquidity(tokenA, tokenB, feeTier, chainId)
const [tickData, setTickData] = useState<{
barData: LiquidityBarData[]
......
import { Trans, t } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { ChainId, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { ChartHeader } from 'components/Charts/ChartHeader'
import { Chart } from 'components/Charts/ChartModel'
......@@ -19,7 +19,7 @@ import { LoadingChart } from 'components/Tokens/TokenDetails/Skeleton'
import { DISPLAYS, TimePeriodDisplay, getTimePeriodFromDisplay } from 'components/Tokens/TokenTable/TimeSelector'
import { Chain, ProtocolVersion } from 'graphql/data/__generated__/types-and-hooks'
import { PoolData } from 'graphql/data/pools/usePoolData'
import { TimePeriod, gqlToCurrency, toHistoryDuration } from 'graphql/data/util'
import { TimePeriod, gqlToCurrency, supportedChainIdFromGQLChain, toHistoryDuration } from 'graphql/data/util'
import useStablecoinPrice from 'hooks/useStablecoinPrice'
import { useAtomValue } from 'jotai/utils'
import { useMemo, useState } from 'react'
......@@ -152,7 +152,7 @@ export default function ChartSection(props: ChartSectionProps) {
const loading = props.loading || (activeQuery.chartType !== ChartType.LIQUIDITY ? activeQuery?.loading : false)
const ChartBody = (() => {
if (!currencyA || !currencyB || !props.poolData) {
if (!currencyA || !currencyB || !props.poolData || !props.chain) {
return <ChartSkeleton type={activeQuery.chartType} height={PDP_CHART_HEIGHT_PX} />
}
......@@ -163,6 +163,7 @@ export default function ChartSection(props: ChartSectionProps) {
timePeriod,
tokenA: currencyA.wrapped,
tokenB: currencyB.wrapped,
chainId: supportedChainIdFromGQLChain(props.chain) ?? ChainId.MAINNET,
}
// TODO(WEB-3740): Integrate BE tick query, remove special casing for liquidity chart
......@@ -328,11 +329,13 @@ function LiquidityChart({
tokenB,
feeTier,
isReversed,
chainId,
}: {
tokenA: Token
tokenB: Token
feeTier: FeeAmount
isReversed: boolean
chainId: ChainId
}) {
const tokenADescriptor = tokenA.symbol ?? tokenA.name ?? t`Token A`
const tokenBDescriptor = tokenB.symbol ?? tokenB.name ?? t`Token B`
......@@ -342,6 +345,7 @@ function LiquidityChart({
tokenB,
feeTier,
isReversed,
chainId,
})
const theme = useTheme()
......
......@@ -124,6 +124,10 @@ describe('SwapModalFooter.tsx', () => {
expect(screen.getByText('Expiry')).toBeInTheDocument()
expect(screen.getByText('Fee')).toBeInTheDocument()
expect(screen.getByText('Network cost')).toBeInTheDocument()
expect(screen.getByText('Canceling a limit will require a small network cost')).toBeInTheDocument()
expect(
screen.getByText(
'Please be aware that the execution for this limit order may vary based on real-time market fluctuations and Ethereum network congestion. Canceling a limit has a network cost.'
)
).toBeInTheDocument()
})
})
......@@ -327,6 +327,12 @@ function ExpandableLineItems(props: { trade: InterfaceTrade; allowedSlippage: Pe
)
}
const StyledInfoIcon = styled(Info)`
margin-top: 2px;
align-self: flex-start;
flex-shrink: 0;
`
function LimitLineItems({ trade }: { trade: LimitOrderTrade }) {
return (
<>
......@@ -334,10 +340,16 @@ function LimitLineItems({ trade }: { trade: LimitOrderTrade }) {
<SwapLineItem trade={trade} type={SwapLineItemType.EXPIRY} />
<SwapLineItem trade={trade} type={SwapLineItemType.SWAP_FEE} />
<SwapLineItem trade={trade} type={SwapLineItemType.NETWORK_COST} />
<Row gap="xs" justify="center" marginTop="12px">
<Info width={16} height={16} />
<Row gap="sm" justify="space-between" marginTop="12px">
<StyledInfoIcon width={16} height={16} />
<ThemedText.LabelMicro>
<Trans>Canceling a limit will require a small network cost</Trans>
<Trans>
Please be aware that the execution for this limit order may vary based on real-time market fluctuations and
Ethereum network congestion. Canceling a limit has a network cost.{' '}
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/24300813697933">
<Trans>Learn more</Trans>
</ExternalLink>
</Trans>
</ThemedText.LabelMicro>
</Row>
</>
......
import { ApolloClient, ApolloLink, concat, HttpLink, InMemoryCache } from '@apollo/client'
import { ApolloClient, ApolloLink, concat, HttpLink, InMemoryCache, NormalizedCacheObject } from '@apollo/client'
import { ChainId } from '@uniswap/sdk-core'
import store from '../../state/index'
......@@ -33,3 +33,34 @@ export const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: concat(authMiddleware, httpLink),
})
export const chainToApolloClient: Record<number, ApolloClient<NormalizedCacheObject>> = {
[ChainId.MAINNET]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.MAINNET],
}),
[ChainId.ARBITRUM_ONE]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.ARBITRUM_ONE],
}),
[ChainId.OPTIMISM]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.OPTIMISM],
}),
[ChainId.POLYGON]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.POLYGON],
}),
[ChainId.CELO]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.CELO],
}),
[ChainId.BNB]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.BNB],
}),
[ChainId.AVALANCHE]: new ApolloClient({
cache: new InMemoryCache(),
uri: CHAIN_SUBGRAPH_URL[ChainId.AVALANCHE],
}),
}
import { Currency, Price, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core'
import { ChainId, Currency, Price, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core'
import { FeeAmount, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core'
import { TickData, Ticks } from 'graphql/thegraph/AllV3TicksQuery'
import { useAllV3TicksQuery } from 'graphql/thegraph/__generated__/types-and-hooks'
import { apolloClient } from 'graphql/thegraph/apollo'
import JSBI from 'jsbi'
import ms from 'ms'
import { useEffect, useMemo, useState } from 'react'
import computeSurroundingTicks from 'utils/computeSurroundingTicks'
import { PoolState, usePool } from './usePools'
import { chainToApolloClient } from 'graphql/thegraph/apollo'
import { PoolState, usePoolMultichain } from './usePools'
const PRICE_FIXED_DIGITS = 8
......@@ -29,9 +29,10 @@ function useTicksFromSubgraph(
currencyA: Currency | undefined,
currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined,
skip = 0
skip = 0,
chainId: ChainId
) {
const { chainId } = useWeb3React()
const apolloClient = chainToApolloClient[chainId]
const poolAddress =
currencyA && currencyB && feeAmount
? Pool.getAddress(
......@@ -56,7 +57,8 @@ const MAX_THE_GRAPH_TICK_FETCH_VALUE = 1000
function useAllV3Ticks(
currencyA: Currency | undefined,
currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined
feeAmount: FeeAmount | undefined,
chainId: ChainId
): {
isLoading: boolean
error: unknown
......@@ -64,7 +66,7 @@ function useAllV3Ticks(
} {
const [skipNumber, setSkipNumber] = useState(0)
const [subgraphTickData, setSubgraphTickData] = useState<Ticks>([])
const { data, error, loading: isLoading } = useTicksFromSubgraph(currencyA, currencyB, feeAmount, skipNumber)
const { data, error, loading: isLoading } = useTicksFromSubgraph(currencyA, currencyB, feeAmount, skipNumber, chainId)
useEffect(() => {
if (data?.ticks.length) {
......@@ -85,7 +87,8 @@ function useAllV3Ticks(
export function usePoolActiveLiquidity(
currencyA: Currency | undefined,
currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined
feeAmount: FeeAmount | undefined,
chainId?: ChainId
): {
isLoading: boolean
error: any
......@@ -95,7 +98,8 @@ export function usePoolActiveLiquidity(
sqrtPriceX96?: JSBI
data?: TickProcessed[]
} {
const pool = usePool(currencyA, currencyB, feeAmount)
const defaultChainId = useWeb3React().chainId ?? ChainId.MAINNET
const pool = usePoolMultichain(currencyA?.wrapped, currencyB?.wrapped, feeAmount, chainId ?? defaultChainId)
const liquidity = pool[1]?.liquidity
const sqrtPriceX96 = pool[1]?.sqrtRatioX96
......@@ -103,7 +107,7 @@ export function usePoolActiveLiquidity(
// Find nearest valid tick for pool in case tick is not initialized.
const activeTick = useMemo(() => getActiveTick(currentTick, feeAmount), [currentTick, feeAmount])
const { isLoading, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount)
const { isLoading, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount, chainId ?? defaultChainId)
return useMemo(() => {
if (
......
import { Interface } from '@ethersproject/abi'
import { BigintIsh, Currency, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core'
import { BigintIsh, ChainId, Currency, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core'
import IUniswapV3PoolStateJSON from '@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json'
import { FeeAmount, Pool, computePoolAddress } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core'
import { useContractMultichain } from 'components/AccountDrawer/MiniPortfolio/Pools/hooks'
import JSBI from 'jsbi'
import { useMultipleContractSingleData } from 'lib/hooks/multicall'
import { useMemo } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { IUniswapV3PoolStateInterface } from 'wallet/src/abis/types/v3/IUniswapV3PoolState'
import { UniswapV3Pool } from 'wallet/src/abis/types/v3/UniswapV3Pool'
const POOL_STATE_INTERFACE = new Interface(IUniswapV3PoolStateJSON.abi) as IUniswapV3PoolStateInterface
......@@ -150,3 +152,41 @@ export function usePool(
return usePools(poolKeys)[0]
}
export function usePoolMultichain(
tokenA: Token | undefined,
tokenB: Token | undefined,
fee: number | undefined,
chainId: ChainId
): [PoolState, Pool | null] {
const [poolData, setPoolData] = useState<[PoolState, Pool | null]>([PoolState.LOADING, null])
const poolAddress =
tokenA && tokenB && fee
? PoolCache.getPoolAddress(V3_CORE_FACTORY_ADDRESSES[chainId], tokenA, tokenB, fee)
: undefined
const contractMap = useMemo(() => (poolAddress ? { [chainId]: poolAddress } : {}), [chainId, poolAddress])
const contract = useContractMultichain<UniswapV3Pool>(contractMap, IUniswapV3PoolStateJSON.abi)[chainId]
useEffect(() => {
async function getPool() {
try {
if (!tokenA || !tokenB || !fee || !poolAddress || !contract) {
setPoolData([PoolState.INVALID, null])
return
}
const slot0 = await contract.slot0()
const liquidity = await contract.liquidity()
setPoolData([PoolState.NOT_EXISTS, null])
const pool = new Pool(tokenA, tokenB, fee, slot0.sqrtPriceX96.toString(), liquidity.toString(), slot0.tick)
setPoolData([PoolState.EXISTS, pool])
} catch (e) {
setPoolData([PoolState.INVALID, null])
}
}
getPool()
}, [contract, fee, poolAddress, tokenA, tokenB])
return poolData
}
import { danger, fail, markdown, message, warn } from 'danger'
// Other ideas:
// - verify TODO have work items linked
function getIndicesOf(searchStr: string, str: string): number[] {
var searchStrLen = searchStr.length;
if (searchStrLen == 0) {
......@@ -16,21 +13,35 @@ function getIndicesOf(searchStr: string, str: string): number[] {
return indices;
}
async function processAddChanges() {
const updatedTsFiles = danger.git.modified_files
.concat(danger.git.created_files)
.filter((file) => (file.endsWith('.ts') || file.endsWith('.tsx')) && !file.includes('dangerfile.ts'))
const linesAddedByFile = (await Promise.all(updatedTsFiles.flatMap(async (file) => {
async function getLinesAddedByFile(files: string[]) {
return await Promise.all(files.flatMap(async (file) => {
const structuredDiff = await danger.git.structuredDiffForFile(file);
return (structuredDiff?.chunks || []).flatMap((chunk) => {
return chunk.changes.filter((change) => change.type === 'add')
})
})))
}))
}
async function processAddChanges() {
const updatedTsFiles = danger.git.modified_files
.concat(danger.git.created_files)
.filter((file) => (file.endsWith('.ts') || file.endsWith('.tsx')) && !file.includes('dangerfile.ts'))
const updatedNonUITsFiles = updatedTsFiles.filter((file) => !file.includes('packages/ui'))
const linesAddedByFile = await getLinesAddedByFile(updatedTsFiles)
const allLinesAdded = linesAddedByFile.flatMap((x) => x)
// Check for non-UI package lines for tamagui imports
const allNonUILinesAddedByFile = await getLinesAddedByFile(updatedNonUITsFiles)
const allNonUILinesAdded = allNonUILinesAddedByFile.flatMap((x) => x)
allNonUILinesAdded.forEach((change) => {
if (change.content.includes(`from 'tamagui`)) {
fail(`Please import any tamagui exports via the ui package. Found an import at ${change.content}`)
}
})
// Checks for any logging and reminds the developer not to log sensitive data
if (allLinesAdded.some((change) => change.content.includes('logMessage') || change.content.includes('logger.'))) {
warn('You are logging data. Please confirm that nothing sensitive is being logged!')
......
......@@ -18,9 +18,11 @@ export {
YGroup,
getToken,
getTokenValue,
isWeb,
styled,
useMedia,
usePropsAndStyle,
useWindowDimensions,
} from 'tamagui'
export type {
Adapt,
......
......@@ -125,7 +125,7 @@ export const fonts = {
},
buttonLabel4: {
family: platformFontFamily('medium'),
fontSize: adjustedSize(12),
fontSize: adjustedSize(14),
lineHeight: 16,
fontWeight: '500',
maxFontSizeMultiplier: 1.2,
......
......@@ -74,7 +74,6 @@
"redux-saga": "1.2.2",
"redux-saga-test-plan": "4.0.4",
"statsig-react-native": "4.11.0",
"tamagui": "1.89.26",
"typed-redux-saga": "1.5.0",
"ua-parser-js": "1.0.37",
"ui": "workspace:^",
......
import { BottomSheetSectionList } from '@gorhom/bottom-sheet'
import { ListRenderItemInfo, SectionList, SectionListData } from 'react-native'
import { FadeIn, FadeOut } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Text, TouchableArea, useDeviceInsets } from 'ui/src'
import { AnimatedFlex, Text, TouchableArea, isWeb, useDeviceInsets } from 'ui/src'
import { spacing } from 'ui/src/theme'
import { AddressDisplay } from 'wallet/src/components/accounts/AddressDisplay'
import { SearchableRecipient } from 'wallet/src/features/address/types'
......
import { ImpactFeedbackStyle } from 'expo-haptics'
import { memo } from 'react'
import { isWeb } from 'tamagui'
import { TouchableArea, useSporeColors } from 'ui/src'
import { isWeb, TouchableArea, useSporeColors } from 'ui/src'
import { iconSizes } from 'ui/src/theme'
import { TokenLogo } from 'wallet/src/components/CurrencyLogo/TokenLogo'
import { Pill } from 'wallet/src/components/text/Pill'
......
import { CSSProperties, Key, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import AutoSizer from 'react-virtualized-auto-sizer'
import { VariableSizeList as List } from 'react-window'
import { useWindowDimensions } from 'tamagui'
import { Flex } from 'ui/src'
import { Flex, useWindowDimensions } from 'ui/src'
import { zIndices } from 'ui/src/theme'
import {
ItemRowInfo,
......
......@@ -3,8 +3,7 @@ import { hasStringAsync } from 'expo-clipboard'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard } from 'react-native'
import { isWeb } from 'tamagui'
import { Flex, useSporeColors } from 'ui/src'
import { Flex, isWeb, useSporeColors } from 'ui/src'
import { zIndices } from 'ui/src/theme'
import { Trace } from 'utilities/src/telemetry/trace/Trace'
import { useDebounce } from 'utilities/src/time/timing'
......
import { memo, useCallback, useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { FadeIn, FadeOut } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Flex, Loader, Skeleton, Text } from 'ui/src'
import { AnimatedFlex, Flex, isWeb, Loader, Skeleton, Text } from 'ui/src'
import { fonts } from 'ui/src/theme'
import { BaseCard } from 'wallet/src/components/BaseCard/BaseCard'
import { useBottomSheetFocusHook } from 'wallet/src/components/modals/hooks'
......
import { skipToken } from '@reduxjs/toolkit/dist/query'
import { memo, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { Flex } from 'ui/src'
import { Flex, isWeb } from 'ui/src'
import { iconSizes } from 'ui/src/theme'
import { BaseCard } from 'wallet/src/components/BaseCard/BaseCard'
import { SpinningLoader } from 'wallet/src/components/loading/SpinningLoader'
......
import { memo, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { isWeb } from 'ui/src'
import {
useCommonTokensOptions,
useFavoriteTokensOptions,
......
import { StyleSheet } from 'react-native'
import Svg, { Defs, RadialGradient as RadialGradientSVG, Rect, Stop } from 'react-native-svg'
import { isWeb } from 'tamagui'
import { ColorTokens, Flex, Icons, Unicon, UniconV2, useUniconColors } from 'ui/src'
import { ColorTokens, Flex, Icons, Unicon, UniconV2, isWeb, useUniconColors } from 'ui/src'
import { spacing } from 'ui/src/theme'
import { FEATURE_FLAGS } from 'wallet/src/features/experiments/constants'
import { useFeatureFlag } from 'wallet/src/features/experiments/hooks'
......
......@@ -165,6 +165,8 @@ export function AddressDisplay({
<Flex centered row gap="$spacing12">
<DisplayNameText
displayName={displayName}
gap="$spacing4"
includeUnitagSuffix={includeUnitagSuffix}
textProps={{
adjustsFontSizeToFit: true,
allowFontScaling,
......
......@@ -68,7 +68,7 @@ export function AnimatedUnitagDisplayName({
</Text>
</Flex>
{isUnitag ? (
<Flex animation="semiBouncy" pl="$spacing2">
<Flex animation="semiBouncy" pl="$spacing4">
<Icons.Unitag size={unitagIconSize} />
</Flex>
) : null}
......
import { Flex, FlexProps, Icons, Text, TextProps } from 'ui/src'
import { IconSizeTokens } from 'ui/src/theme'
import { UNITAG_SUFFIX } from 'wallet/src/features/unitags/constants'
import { DisplayName, DisplayNameType } from 'wallet/src/features/wallet/types'
type DisplayNameProps = {
displayName?: DisplayName
unitagIconSize?: IconSizeTokens | number
textProps?: TextProps
includeUnitagSuffix?: boolean
} & FlexProps
export function DisplayNameText({
displayName,
unitagIconSize = '$icon.24',
textProps,
includeUnitagSuffix,
...rest
}: DisplayNameProps): JSX.Element {
const isUnitag = displayName?.type === DisplayNameType.Unitag
const name = isUnitag ? displayName?.name.replaceAll(UNITAG_SUFFIX, '') : displayName?.name
return (
<Flex centered row {...rest}>
<Text {...textProps} color={textProps?.color ?? '$neutral1'} flexShrink={1} numberOfLines={1}>
{displayName?.name}
{name}
{isUnitag && includeUnitagSuffix && (
<Text {...textProps} color="$neutral3" flexShrink={1} numberOfLines={1}>
{UNITAG_SUFFIX}
</Text>
)}
</Text>
{isUnitag ? (
<Flex>
......
......@@ -274,6 +274,7 @@ exports[`AccountDetails renders without error 1`] = `
{
"alignItems": "center",
"flexDirection": "row",
"gap": 4,
"justifyContent": "center",
}
}
......@@ -607,6 +608,7 @@ exports[`AccountDetails renders without error with chevron 1`] = `
{
"alignItems": "center",
"flexDirection": "row",
"gap": 4,
"justifyContent": "center",
}
}
......
import { selectionAsync } from 'expo-haptics'
import { useCallback, useMemo, useState } from 'react'
import { LayoutAnimation, StyleSheet, VirtualizedList } from 'react-native'
import { isWeb } from 'tamagui'
import { Flex, Icons } from 'ui/src'
import { Flex, Icons, isWeb } from 'ui/src'
import EllipsisIcon from 'ui/src/assets/icons/ellipsis.svg'
import { colors, iconSizes } from 'ui/src/theme'
import {
......
......@@ -123,7 +123,7 @@ exports[`NetworkPill renders an InlineNetworkPill 1`] = `
{
"color": "#209853",
"fontFamily": "Basel-Medium",
"fontSize": 13,
"fontSize": 15,
"fontWeight": "500",
"lineHeight": 16,
"paddingTop": 1,
......
......@@ -8,3 +8,6 @@ export const selectHasSubmittedHoldToSwap = (state: SharedState): boolean =>
export const selectHasSkippedUnitagPrompt = (state: SharedState): boolean =>
state.behaviorHistory.hasSkippedUnitagPrompt
export const selectHasCompletedUnitagsIntroModal = (state: SharedState): boolean =>
state.behaviorHistory.hasCompletedUnitagsIntroModal
......@@ -8,12 +8,14 @@ export interface BehaviorHistoryState {
hasViewedReviewScreen: boolean // used for hold to swap tip on swap UI
hasSubmittedHoldToSwap: boolean
hasSkippedUnitagPrompt: boolean
hasCompletedUnitagsIntroModal: boolean
}
export const initialBehaviorHistoryState: BehaviorHistoryState = {
hasViewedReviewScreen: false,
hasSubmittedHoldToSwap: false,
hasSkippedUnitagPrompt: false,
hasCompletedUnitagsIntroModal: false,
}
const slice = createSlice({
......@@ -29,10 +31,17 @@ const slice = createSlice({
setHasSkippedUnitagPrompt: (state, action: PayloadAction<boolean>) => {
state.hasSkippedUnitagPrompt = action.payload
},
setHasCompletedUnitagsIntroModal: (state, action: PayloadAction<boolean>) => {
state.hasCompletedUnitagsIntroModal = action.payload
},
},
})
export const { setHasViewedReviewScreen, setHasSubmittedHoldToSwap, setHasSkippedUnitagPrompt } =
slice.actions
export const {
setHasViewedReviewScreen,
setHasSubmittedHoldToSwap,
setHasSkippedUnitagPrompt,
setHasCompletedUnitagsIntroModal,
} = slice.actions
export const behaviorHistoryReducer = slice.reducer
......@@ -10,8 +10,15 @@ import {
State,
} from 'react-native-gesture-handler'
import { useAnimatedStyle, useSharedValue, withDelay, withSpring } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Flex, Text, TouchableArea, mediumShadowProps, useDeviceInsets } from 'ui/src'
import {
AnimatedFlex,
Flex,
Text,
TouchableArea,
isWeb,
mediumShadowProps,
useDeviceInsets,
} from 'ui/src'
import { borderRadii, spacing } from 'ui/src/theme'
import { useTimeout } from 'utilities/src/time/timing'
import { selectActiveAccountNotifications } from 'wallet/src/features/notifications/selectors'
......
import { isWeb } from 'tamagui'
import { Flex, Icons, Shine, Skeleton, Text, useSporeColors } from 'ui/src'
import { Flex, Icons, Shine, Skeleton, Text, isWeb, useSporeColors } from 'ui/src'
import { isWarmLoadingStatus } from 'wallet/src/data/utils'
import { usePortfolioTotalValue } from 'wallet/src/features/dataApi/balances'
type WalletBalanceProps = {
......
import { ImpactFeedbackStyle } from 'expo-haptics'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { Flex, Shine, Text, TouchableArea } from 'ui/src'
import { Flex, Shine, Text, TouchableArea, isWeb } from 'ui/src'
import { NumberType } from 'utilities/src/format/types'
import { TokenLogo } from 'wallet/src/components/CurrencyLogo/TokenLogo'
import { RelativeChange } from 'wallet/src/components/text/RelativeChange'
......
......@@ -8,7 +8,6 @@ import {
Platform,
TextInputFocusEventData,
} from 'react-native'
import { isWeb } from 'tamagui'
import {
AnimatePresence,
Button,
......@@ -19,6 +18,7 @@ import {
SpaceTokens,
Text,
TouchableArea,
isWeb,
useDeviceDimensions,
} from 'ui/src'
import { fonts, iconSizes, spacing } from 'ui/src/theme'
......
......@@ -2,8 +2,7 @@ import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { FadeInUp, FadeOut } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Button, Flex, Text, useDeviceDimensions, useMedia } from 'ui/src'
import { AnimatedFlex, Button, Flex, isWeb, Text, useDeviceDimensions, useMedia } from 'ui/src'
import { BackArrow } from 'ui/src/components/icons/BackArrow'
import { fonts, iconSizes } from 'ui/src/theme'
import { NumberType } from 'utilities/src/format/types'
......
import { FunctionComponent, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { SvgProps } from 'react-native-svg'
import { isWeb } from 'tamagui'
import { Icons } from 'ui/src'
import { Icons, isWeb } from 'ui/src'
import { useSwapFormContext } from 'wallet/src/features/transactions/contexts/SwapFormContext'
import { useSwapTxContext } from 'wallet/src/features/transactions/contexts/SwapTxContext'
import { useSwapWarnings } from 'wallet/src/features/transactions/hooks/useSwapWarnings'
......
......@@ -2,7 +2,7 @@ import { useNetInfo } from '@react-native-community/netinfo'
import { Percent } from '@uniswap/sdk-core'
import _ from 'lodash'
import { TFunction } from 'react-i18next'
import { isWeb } from 'tamagui'
import { isWeb } from 'ui/src'
import { formatPriceImpact } from 'utilities/src/format/formatPriceImpact'
import { useMemoCompare } from 'utilities/src/react/hooks'
import {
......
import { CurrencyAmount, NativeCurrency } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { isWeb } from 'ui/src'
import { useOnChainNativeCurrencyBalance } from 'wallet/src/features/portfolio/api'
import { DerivedSwapInfo } from 'wallet/src/features/transactions/swap/types'
import { CurrencyField } from 'wallet/src/features/transactions/transactionState/types'
......
import { useCallback, useState } from 'react'
import { Keyboard } from 'react-native'
import { FadeIn, FadeOut } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Flex, Icons, Text, TouchableArea, useSporeColors } from 'ui/src'
import { AnimatedFlex, Flex, Icons, isWeb, Text, TouchableArea, useSporeColors } from 'ui/src'
import { iconSizes } from 'ui/src/theme'
import { NumberType } from 'utilities/src/format/types'
import { useUSDValue } from 'wallet/src/features/gas/hooks'
......
import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from 'react'
import { isWeb } from 'tamagui'
import { isWeb } from 'ui/src'
import { Trace } from 'utilities/src/telemetry/trace/Trace'
import { BottomSheetModal } from 'wallet/src/components/modals/BottomSheetModal'
import { FEATURE_FLAGS } from 'wallet/src/features/experiments/constants'
......
/* eslint-disable complexity */
import { useCallback, useMemo } from 'react'
import { TFunction, useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { Button, Flex, Icons, Text } from 'ui/src'
import { Button, Flex, Icons, Text, isWeb } from 'ui/src'
import { Trace } from 'utilities/src/telemetry/trace/Trace'
import {
selectHasSubmittedHoldToSwap,
......
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard } from 'react-native'
import { isWeb } from 'tamagui'
import { Flex, Icons, Text, TouchableArea, useSporeColors } from 'ui/src'
import { Flex, Icons, isWeb, Text, TouchableArea, useSporeColors } from 'ui/src'
import EyeIcon from 'ui/src/assets/icons/eye.svg'
import SettingsIcon from 'ui/src/assets/icons/settings.svg'
import XIcon from 'ui/src/assets/icons/x.svg'
......
......@@ -11,8 +11,7 @@ import {
useDerivedValue,
withTiming,
} from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Flex, Icons, Text, TouchableArea, useSporeColors } from 'ui/src'
import { AnimatedFlex, Flex, Icons, Text, TouchableArea, isWeb, useSporeColors } from 'ui/src'
import { iconSizes, spacing } from 'ui/src/theme'
import { NumberType } from 'utilities/src/format/types'
import { Trace } from 'utilities/src/telemetry/trace/Trace'
......
......@@ -26,8 +26,7 @@ import {
import { OnShowSwapFeeInfo } from 'wallet/src/features/transactions/TransactionDetails/SwapFee'
import { ElementName, ModalName } from 'wallet/src/telemetry/constants'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Button, Flex, Separator } from 'ui/src'
import { AnimatedFlex, Button, Flex, isWeb, Separator } from 'ui/src'
import { BackArrow } from 'ui/src/components/icons/BackArrow'
import { iconSizes } from 'ui/src/theme'
import { pushNotification } from 'wallet/src/features/notifications/slice'
......
import { Currency } from '@uniswap/sdk-core'
import { useCallback } from 'react'
import { isWeb } from 'tamagui'
import { isWeb } from 'ui/src'
import { flowToModalName } from 'wallet/src/components/TokenSelector/flowToModalName'
import {
TokenSelector,
......
import { useTranslation } from 'react-i18next'
import { isWeb } from 'tamagui'
import { Button, Flex, Icons, Text, useSporeColors } from 'ui/src'
import { Button, Flex, Icons, Text, isWeb, useSporeColors } from 'ui/src'
import { iconSizes } from 'ui/src/theme'
import { NumberType } from 'utilities/src/format/types'
import { CurrencyLogo } from 'wallet/src/components/CurrencyLogo/CurrencyLogo'
......
......@@ -5,8 +5,16 @@ import { impactAsync } from 'expo-haptics'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import { AnimatedFlex, Button, Flex, Icons, Text, TouchableArea, useSporeColors } from 'ui/src'
import {
AnimatedFlex,
Button,
Flex,
Icons,
Text,
TouchableArea,
isWeb,
useSporeColors,
} from 'ui/src'
import AlertTriangleIcon from 'ui/src/assets/icons/alert-triangle.svg'
import { fonts, iconSizes, spacing } from 'ui/src/theme'
import { NumberType } from 'utilities/src/format/types'
......
import { providers } from 'ethers'
import { Statsig } from 'statsig-react-native'
import { isWeb } from 'tamagui'
import { call, select } from 'typed-redux-saga'
import { isWeb } from 'ui/src'
import { logger } from 'utilities/src/logger/logger'
import { RPCType } from 'wallet/src/constants/chains'
import { FEATURE_FLAGS } from 'wallet/src/features/experiments/constants'
......
......@@ -5,7 +5,6 @@ import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard, LayoutChangeEvent, StyleSheet } from 'react-native'
import { FadeIn, FadeOut, FadeOutDown } from 'react-native-reanimated'
import { isWeb } from 'tamagui'
import {
AnimatedFlex,
Button,
......@@ -13,6 +12,7 @@ import {
Icons,
Text,
TouchableArea,
isWeb,
useDeviceDimensions,
useSporeColors,
} from 'ui/src'
......
......@@ -34,6 +34,7 @@
"{{what}} to {{recipient}}": "{{what}} to {{recipient}}",
"<0>Allow {dapp.name} to use up to<3> {readablePermitAmount} </3>{permitCurrency?.symbol}?</0>": "<0>Allow {dapp.name} to use up to<3> {readablePermitAmount} </3>{permitCurrency?.symbol}?</0>",
"<0>Allow <1>{dapp.name}</1> to use your {permitCurrency?.symbol}?</0>": "<0>Allow <1>{dapp.name}</1> to use your {permitCurrency?.symbol}?</0>",
"<0>This isn’t your currently active wallet.</0><1>Make sure it’s the right one</1>": "<0>This isn’t your currently active wallet.</0><1>Make sure it’s the right one</1>",
"<0>You need more <2>{{currencySymbol}}</2> to cover the network cost for this transaction.</0>": "<0>You need more <2>{{currencySymbol}}</2> to cover the network cost for this transaction.</0>",
"<0>You’re removing <2>{{wallet}}</2></0>": "<0>You’re removing <2>{{wallet}}</2></0>",
"<0>You’re removing your <2>recovery phrase</2></0>": "<0>You’re removing your <2>recovery phrase</2></0>",
......@@ -629,7 +630,6 @@
"This address is blocked on Uniswap Wallet because it is associated with one or more blocked activities. If you believe this is an error, please email compliance@uniswap.org.": "This address is blocked on Uniswap Wallet because it is associated with one or more blocked activities. If you believe this is an error, please email compliance@uniswap.org.",
"This is a {text.toLowerCase()} password": "This is a {text.toLowerCase()} password",
"This is a view-only wallet": "This is a view-only wallet",
"This is not your active wallet": "This is not your active wallet",
"This is the cost to process your transaction on the blockchain. Uniswap does not receive any share of these fees.": "This is the cost to process your transaction on the blockchain. Uniswap does not receive any share of these fees.",
"This is your personal space for tokens, NFTs, and all of your trades. Finish setting it up to keep your funds safe.": "This is your personal space for tokens, NFTs, and all of your trades. Finish setting it up to keep your funds safe.",
"This is your unique name that anyone can send crypto to.": "This is your unique name that anyone can send crypto to.",
......
......@@ -109,8 +109,7 @@
"./apps/next/.next/**"
],
"dependsOn": [
"^build",
"utilities#typecheck"
"^build"
]
},
"storybook#build": {
......
......@@ -44895,7 +44895,6 @@ __metadata:
redux-saga: 1.2.2
redux-saga-test-plan: 4.0.4
statsig-react-native: 4.11.0
tamagui: 1.89.26
typechain: 5.2.0
typed-redux-saga: 1.5.0
typescript: 5.3.3
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