import { SessionTypes } from '@walletconnect/types'
import { getSdkError } from '@walletconnect/utils'
import { Web3WalletTypes } from '@walletconnect/web3wallet'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Text, View } from 'react-native'
import InLineNotification, { NotificationVariant } from 'src/components/InLineNotification'
import { useDispatch, useSelector } from 'src/redux/hooks'
import { SentryTransactionHub } from 'src/sentry/SentryTransactionHub'
import { SentryTransaction } from 'src/sentry/SentryTransactions'
import { NETWORK_NAMES } from 'src/shared/conts'
import Colors from 'src/styles/colors'
import { typeScale } from 'src/styles/fonts'
import { Spacing } from 'src/styles/styles'
import { acceptSession, denySession } from 'src/walletConnect/actions'
import { isSupportedAction, isSupportedEvent } from 'src/walletConnect/constants'
import RequestContent, {
RequestDetail,
useDappMetadata,
} from 'src/walletConnect/screens/RequestContent'
import { walletConnectChainIdToNetworkId } from 'src/web3/networkConfig'
import { currentAccountSelector } from 'src/web3/selectors'
export type SessionRequestProps = {
version: 2
pendingSession: Web3WalletTypes.EventArguments['session_proposal']
namespacesToApprove: SessionTypes.Namespaces | null
supportedChains: string[]
}
// do not destructure props or else the type inference is lost
function SessionRequest({
pendingSession,
namespacesToApprove,
supportedChains,
}: SessionRequestProps) {
const { metadata } = pendingSession.params.proposer
const { t } = useTranslation()
const dispatch = useDispatch()
const address = useSelector(currentAccountSelector)
const { dappName, dappImageUrl } = useDappMetadata(metadata)
const requestDetails: RequestDetail[] = [
{
label: t('address'),
value: address,
},
]
const matchedSupportedChains = (namespacesToApprove?.['eip155']?.chains ?? []).filter((chainId) =>
supportedChains.includes(chainId)
)
const networkNames = matchedSupportedChains
.map((chain) => NETWORK_NAMES[walletConnectChainIdToNetworkId[chain]])
.sort()
if (networkNames.length > 0) {
requestDetails.push({
label: t('walletConnectRequest.networksList'),
value: ,
})
}
const supportedNetworkNames = supportedChains
.map((chain) => NETWORK_NAMES[walletConnectChainIdToNetworkId[chain]])
.join(', ')
if (!namespacesToApprove) {
// We couldn't build an namespace to approve, so we reject the session, showing the reason
// Note: for now it can only be because it's not an EVM chain
return (
{
dispatch(denySession(pendingSession, getSdkError('UNSUPPORTED_NAMESPACE_KEY')))
}}
dappName={dappName}
dappImageUrl={dappImageUrl}
title={t('connectToWallet', { dappName })}
description={t('shareInfo')}
testId="WalletConnectSessionRequest"
>
)
}
return (
{
SentryTransactionHub.startTransaction(SentryTransaction.wallet_connect_connection)
dispatch(acceptSession(pendingSession, namespacesToApprove))
}}
onDeny={() => {
dispatch(denySession(pendingSession, getSdkError('USER_REJECTED')))
}}
dappName={dappName}
dappImageUrl={dappImageUrl}
title={t('connectToWallet', { dappName })}
description={t('shareInfo')}
requestDetails={requestDetails}
testId="WalletConnectSessionRequest"
>
)
}
function NamespacesWarning({
namespacesToApprove,
supportedChains,
supportedNetworkNames,
dappName,
}: {
namespacesToApprove: SessionTypes.Namespaces
supportedChains: string[]
supportedNetworkNames: string
dappName: string
}) {
const { t } = useTranslation()
let title: string | null = null
let description: string | null = null
const eip155NamespaceToApprove = namespacesToApprove['eip155']
const supportedChainsToApprove = (eip155NamespaceToApprove?.chains ?? []).filter((chainId) =>
supportedChains.includes(chainId)
)
const unsupportedMethods = (eip155NamespaceToApprove?.methods ?? []).filter(
(method) => !isSupportedAction(method)
)
const unsupportedEvents = (eip155NamespaceToApprove?.events ?? []).filter(
(event) => !isSupportedEvent(event)
)
if (supportedChainsToApprove.length === 0) {
title = t('walletConnectRequest.session.warnUnsupportedChains.title', { dappName })
description = t('walletConnectRequest.session.warnUnsupportedChains.descriptionV1_74', {
dappName,
supportedNetworkNames,
count: supportedChains.length,
})
} else if (unsupportedMethods.length > 0) {
title = t('walletConnectRequest.session.warnSomeUnsupportedMethods.title', { dappName })
description = t('walletConnectRequest.session.warnSomeUnsupportedMethods.description', {
dappName,
})
} else if (unsupportedEvents.length > 0) {
title = t('walletConnectRequest.session.warnSomeUnsupportedEvents.title', { dappName })
description = t('walletConnectRequest.session.warnSomeUnsupportedEvents.description', {
dappName,
})
}
if (!title || !description) {
return null
}
return (
)
}
function NetworkChips({ networkNames }: { networkNames: string[] }) {
return (
{networkNames.map((networkName) => (
{networkName}
))}
)
}
const styles = StyleSheet.create({
warning: {
marginBottom: Spacing.Thick24,
},
networkChipsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: Spacing.Tiny4,
},
networkChip: {
...typeScale.labelXSmall,
backgroundColor: Colors.backgroundTertiary,
paddingVertical: Spacing.Tiny4,
paddingHorizontal: Spacing.Smallest8,
borderRadius: 8,
overflow: 'hidden',
},
})
export default SessionRequest