Skip to content

Commit

Permalink
US-1964 WalletConnect sessions don't get erased when the wallet is re…
Browse files Browse the repository at this point in the history
…set (#900)

* fix: wc sessions are being pulled from the same storage, even for different address

* refactor: more effective solutions for removing WC sessions

* fix: return the WC2 key to MMKV storage

* fix: not being able to delete wc sessions

* fix: renaming the mmkv back to mmkv.default

* Added .toLowerCase() in the sign typed data resolver logic.

* Update WalletConnect2Context.tsx

* Update WalletConnect2Context.tsx

---------

Co-authored-by: Francis Rodriguez <[email protected]>
Co-authored-by: Jesse Clark <[email protected]>
  • Loading branch information
3 people authored Mar 29, 2024
1 parent f7139fe commit a62861d
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 52 deletions.
2 changes: 2 additions & 0 deletions src/redux/slices/settingsSlice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
import { addressToUse, Wallet } from 'shared/wallet'
import { createAppWallet, loadAppWallet } from 'shared/utils'
import { MMKVStorage } from 'storage/MMKVStorage'
import { deleteWCSessions } from 'screens/walletConnect/walletConnect2.utils'

import {
Bitcoin,
Expand Down Expand Up @@ -346,6 +347,7 @@ export const resetApp = createAsyncThunk(
thunkAPI.dispatch(setKeysExist(false))
resetMainStorage()
resetReduxStorage()
deleteWCSessions()
return 'deleted'
} catch (err) {
return thunkAPI.rejectWithValue(err)
Expand Down
56 changes: 32 additions & 24 deletions src/screens/walletConnect/WalletConnect2Context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { IWeb3Wallet } from '@walletconnect/web3wallet'
import { WalletConnectAdapter } from '@rsksmart/rif-wallet-adapters'

import { ChainID } from 'lib/eoaWallet'
import { createPendingTxFromTxResponse } from 'lib/utils'

import {
buildRskAllowedNamespaces,
Expand All @@ -21,7 +22,7 @@ import {
import { useAppDispatch, useAppSelector } from 'store/storeUtils'
import { selectChainId } from 'store/slices/settingsSlice'
import { addPendingTransaction } from 'store/slices/transactionsSlice'
import { createPendingTxFromTxResponse } from 'src/lib/utils'
import { Wallet, addressToUse } from 'shared/wallet'

const onSessionApprove = async (
web3wallet: Web3Wallet,
Expand Down Expand Up @@ -112,6 +113,7 @@ export const WalletConnect2Provider = ({
children,
wallet,
}: WalletConnect2ProviderProps) => {
const address = wallet ? addressToUse(wallet) : null
const dispatch = useAppDispatch()
const chainId = useAppSelector(selectChainId)
const [sessions, setSessions] = useState<SessionStruct[]>([])
Expand All @@ -125,6 +127,8 @@ export const WalletConnect2Provider = ({
proposal: Web3WalletTypes.SessionProposal,
usersWallet: Web3Wallet,
) => {
console.log('onSessionProposal', proposal)

const hasErrors = getProposalErrorComparedWithRskNamespace(proposal)
if (hasErrors) {
await onSessionReject(usersWallet, proposal, hasErrors)
Expand All @@ -144,15 +148,15 @@ export const WalletConnect2Provider = ({
}

const subscribeToEvents = useCallback(
(usersWallet: Web3Wallet) => {
(usersWallet: Web3Wallet, _wallet: Wallet) => {
usersWallet.on('session_proposal', async proposal =>
onSessionProposal(proposal, usersWallet),
)
usersWallet.on('session_request', async event => {
if (!wallet) {
if (!_wallet) {
return
}
const adapter = new WalletConnectAdapter(wallet)
const adapter = new WalletConnectAdapter(_wallet)
const eth_signTypedDataResolver = adapter
.getResolvers()
.find(
Expand All @@ -164,10 +168,7 @@ export const WalletConnect2Provider = ({
// if address = relay address - throw error
const { verifyingContract } = domain
if (
[
wallet.smartWalletAddress.toLowerCase(),
wallet.rifRelaySdk.smartWalletFactory.address.toLowerCase(),
].includes(verifyingContract.toLowerCase())
[address?.toLowerCase()].includes(verifyingContract.toLowerCase())
) {
throw new Error(
'Error: Unauthorized Contract Address - Signing not permitted. This address is exclusive to the relay contract.',
Expand All @@ -194,12 +195,12 @@ export const WalletConnect2Provider = ({
adapter
.handleCall(method, params)
.then(async signedMessage => {
if (method === 'eth_sendTransaction') {
if (method === 'eth_sendTransaction' && address) {
const pendingTx = await createPendingTxFromTxResponse(
signedMessage,
{
chainId,
from: wallet.smartWalletAddress,
from: address,
to: params[0].to,
},
)
Expand Down Expand Up @@ -231,14 +232,14 @@ export const WalletConnect2Provider = ({
)
})
},
[chainId, dispatch, wallet],
[chainId, dispatch, address],
)

const onCreateNewSession = useCallback(
async (uri: string) => {
if (web3wallet) {
if (web3wallet && wallet) {
try {
subscribeToEvents(web3wallet)
subscribeToEvents(web3wallet, wallet)
// Refer to https://docs.walletconnect.com/2.0/reactnative/web3wallet/wallet-usage#session-requests

if (!isWcUriValid(uri)) {
Expand Down Expand Up @@ -279,15 +280,15 @@ export const WalletConnect2Provider = ({
}
}
},
[subscribeToEvents, web3wallet],
[subscribeToEvents, web3wallet, wallet],
)

const onUserApprovedSession = async () => {
if (pendingSession && wallet) {
if (pendingSession && address) {
const newSession = await onSessionApprove(
pendingSession.web3wallet,
pendingSession.proposal,
wallet.smartWalletAddress,
address,
chainId,
)
if (typeof newSession === 'string') {
Expand Down Expand Up @@ -338,20 +339,27 @@ export const WalletConnect2Provider = ({
[web3wallet],
)

const onContextFirstLoad = useCallback(async () => {
console.log('onContextFirstLoad')
const newWeb3Wallet = await createWeb3Wallet()
setWeb3Wallet(newWeb3Wallet)
subscribeToEvents(newWeb3Wallet)
setSessions(Object.values(newWeb3Wallet.getActiveSessions()))
}, [subscribeToEvents])
const onContextFirstLoad = useCallback(
async (_wallet: Wallet) => {
try {
console.log('onContextFirstLoad')
const newWeb3Wallet = await createWeb3Wallet()
setWeb3Wallet(newWeb3Wallet)
subscribeToEvents(newWeb3Wallet, _wallet)
setSessions(Object.values(newWeb3Wallet.getActiveSessions()))
} catch (err) {
throw new Error(err)
}
},
[subscribeToEvents],
)

/**
* useEffect On first load, fetch previous saved sessions
*/
useEffect(() => {
if (wallet) {
onContextFirstLoad().catch(console.log)
onContextFirstLoad(wallet).catch(console.log)
}
}, [wallet, onContextFirstLoad])

Expand Down
9 changes: 8 additions & 1 deletion src/screens/walletConnect/walletConnect2.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { getEnvSetting } from 'core/config'
import { SETTINGS } from 'core/types'
import { AcceptedValue, MMKVStorage } from 'storage/MMKVStorage'

const WC2 = 'WC2'

export type WalletConnect2SdkErrorString = Parameters<typeof getSdkError>[0]

const WalletConnect2SdkErrorEnum: { [P in WalletConnect2SdkErrorString]: P } = {
Expand Down Expand Up @@ -36,8 +38,13 @@ const WalletConnect2SdkErrorEnum: { [P in WalletConnect2SdkErrorString]: P } = {

type StorageTypeFromCore = InstanceType<typeof Core>['storage']

export const deleteWCSessions = () => {
const storage = new MMKVStorage('WC2')
storage.deleteAll()
}

class MMKVCoreStorage implements StorageTypeFromCore {
storage = new MMKVStorage('WC2')
storage = new MMKVStorage(WC2)

getEntries<T = never>(): Promise<[string, T][]> {
const keys = this.storage.getAllKeys()
Expand Down
8 changes: 3 additions & 5 deletions src/storage/ChainStorage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ChainID } from 'lib/eoaWallet'

import { MMKVStorage } from 'storage/MMKVStorage'

const ChainStorage = new MMKVStorage('chainStorage')
import { MainStorage } from './MainStorage'

export const getCurrentChainId: () => ChainID = () =>
ChainStorage.get('chainId') || 31
MainStorage.get('chainId') || 31

export const setCurrentChainId = (chainId: ChainID) =>
ChainStorage.set('chainId', chainId)
MainStorage.set('chainId', chainId)
31 changes: 9 additions & 22 deletions src/storage/MMKVStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { initializeMMKVFlipper } from 'react-native-mmkv-flipper-plugin'
export type AcceptedValue = boolean | string | number | object

export class MMKVStorage {
private id = 'mmkv.default'
private storage: MMKV | null = null
private id: string
private storage: MMKV

constructor(id = 'mmkv.default', encryptionKey?: string) {
this.id = id
Expand All @@ -20,42 +20,29 @@ export class MMKVStorage {
}

public set(key: string, value: AcceptedValue) {
if (this.storage && typeof value !== 'undefined') {
if (typeof value !== 'undefined') {
this.storage.set(key, JSON.stringify(value))
}
}

public get(key = 'default') {
if (this.storage) {
const value = this.storage.getString(key)
return value && JSON.parse(value)
}
const value = this.storage.getString(key)
return value && JSON.parse(value)
}

public has(key = 'default') {
if (this.storage) {
return this.storage.contains(key)
} else {
return false
}
return this.storage.contains(key)
}

public delete(key: string) {
if (this.storage) {
this.storage.delete(key)
}
this.storage.delete(key)
}

public deleteAll() {
if (this.storage) {
this.storage.clearAll()
}
this.storage.clearAll()
}

public getAllKeys() {
if (this.storage) {
return this.storage.getAllKeys()
}
return []
return this.storage.getAllKeys() || []
}
}

0 comments on commit a62861d

Please sign in to comment.