Skip to content

Commit

Permalink
Fix: avoid fetching Safe Apps on all pages (#3254)
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh authored Feb 20, 2024
1 parent 2a1cb02 commit 129b1b1
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,50 +1,23 @@
import * as nextRouter from 'next/router'
import * as nextNav from 'next/navigation'
import useChainId from '@/hooks/useChainId'
import { render, waitFor } from '@/tests/test-utils'
import { SafeAppAccessPolicyTypes } from '@safe-global/safe-gateway-typescript-sdk'
import SafeTokenWidget from '..'
import { toBeHex } from 'ethers'
import { AppRoutes } from '@/config/routes'
import useSafeTokenAllocation, { useSafeVotingPower } from '@/hooks/useSafeTokenAllocation'

const MOCK_GOVERNANCE_APP_URL = 'https://mock.governance.safe.global'

jest.mock('@/hooks/useChainId', () => jest.fn(() => '1'))

jest.mock('@/hooks/useSafeTokenAllocation')

jest.mock(
'@/hooks/safe-apps/useRemoteSafeApps',
jest.fn(() => ({
useRemoteSafeApps: () => [
[
{
id: 61,
url: MOCK_GOVERNANCE_APP_URL,
chainIds: ['4'],
name: 'Safe {DAO} Governance',
description: '',
iconUrl: '',
tags: ['safe-dao-governance-app'],
accessControl: {
type: SafeAppAccessPolicyTypes.NoRestrictions,
},
},
],
],
})),
)

describe('SafeTokenWidget', () => {
const fakeSafeAddress = toBeHex('0x1', 20)
beforeEach(() => {
jest.restoreAllMocks()
jest.spyOn(nextRouter, 'useRouter').mockImplementation(
jest.spyOn(nextNav, 'useSearchParams').mockImplementation(
() =>
({
query: {
safe: fakeSafeAddress,
},
get: () => fakeSafeAddress,
} as any),
)
})
Expand Down Expand Up @@ -90,7 +63,9 @@ describe('SafeTokenWidget', () => {
const result = render(<SafeTokenWidget />)
await waitFor(() => {
expect(result.baseElement).toContainHTML(
`href="${AppRoutes.apps.open}?safe=${fakeSafeAddress}&appUrl=${encodeURIComponent(MOCK_GOVERNANCE_APP_URL)}"`,
`href="${AppRoutes.apps.open}?safe=${fakeSafeAddress}&appUrl=${encodeURIComponent(
'https://safe-dao-governance.dev.5afe.dev',
)}`,
)
})
})
Expand Down
34 changes: 10 additions & 24 deletions src/components/common/SafeTokenWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { SafeAppsTag, SAFE_TOKEN_ADDRESSES } from '@/config/constants'
import { IS_PRODUCTION, SAFE_TOKEN_ADDRESSES } from '@/config/constants'
import { AppRoutes } from '@/config/routes'
import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps'
import useChainId from '@/hooks/useChainId'
import useSafeTokenAllocation, { useSafeVotingPower, type Vesting } from '@/hooks/useSafeTokenAllocation'
import { OVERVIEW_EVENTS } from '@/services/analytics'
import { formatVisualAmount } from '@/utils/formatters'
import { Box, Button, ButtonBase, Skeleton, Tooltip, Typography } from '@mui/material'
import Link from 'next/link'
import { useRouter } from 'next/router'
import type { UrlObject } from 'url'
import { useSearchParams } from 'next/navigation'
import Track from '../Track'
import SafeTokenIcon from '@/public/images/common/safe-token.svg'
import css from './styles.module.css'
Expand Down Expand Up @@ -36,13 +34,11 @@ const canRedeemSep5Airdrop = (allocation?: Vesting[]): boolean => {
return !sep5Allocation.isRedeemed && !sep5Allocation.isExpired
}

const SEP5_DEADLINE = '27.10'
const GOVERNANCE_APP_URL = IS_PRODUCTION ? 'https://governance.safe.global' : 'https://safe-dao-governance.dev.5afe.dev'

const SafeTokenWidget = () => {
const chainId = useChainId()
const router = useRouter()
const [apps] = useRemoteSafeApps(SafeAppsTag.SAFE_GOVERNANCE_APP)
const governanceApp = apps?.[0]
const query = useSearchParams()

const [allocationData, , allocationDataLoading] = useSafeTokenAllocation()
const [allocation, , allocationLoading] = useSafeVotingPower(allocationData)
Expand All @@ -52,30 +48,20 @@ const SafeTokenWidget = () => {
return null
}

const url: UrlObject | undefined = governanceApp
? {
pathname: AppRoutes.apps.open,
query: { safe: router.query.safe, appUrl: governanceApp.url },
}
: undefined
const url = {
pathname: AppRoutes.apps.open,
query: { safe: query.get('safe'), appUrl: GOVERNANCE_APP_URL },
}

const canRedeemSep5 = canRedeemSep5Airdrop(allocationData)
const flooredSafeBalance = formatVisualAmount(allocation || BigInt(0), TOKEN_DECIMALS, 2)

return (
<Box className={css.container}>
<Tooltip
title={
url
? canRedeemSep5
? `Claim any amount until ${SEP5_DEADLINE} to be eligible!`
: `Open ${governanceApp?.name}`
: ''
}
>
<Tooltip title="Go to Safe{DAO} Governance">
<span>
<Track {...OVERVIEW_EVENTS.SAFE_TOKEN_WIDGET}>
<Link href={url || ''} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<ButtonBase
aria-describedby="safe-token-widget"
className={classnames(css.tokenButton, { [css.sep5]: canRedeemSep5 })}
Expand Down
11 changes: 9 additions & 2 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ export const CYPRESS_MNEMONIC = process.env.NEXT_PUBLIC_CYPRESS_MNEMONIC || ''
// Safe Token
export const SAFE_TOKEN_ADDRESSES: { [chainId: string]: string } = {
[chains.eth]: '0x5aFE3855358E112B5647B952709E6165e1c1eEEe',
[chains.rin]: '0xCFf1b0FdE85C102552D1D96084AF148f478F964A',
[chains.gor]: '0x61fD3b6d656F39395e32f46E2050953376c3f5Ff',
}

// Safe Apps
Expand Down Expand Up @@ -60,6 +58,15 @@ export enum SafeAppsTag {
ONRAMP = 'onramp',
}

export const WC_APP_PROD = {
id: 111,
url: 'https://apps-portal.safe.global/wallet-connect',
}
export const WC_APP_DEV = {
id: 25,
url: 'https://safe-apps.dev.5afe.dev/wallet-connect',
}

// Safe Gelato relay service
export const SAFE_RELAY_SERVICE_URL_PRODUCTION =
process.env.NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_PRODUCTION || 'https://safe-client.safe.global/v1/relay'
Expand Down
20 changes: 2 additions & 18 deletions src/features/walletconnect/__tests__/WalletConnectContext.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,6 @@ import * as useSafeWalletProvider from '@/services/safe-wallet-provider/useSafeW
jest.mock('../services/WalletConnectWallet')
jest.mock('@/services/safe-wallet-provider/useSafeWalletProvider')

jest.mock('@/hooks/safe-apps/useRemoteSafeApps', () => ({
useRemoteSafeApps: () => [
[
{
id: 111,
url: 'https://apps-portal.safe.global/wallet-connect',
name: 'WC App',
iconUrl: 'https://test.com/icon.png',
description: 'Test App Description',
},
],
undefined,
false,
],
}))

const TestComponent = () => {
const { walletConnect, error } = useContext(WalletConnectContext)
return (
Expand Down Expand Up @@ -426,10 +410,10 @@ describe('WalletConnectProvider', () => {
1,
{ method: 'fake', params: [] },
{
id: 111,
id: 25,
name: 'name',
description: 'description',
url: 'https://apps-portal.safe.global/wallet-connect',
url: 'https://safe-apps.dev.5afe.dev/wallet-connect',
iconUrl: 'iconUrl',
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { formatJsonRpcError } from '@walletconnect/jsonrpc-utils'
import useSafeInfo from '@/hooks/useSafeInfo'
import useSafeWalletProvider from '@/services/safe-wallet-provider/useSafeWalletProvider'
import { asError } from '@/services/exceptions/utils'
import { IS_PRODUCTION } from '@/config/constants'
import { SafeAppsTag } from '@/config/constants'
import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps'
import { IS_PRODUCTION, WC_APP_DEV, WC_APP_PROD } from '@/config/constants'
import { getPeerName, stripEip155Prefix } from '@/features/walletconnect/services/utils'
import { trackRequest } from '@/features/walletconnect//services/tracking'
import { wcPopupStore } from '@/features/walletconnect/components'
Expand All @@ -18,18 +16,15 @@ enum Errors {
WRONG_CHAIN = '%%dappName%% made a request on a different chain than the one you are connected to',
}

const WalletConnectSafeApp = IS_PRODUCTION ? WC_APP_PROD : WC_APP_DEV

const walletConnectSingleton = new WalletConnectWallet()

const getWrongChainError = (dappName: string): Error => {
const message = Errors.WRONG_CHAIN.replace('%%dappName%%', dappName)
return new Error(message)
}

const useWalletConnectApp = () => {
const [matchingApps] = useRemoteSafeApps(SafeAppsTag.WALLET_CONNECT)
return matchingApps?.[0]
}

export const WalletConnectProvider = ({ children }: { children: ReactNode }) => {
const {
safe: { chainId },
Expand All @@ -40,7 +35,6 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) =>
const setOpen = wcPopupStore.setStore
const [error, setError] = useState<Error | null>(null)
const safeWalletProvider = useSafeWalletProvider()
const wcApp = useWalletConnectApp()

// Init WalletConnect
useEffect(() => {
Expand Down Expand Up @@ -88,8 +82,8 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) =>

// Get response from Safe Wallet Provider
return safeWalletProvider.request(event.id, event.params.request, {
id: wcApp?.id || -1,
url: wcApp?.url || '',
id: WalletConnectSafeApp.id,
url: WalletConnectSafeApp.url,
name: getPeerName(session.peer) || 'Unknown dApp',
description: session.peer.metadata.description,
iconUrl: session.peer.metadata.icons[0],
Expand All @@ -105,7 +99,7 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) =>
setError(asError(e))
}
})
}, [walletConnect, chainId, safeWalletProvider, wcApp])
}, [walletConnect, chainId, safeWalletProvider])

return (
<WalletConnectContext.Provider value={{ walletConnect, error, setError, open, setOpen }}>
Expand Down
2 changes: 1 addition & 1 deletion src/services/analytics/__tests__/tx-tracking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ describe('getTransactionTrackingType', () => {
type: TransactionInfoType.CUSTOM,
},
safeAppInfo: {
url: 'https://apps-portal.safe.global/wallet-connect',
url: 'https://safe-apps.dev.5afe.dev/wallet-connect',
},
} as unknown)

Expand Down
7 changes: 2 additions & 5 deletions src/utils/gateway.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { WC_APP_PROD, WC_APP_DEV } from '@/config/constants'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'

export const _replaceTemplate = (uri: string, data: Record<string, string>): string => {
Expand Down Expand Up @@ -28,9 +29,5 @@ export const getExplorerLink = (
}

export const isWalletConnectSafeApp = (url: string): boolean => {
const WC_APP_URLS = [
'https://apps-portal.safe.global/wallet-connect',
'https://safe-apps.dev.5afe.dev/wallet-connect',
]
return WC_APP_URLS.includes(url)
return url === WC_APP_PROD.url || url === WC_APP_DEV.url
}

0 comments on commit 129b1b1

Please sign in to comment.