diff --git a/src/components/settings/PushNotifications/logic.ts b/src/components/settings/PushNotifications/logic.ts index 2c22acce7d..8156b07194 100644 --- a/src/components/settings/PushNotifications/logic.ts +++ b/src/components/settings/PushNotifications/logic.ts @@ -4,7 +4,7 @@ import { DeviceType } from '@safe-global/safe-gateway-typescript-sdk/dist/types/ import type { RegisterNotificationsRequest } from '@safe-global/safe-gateway-typescript-sdk/dist/types/notifications' import type { Web3Provider } from '@ethersproject/providers' -import { FIREBASE_MESSAGING_SW_PATH, FIREBASE_VAPID_KEY } from '@/services/firebase/constants' +import { FIREBASE_MESSAGING_SW_PATH, FIREBASE_VAPID_KEY } from '@/services/firebase/firebase' import { trackEvent } from '@/services/analytics' import { PUSH_NOTIFICATION_EVENTS } from '@/services/analytics/events/push-notifications' import packageJson from '../../../../package.json' diff --git a/src/config/constants.ts b/src/config/constants.ts index 36bb02c093..a148aa3caa 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,12 +1,11 @@ import chains from './chains' -import { _GATEWAY_URL_PRODUCTION, _GATEWAY_URL_STAGING, _IS_PRODUCTION } from '@/services/firebase/constants' -// Imported from firebase service worker constants as we want to keep its budle size small -export const IS_PRODUCTION = _IS_PRODUCTION +export const IS_PRODUCTION = !!process.env.NEXT_PUBLIC_IS_PRODUCTION export const IS_DEV = process.env.NODE_ENV === 'development' -export const GATEWAY_URL_PRODUCTION = _GATEWAY_URL_PRODUCTION -export const GATEWAY_URL_STAGING = _GATEWAY_URL_STAGING +export const GATEWAY_URL_PRODUCTION = + process.env.NEXT_PUBLIC_GATEWAY_URL_PRODUCTION || 'https://safe-client.safe.global' +export const GATEWAY_URL_STAGING = process.env.NEXT_PUBLIC_GATEWAY_URL_STAGING || 'https://safe-client.staging.5afe.dev' // Magic numbers export const POLLING_INTERVAL = 15_000 diff --git a/src/hooks/useFirebaseNotifications.ts b/src/hooks/useFirebaseNotifications.ts index e1d2ebc5d9..6f835ed692 100644 --- a/src/hooks/useFirebaseNotifications.ts +++ b/src/hooks/useFirebaseNotifications.ts @@ -1,7 +1,7 @@ import { useEffect } from 'react' import { initializeFirebase } from '@/services/firebase/firebase' -import { FIREBASE_MESSAGING_SW_PATH } from '@/services/firebase/constants' +import { FIREBASE_MESSAGING_SW_PATH } from '@/services/firebase/firebase' export const useFirebaseNotifications = (): void => { // Register servicer worker diff --git a/src/services/firebase/constants.ts b/src/services/firebase/constants.ts deleted file mode 100644 index 95a0a3d694..0000000000 --- a/src/services/firebase/constants.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Refrain from importing outside of this folder to keep firebase-sw.js bundle small - -import type { FirebaseOptions } from 'firebase/app' - -// The following are re-exported in our constants file to avoid incorrect contants -export const _IS_PRODUCTION = !!process.env.NEXT_PUBLIC_IS_PRODUCTION - -export const _GATEWAY_URL_PRODUCTION = - process.env.NEXT_PUBLIC_GATEWAY_URL_PRODUCTION || 'https://safe-client.safe.global' -export const _GATEWAY_URL_STAGING = - process.env.NEXT_PUBLIC_GATEWAY_URL_STAGING || 'https://safe-client.staging.5afe.dev' - -// localStorage cannot be accessed in service workers so we reference the flag -export const _GATEWAY_URL = _IS_PRODUCTION ? _GATEWAY_URL_PRODUCTION : _GATEWAY_URL_STAGING - -export const FIREBASE_MESSAGING_SW_PATH = '/firebase-messaging-sw.js' - -const FIREBASE_API_KEY_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_API_KEY_PRODUCTION || '' -const FIREBASE_AUTH_DOMAIN_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN_PRODUCTION || '' -const FIREBASE_DATABASE_URL_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL_PRODUCTION || '' -const FIREBASE_PROJECT_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID_PRODUCTION || '' -const FIREBASE_STORAGE_BUCKET_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_PRODUCTION || '' -const FIREBASE_MESSAGING_SENDER_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID_PRODUCTION || '' -const FIREBASE_APP_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_APP_ID_PRODUCTION || '' -const FIREBASE_MEASUREMENT_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID_PRODUCTION || '' -const FIREBASE_VAPID_KEY_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION || '' - -const FIREBASE_API_KEY_STAGING = process.env.NEXT_PUBLIC_FIREBASE_API_KEY_STAGING || '' -const FIREBASE_AUTH_DOMAIN_STAGING = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN_STAGING || '' -const FIREBASE_DATABASE_URL_STAGING = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL_STAGING || '' -const FIREBASE_PROJECT_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID_STAGING || '' -const FIREBASE_STORAGE_BUCKET_STAGING = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_STAGING || '' -const FIREBASE_MESSAGING_SENDER_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID_STAGING || '' -const FIREBASE_APP_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_APP_ID_STAGING || '' -const FIREBASE_MEASUREMENT_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID_STAGING || '' -const FIREBASE_VAPID_KEY_STAGING = process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING || '' - -export const FIREBASE_VAPID_KEY = _IS_PRODUCTION ? FIREBASE_VAPID_KEY_PRODUCTION : FIREBASE_VAPID_KEY_STAGING - -export const FIREBASE_OPTIONS: FirebaseOptions = { - apiKey: _IS_PRODUCTION ? FIREBASE_API_KEY_PRODUCTION : FIREBASE_API_KEY_STAGING, - authDomain: _IS_PRODUCTION ? FIREBASE_AUTH_DOMAIN_PRODUCTION : FIREBASE_AUTH_DOMAIN_STAGING, - databaseURL: _IS_PRODUCTION ? FIREBASE_DATABASE_URL_PRODUCTION : FIREBASE_DATABASE_URL_STAGING, - projectId: _IS_PRODUCTION ? FIREBASE_PROJECT_ID_PRODUCTION : FIREBASE_PROJECT_ID_STAGING, - storageBucket: _IS_PRODUCTION ? FIREBASE_STORAGE_BUCKET_PRODUCTION : FIREBASE_STORAGE_BUCKET_STAGING, - messagingSenderId: _IS_PRODUCTION ? FIREBASE_MESSAGING_SENDER_ID_PRODUCTION : FIREBASE_MESSAGING_SENDER_ID_STAGING, - appId: _IS_PRODUCTION ? FIREBASE_APP_ID_PRODUCTION : FIREBASE_APP_ID_STAGING, - measurementId: _IS_PRODUCTION ? FIREBASE_MEASUREMENT_ID_PRODUCTION : FIREBASE_MEASUREMENT_ID_STAGING, -} as const diff --git a/src/services/firebase/firebase.ts b/src/services/firebase/firebase.ts index 22849b1a3c..b77557811d 100644 --- a/src/services/firebase/firebase.ts +++ b/src/services/firebase/firebase.ts @@ -1,9 +1,44 @@ // Refrain from importing outside of this folder to keep firebase-sw.js bundle small import { initializeApp } from 'firebase/app' -import type { FirebaseApp } from 'firebase/app' +import type { FirebaseApp, FirebaseOptions } from 'firebase/app' -import { FIREBASE_OPTIONS } from './constants' +const IS_PRODUCTION = !!process.env.NEXT_PUBLIC_IS_PRODUCTION + +export const FIREBASE_MESSAGING_SW_PATH = '/firebase-messaging-sw.js' + +const FIREBASE_API_KEY_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_API_KEY_PRODUCTION || '' +const FIREBASE_AUTH_DOMAIN_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN_PRODUCTION || '' +const FIREBASE_DATABASE_URL_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL_PRODUCTION || '' +const FIREBASE_PROJECT_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID_PRODUCTION || '' +const FIREBASE_STORAGE_BUCKET_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_PRODUCTION || '' +const FIREBASE_MESSAGING_SENDER_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID_PRODUCTION || '' +const FIREBASE_APP_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_APP_ID_PRODUCTION || '' +const FIREBASE_MEASUREMENT_ID_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID_PRODUCTION || '' +const FIREBASE_VAPID_KEY_PRODUCTION = process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION || '' + +const FIREBASE_API_KEY_STAGING = process.env.NEXT_PUBLIC_FIREBASE_API_KEY_STAGING || '' +const FIREBASE_AUTH_DOMAIN_STAGING = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN_STAGING || '' +const FIREBASE_DATABASE_URL_STAGING = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL_STAGING || '' +const FIREBASE_PROJECT_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID_STAGING || '' +const FIREBASE_STORAGE_BUCKET_STAGING = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_STAGING || '' +const FIREBASE_MESSAGING_SENDER_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID_STAGING || '' +const FIREBASE_APP_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_APP_ID_STAGING || '' +const FIREBASE_MEASUREMENT_ID_STAGING = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID_STAGING || '' +const FIREBASE_VAPID_KEY_STAGING = process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING || '' + +export const FIREBASE_VAPID_KEY = IS_PRODUCTION ? FIREBASE_VAPID_KEY_PRODUCTION : FIREBASE_VAPID_KEY_STAGING + +export const FIREBASE_OPTIONS: FirebaseOptions = { + apiKey: IS_PRODUCTION ? FIREBASE_API_KEY_PRODUCTION : FIREBASE_API_KEY_STAGING, + authDomain: IS_PRODUCTION ? FIREBASE_AUTH_DOMAIN_PRODUCTION : FIREBASE_AUTH_DOMAIN_STAGING, + databaseURL: IS_PRODUCTION ? FIREBASE_DATABASE_URL_PRODUCTION : FIREBASE_DATABASE_URL_STAGING, + projectId: IS_PRODUCTION ? FIREBASE_PROJECT_ID_PRODUCTION : FIREBASE_PROJECT_ID_STAGING, + storageBucket: IS_PRODUCTION ? FIREBASE_STORAGE_BUCKET_PRODUCTION : FIREBASE_STORAGE_BUCKET_STAGING, + messagingSenderId: IS_PRODUCTION ? FIREBASE_MESSAGING_SENDER_ID_PRODUCTION : FIREBASE_MESSAGING_SENDER_ID_STAGING, + appId: IS_PRODUCTION ? FIREBASE_APP_ID_PRODUCTION : FIREBASE_APP_ID_STAGING, + measurementId: IS_PRODUCTION ? FIREBASE_MEASUREMENT_ID_PRODUCTION : FIREBASE_MEASUREMENT_ID_STAGING, +} as const export const initializeFirebase = () => { const hasFirebaseOptions = Object.values(FIREBASE_OPTIONS).every(Boolean) diff --git a/src/services/firebase/notifications.ts b/src/services/firebase/notifications.ts index 609ffd9835..d46fbbcdba 100644 --- a/src/services/firebase/notifications.ts +++ b/src/services/firebase/notifications.ts @@ -6,14 +6,12 @@ import type { ChainInfo, ChainListResponse, SafeBalanceResponse } from '@safe-gl import type { MessagePayload } from 'firebase/messaging' import { AppRoutes } from '@/config/routes' // Has no internal imports -import { _GATEWAY_URL } from './constants' import { isWebhookEvent, WebhookType } from './webhooks' import { getSafeNotificationPrefsKey, createNotificationUuidIndexedDb } from './preferences' import type { WebhookEvent } from './webhooks' import type { NotificationPreferences, SafeNotificationPrefsKey } from './preferences' -// Export for formatters to keep bundle small -export const _shortenAddress = (address: string, length = 4): string => { +const shortenAddress = (address: string, length = 4): string => { if (!address) { return '' } @@ -42,12 +40,16 @@ export const shouldShowNotification = async (payload: MessagePayload): Promise => { - const ENDPOINT = `${_GATEWAY_URL}/v1/chains` + const ENDPOINT = `${GATEWAY_URL}/v1/chains` let chains: ChainListResponse | null = null @@ -68,7 +70,7 @@ const getTokenInfo = async ( tokenValue?: string, ): Promise<{ symbol: string; value: string; name: string }> => { const DEFAULT_CURRENCY = 'USD' - const ENDPOINT = `${_GATEWAY_URL}/v1/chains/${chainId}/safes/${safeAddress}/balances/${DEFAULT_CURRENCY}` + const ENDPOINT = `${GATEWAY_URL}/v1/chains/${chainId}/safes/${safeAddress}/balances/${DEFAULT_CURRENCY}` const DEFAULT_INFO = { symbol: 'tokens', @@ -144,24 +146,24 @@ export const _parseWebhookNotification = async ( [WebhookType.NEW_CONFIRMATION]: ({ address, owner, safeTxHash }) => { return { title: 'Transaction confirmation', - body: `Safe ${_shortenAddress(address)} on ${chainName} has a new confirmation from ${_shortenAddress( + body: `Safe ${shortenAddress(address)} on ${chainName} has a new confirmation from ${shortenAddress( owner, - )} on transaction ${_shortenAddress(safeTxHash)}.`, + )} on transaction ${shortenAddress(safeTxHash)}.`, } }, [WebhookType.EXECUTED_MULTISIG_TRANSACTION]: ({ address, failed, txHash }) => { const didFail = failed === 'true' return { title: `Transaction ${didFail ? 'failed' : 'executed'}`, - body: `Safe ${_shortenAddress(address)} on ${chainName} ${ + body: `Safe ${shortenAddress(address)} on ${chainName} ${ didFail ? 'failed to execute' : 'executed' - } transaction ${_shortenAddress(txHash)}.`, + } transaction ${shortenAddress(txHash)}.`, } }, [WebhookType.PENDING_MULTISIG_TRANSACTION]: ({ address, safeTxHash }) => { return { title: 'Pending transaction', - body: `Safe ${_shortenAddress(address)} on ${chainName} has a pending transaction ${_shortenAddress( + body: `Safe ${shortenAddress(address)} on ${chainName} has a pending transaction ${shortenAddress( safeTxHash, )}.`, } @@ -169,53 +171,53 @@ export const _parseWebhookNotification = async ( [WebhookType.INCOMING_ETHER]: ({ address, txHash, value }) => { return { title: `${currencyName} received`, - body: `Safe ${_shortenAddress(address)} on ${chainName} received ${formatUnits( + body: `Safe ${shortenAddress(address)} on ${chainName} received ${formatUnits( value, chain?.nativeCurrency?.decimals, - ).toString()} ${currencySymbol} in transaction ${_shortenAddress(txHash)}.`, + ).toString()} ${currencySymbol} in transaction ${shortenAddress(txHash)}.`, } }, [WebhookType.OUTGOING_ETHER]: ({ address, txHash, value }) => { return { title: `${currencyName} sent`, - body: `Safe ${_shortenAddress(address)} on ${chainName} sent ${formatUnits( + body: `Safe ${shortenAddress(address)} on ${chainName} sent ${formatUnits( value, chain?.nativeCurrency?.decimals, - ).toString()} ${currencySymbol} in transaction ${_shortenAddress(txHash)}.`, + ).toString()} ${currencySymbol} in transaction ${shortenAddress(txHash)}.`, } }, [WebhookType.INCOMING_TOKEN]: async ({ address, txHash, tokenAddress, value }) => { const token = await getTokenInfo(data.chainId, address, tokenAddress, value) return { title: `${token.name} received`, - body: `Safe ${_shortenAddress(address)} on ${chainName} received ${token.value} ${ + body: `Safe ${shortenAddress(address)} on ${chainName} received ${token.value} ${ token.symbol - } in transaction ${_shortenAddress(txHash)}.`, + } in transaction ${shortenAddress(txHash)}.`, } }, [WebhookType.OUTGOING_TOKEN]: async ({ address, txHash, tokenAddress, value }) => { const token = await getTokenInfo(data.chainId, address, tokenAddress, value) return { title: `${token.name} sent`, - body: `Safe ${_shortenAddress(address)} on ${chainName} sent ${token.value} ${ + body: `Safe ${shortenAddress(address)} on ${chainName} sent ${token.value} ${ token.symbol - } in transaction ${_shortenAddress(txHash)}.`, + } in transaction ${shortenAddress(txHash)}.`, } }, [WebhookType.MODULE_TRANSACTION]: ({ address, module, txHash }) => { return { title: 'Module transaction', - body: `Safe ${_shortenAddress(address)} on ${chainName} executed a module transaction ${_shortenAddress( + body: `Safe ${shortenAddress(address)} on ${chainName} executed a module transaction ${shortenAddress( txHash, - )} from module ${_shortenAddress(module)}.`, + )} from module ${shortenAddress(module)}.`, } }, [WebhookType.CONFIRMATION_REQUEST]: ({ address, safeTxHash }) => { return { title: 'Confirmation request', - body: `Safe ${_shortenAddress( + body: `Safe ${shortenAddress( address, - )} on ${chainName} has a new confirmation request for transaction ${_shortenAddress(safeTxHash)}.`, + )} on ${chainName} has a new confirmation request for transaction ${shortenAddress(safeTxHash)}.`, } }, [WebhookType.SAFE_CREATED]: () => { diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts index 7d3f619ac7..c5770232bd 100644 --- a/src/utils/formatters.ts +++ b/src/utils/formatters.ts @@ -51,7 +51,13 @@ export const safeParseUnits = (value: string, decimals: number | string = GWEI): } } -export { _shortenAddress as shortenAddress } from '@/services/firebase/notifications' +export const shortenAddress = (address: string, length = 4): string => { + if (!address) { + return '' + } + + return `${address.slice(0, length + 2)}...${address.slice(-length)}` +} export const shortenText = (text: string, length = 10, separator = '...'): string => { return `${text.slice(0, length)}${separator}`