Skip to content

Commit

Permalink
fix: address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
iamacook committed Sep 8, 2023
1 parent bbe73f4 commit a115c14
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,14 @@ export const GlobalPushNotifications = (): ReactElement | null => {
<Grid container>
<Grid item xs={12} display="flex" alignItems="center" justifyContent="space-between" mb={1}>
<Typography variant="h4" fontWeight={700} display="inline">
My Safes ({totalNotifiableSafes})
My Safes Accounts ({totalNotifiableSafes})
</Typography>

<div>
{totalSignaturesRequired > 0 && (
<Typography display="inline" mr={1}>
We&apos;ll ask you to verify with your signature {totalSignaturesRequired} times
<Typography display="inline" mr={2}>
We&apos;ll ask you to verify your ownership of {totalSignaturesRequired} Safe Account
{totalSignaturesRequired > 1 ? 's' : ''} with your signature
</Typography>
)}

Expand Down Expand Up @@ -358,7 +359,10 @@ export const GlobalPushNotifications = (): ReactElement | null => {
<ListItemIcon className={css.icon}>
<Checkbox edge="start" checked={isChainSelected} disableRipple />
</ListItemIcon>
<ListItemText primary={`${chain?.chainName} Safes`} primaryTypographyProps={{ variant: 'h5' }} />
<ListItemText
primary={`${chain?.chainName} Safe Accounts`}
primaryTypographyProps={{ variant: 'h5' }}
/>
</ListItemButton>
</ListItem>

Expand Down
2 changes: 1 addition & 1 deletion src/components/settings/PushNotifications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export const PushNotifications = (): ReactElement => {

<Paper className={css.globalInfo} variant="outlined">
<Typography variant="body2">
Want to setup notifications for different or all Safes? You can do so in your{' '}
Want to setup notifications for different or all Safe Accounts? You can do so in your{' '}
<Link href={AppRoutes.settings.notifications} passHref legacyBehavior>
<MuiLink>global preferences</MuiLink>
</Link>
Expand Down
161 changes: 161 additions & 0 deletions src/service-workers/firebase-messaging/notification-mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Be careful what you import here as it will increase the service worker bundle size

import { formatUnits } from '@ethersproject/units' // Increases bundle significantly but unavoidable
import { getBalances } from '@safe-global/safe-gateway-typescript-sdk'
import type { ChainInfo, TokenInfo } from '@safe-global/safe-gateway-typescript-sdk'

import { WebhookType } from './webhook-types'
import type { WebhookEvent } from './webhook-types'

type PushNotificationsMap<T extends WebhookEvent = WebhookEvent> = {
[P in T['type']]: (
data: Extract<T, { type: P }>,
chain?: ChainInfo,
) => Promise<{ title: string; body: string }> | { title: string; body: string } | null
}

const getChainName = (chainId: string, chain?: ChainInfo): string => {
return chain?.chainName ?? `chain ${chainId}`
}

const getCurrencyName = (chain?: ChainInfo): string => {
return chain?.nativeCurrency?.name ?? 'Ether'
}

const getCurrencySymbol = (chain?: ChainInfo): string => {
return chain?.nativeCurrency?.symbol ?? 'ETH'
}

const getTokenInfo = async (
chainId: string,
safeAddress: string,
tokenAddress: string,
tokenValue?: string,
): Promise<{ symbol: string; value: string; name: string }> => {
const DEFAULT_CURRENCY = 'USD'

const DEFAULT_INFO = {
symbol: 'tokens',
value: 'some',
name: 'Token',
}

let tokenInfo: TokenInfo | undefined

try {
const balances = await getBalances(chainId, safeAddress, DEFAULT_CURRENCY)
tokenInfo = balances.items.find((token) => token.tokenInfo.address === tokenAddress)?.tokenInfo
} catch {
// Swallow error
}

if (!tokenInfo) {
return DEFAULT_INFO
}

const symbol = tokenInfo?.symbol ?? DEFAULT_INFO.symbol
const value = tokenValue && tokenInfo ? formatUnits(tokenValue, tokenInfo.decimals).toString() : DEFAULT_INFO.value
const name = tokenInfo?.name ?? DEFAULT_INFO.name

return {
symbol,
value,
name,
}
}

const shortenAddress = (address: string, length = 4): string => {
if (!address) {
return ''
}

return `${address.slice(0, length + 2)}...${address.slice(-length)}`
}

export const Notifications: PushNotificationsMap = {
[WebhookType.NEW_CONFIRMATION]: ({ address, owner, safeTxHash, chainId }, chain) => {
return {
title: 'Transaction confirmation',
body: `Safe ${shortenAddress(address)} on ${getChainName(
chainId,
chain,
)} has a new confirmation from ${shortenAddress(owner)} on transaction ${shortenAddress(safeTxHash)}.`,
}
},
[WebhookType.EXECUTED_MULTISIG_TRANSACTION]: ({ address, failed, txHash, chainId }, chain) => {
const didFail = failed === 'true'
return {
title: `Transaction ${didFail ? 'failed' : 'executed'}`,
body: `Safe ${shortenAddress(address)} on ${getChainName(chainId, chain)} ${
didFail ? 'failed to execute' : 'executed'
} transaction ${shortenAddress(txHash)}.`,
}
},
[WebhookType.PENDING_MULTISIG_TRANSACTION]: ({ address, safeTxHash, chainId }, chain) => {
return {
title: 'Pending transaction',
body: `Safe ${shortenAddress(address)} on ${getChainName(
chainId,
chain,
)} has a pending transaction ${shortenAddress(safeTxHash)}.`,
}
},
[WebhookType.INCOMING_ETHER]: ({ address, txHash, value, chainId }, chain) => {
return {
title: `${getCurrencyName(chain)} received`,
body: `Safe ${shortenAddress(address)} on ${getChainName(chainId, chain)} received ${formatUnits(
value,
chain?.nativeCurrency?.decimals,
).toString()} ${getCurrencySymbol(chain)} in transaction ${shortenAddress(txHash)}.`,
}
},
[WebhookType.OUTGOING_ETHER]: ({ address, txHash, value, chainId }, chain) => {
return {
title: `${getCurrencyName(chain)} sent`,
body: `Safe ${shortenAddress(address)} on ${getChainName(chainId, chain)} sent ${formatUnits(
value,
chain?.nativeCurrency?.decimals,
).toString()} ${getCurrencySymbol(chain)} in transaction ${shortenAddress(txHash)}.`,
}
},
[WebhookType.INCOMING_TOKEN]: async ({ address, txHash, tokenAddress, value, chainId }, chain) => {
const token = await getTokenInfo(chainId, address, tokenAddress, value)
return {
title: `${token.name} received`,
body: `Safe ${shortenAddress(address)} on ${getChainName(chainId, chain)} received ${token.value} ${
token.symbol
} in transaction ${shortenAddress(txHash)}.`,
}
},
[WebhookType.OUTGOING_TOKEN]: async ({ address, txHash, tokenAddress, value, chainId }, chain) => {
const token = await getTokenInfo(chainId, address, tokenAddress, value)
return {
title: `${token.name} sent`,
body: `Safe ${shortenAddress(address)} on ${getChainName(chainId, chain)} sent ${token.value} ${
token.symbol
} in transaction ${shortenAddress(txHash)}.`,
}
},
[WebhookType.MODULE_TRANSACTION]: ({ address, module, txHash, chainId }, chain) => {
return {
title: 'Module transaction',
body: `Safe ${shortenAddress(address)} on ${getChainName(
chainId,
chain,
)} executed a module transaction ${shortenAddress(txHash)} from module ${shortenAddress(module)}.`,
}
},
[WebhookType.CONFIRMATION_REQUEST]: ({ address, safeTxHash, chainId }, chain) => {
return {
title: 'Confirmation request',
body: `Safe ${shortenAddress(address)} on ${getChainName(
chainId,
chain,
)} has a new confirmation request for transaction ${shortenAddress(safeTxHash)}.`,
}
},
[WebhookType.SAFE_CREATED]: () => {
// We do not preemptively subscribe to Safes before they are created
return null
},
}
Loading

0 comments on commit a115c14

Please sign in to comment.