Skip to content

Commit

Permalink
Handle WalletConnect sessions in auth flow
Browse files Browse the repository at this point in the history
  • Loading branch information
ccali11 committed Dec 19, 2023
1 parent 24795e6 commit 3127474
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 77 deletions.
11 changes: 9 additions & 2 deletions apps/mvp/src/components/ConnectWalletsFlow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const { getEthersLedgerAddresses } = useLedger()
const { getEthersTrezorAddresses } = useTrezor()
const { user } = useUser()
const { detectActiveNetwork, switchEthersNetwork } = useWallets()
const { connectWalletConnectV2 } = useWalletConnect()
const { connectWalletConnectV2, walletConnectSelectedAccount } = useWalletConnect()
// const { installedWallets, detectInstalledWalletProviders } = useWallets()
// eslint-disable-next-line no-undef
Expand Down Expand Up @@ -104,6 +104,7 @@ async function handleConfirmCreateAccountWithExistingSecondary() {
*/
async function selectAddress(address: string, pathIndex?: number): Promise<void> {
selectedAddress.value = address
console.log("selectedAddress.value :>> ", selectedAddress.value)
flowState.value = "loading"
const loginCredentials: LoginCredentials =
pathIndex !== undefined ?
Expand Down Expand Up @@ -226,6 +227,12 @@ onUnmounted(() => {
flowState.value = "select_provider"
}
})
watch(walletConnectSelectedAccount, () => {
if (selectedProvider.value === "WalletConnect") {
walletProviderAddresses.value = walletConnectSelectedAccount.value as CryptoAddress[]
}
})
</script>

<template>
Expand Down Expand Up @@ -374,7 +381,7 @@ onUnmounted(() => {
@click="
selectedProvider === 'Ledger' || selectedProvider === 'Trezor' ?
selectAddress(trimAndLowercaseAddress(act.address), pathIndex) :
selectAddress(trimAndLowercaseAddress(act.address), undefined)
selectAddress(act.address, undefined)
"
>
<div>
Expand Down
10 changes: 4 additions & 6 deletions apps/mvp/src/composables/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export default function useAuth() {
loginCredentials: LoginCredentials
): Promise<UserAuthState> {
const { address, provider } = loginCredentials
console.log("loginCredentials :>> ", loginCredentials)
try {
if (user.value) {
// If address already exists on user, do nothing
Expand Down Expand Up @@ -174,6 +175,7 @@ export default function useAuth() {
const browserWallet = browserProvidersList.includes(provider as ProviderString)

if (provider === "WalletConnect") {
console.log("got to wallet connect login")
await loginWithProvider(loginCredentials as LoginCredentials)
await getUser()
return "Successfully logged in"
Expand Down Expand Up @@ -265,6 +267,7 @@ export default function useAuth() {
} else if (provider === "Trezor") {
await loginWithTrezor(loginCredentials)
} else if (provider === "WalletConnect") {
console.log("logging in with wallet connect")
await loginWithWalletConnectV2(loginCredentials)
} else {
console.log("Sign up not yet supported for this wallet provider")
Expand Down Expand Up @@ -308,12 +311,7 @@ export default function useAuth() {
}
}
})

onUnmounted(() => {
initializedAuthComposable.value = false
uninitializeWalletConnect()
})


// TODO: Re-enable once we have a way to remove accounts in UI
// async function removeConnectedAccount() {
// if (!user?.value?.address) {
Expand Down
129 changes: 60 additions & 69 deletions apps/mvp/src/composables/walletConnectV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let cleanupFunctions: Array<any> = [] // TODO: Potentially fix type here.
const accounts = ref<Array<string>>([])
const ethereumProvider = ref()
const pairings = ref([])
const session = ref()
const session = ref<SessionTypes.Struct>()
const web3Modal = ref()
const web3Provider = shallowRef()

Expand All @@ -28,6 +28,8 @@ const subscribedToProviderEvents = ref(false)
const componentIsMounted = ref(false)
const isInitializing = ref(false)

const walletConnectSelectedAccount = ref([] as Array<CryptoAddress>)

export default function useWalletConnectV2() {
async function connectWalletConnectV2(chainId: "1" | "5" | "1337", pairing?: PairingTypes.Struct): Promise<CryptoAddress[]> {
try {
Expand All @@ -40,13 +42,18 @@ export default function useWalletConnectV2() {
}
const rpcUrl = customRpcs[chainId]
if (!rpcUrl) throw new Error(`RPC URL not found for chainId: ${chainId}`)

await ethereumProvider.value.connect()
createEthersProvider()
const _accounts = await ethereumProvider.value.enable()
// const _accounts = await ethereumProvider.value.enable()
const _accounts = ethereumProvider.value.accounts
accounts.value = _accounts
session.value = session
session.value = ethereumProvider.value.session
web3Modal.value?.closeModal()
walletConnectSelectedAccount.value = [{
address: accounts.value[0],
balance: (await getEthersBalance(accounts.value[0])).toString()
}]

const connectedAddress = _accounts[0].toLowerCase().trim() as string
const connectedAddressBalance = (await getEthersBalance(connectedAddress)).toString()
return [{ address: connectedAddress as string, balance: connectedAddressBalance }]
Expand Down Expand Up @@ -99,93 +106,64 @@ export default function useWalletConnectV2() {
}

function getWalletConnectSignerV2() {
if (!web3Provider.value) {
throw new Error("Web3Provider is not initialized")
}
if (!web3Provider.value) throw new Error("Web3Provider is not initialized")
return web3Provider.value.getSigner()
}

async function initializeWalletConnect() {
if (componentIsMounted.value) return
if (import.meta.env.MODE === "development") console.log("initializing wallet connect")
componentIsMounted.value = true

// Check for persisted sessions & Subscribe to provider events
if (ethereumProvider.value && user.value) {
_subscribeToProviderEvents()
subscribedToProviderEvents.value = true
await _checkForPersistedSession()
checkedForPersistedSession.value = true
} else {
await createClient()
}
await createClient()
}

async function loginWithWalletConnectV2(loginCredentials: LoginCredentials) {
const { provider, address, currency } = loginCredentials
try {
const message = await createSiweMessage(address, "Sign in with Ethereum to the Casimir.")
const signedMessage = await signWalletConnectMessage(message)
await signInWithEthereum({
address,
currency: currency || "ETH",
provider,
message,
signedMessage
})
} catch (err) {
console.log("error in loginWithWalletConnect :>> ", err)
}
const message = await createSiweMessage(address, "Sign in with Ethereum to the Casimir.")
const signedMessage = await signWalletConnectMessage(message)
await signInWithEthereum({
address,
currency: currency || "ETH",
provider,
message,
signedMessage
})
}

async function signWalletConnectMessage(message: string) : Promise<string> {
try {
const signer = await web3Provider.value?.getSigner()
return await signer?.signMessage(message) as string
} catch (err) {
console.error("error in signWalletConnectMessage :>> ", err)
throw err
return ""
}
}

function uninitializeWalletConnect() {
cleanupFunctions.forEach((cleanup) => cleanup())
cleanupFunctions = [] // Reset the array
componentIsMounted.value = false
const signer = await web3Provider.value?.getSigner()
return await signer?.signMessage(message) as string
}

async function _checkForPersistedSession() {
if (ethereumProvider.value?.session) {
const _session = ethereumProvider.value?.session
console.log("RESTORED SESSION:", _session)
session.value = ethereumProvider.value?.session
console.log("RESTORED SESSION:", session.value)
if (!user.value) {
await disconnectWalletConnect()
return
} else {
if (!ethereumProvider.value) {
throw new ReferenceError("EthereumProvider is not initialized.")
}
walletConnectSelectedAccount.value = [{
address: ethereumProvider.value.accounts[0],
balance: (await getEthersBalance(ethereumProvider.value.accounts[0])).toString()
}]
createEthersProvider()
}
await _onSessionConnected(_session)
return _session
}
}

async function _onSessionConnected(_session: SessionTypes.Struct) {
if (!ethereumProvider.value) {
throw new ReferenceError("EthereumProvider is not initialized.")
}
const allNamespaceAccounts = Object.values(_session.namespaces).map(namespace => namespace.accounts).flat()
const allNamespaceChains = Object.keys(_session.namespaces)

session.value = _session
accounts.value = allNamespaceAccounts.map(account => account.split(":")[2])
console.log("RESTORED", allNamespaceChains, allNamespaceAccounts)
createEthersProvider()
}

function _resetApp() {
console.log("resetting app")
cleanupFunctions.forEach((cleanup) => cleanup())
cleanupFunctions = [] // Reset the array
pairings.value = []
session.value = undefined
accounts.value = []
web3Provider.value = undefined
walletConnectSelectedAccount.value = []
checkedForPersistedSession.value = false
subscribedToProviderEvents.value = false
}

function _subscribeToProviderEvents() {
Expand All @@ -195,10 +173,21 @@ export default function useWalletConnectV2() {

// Event handler for display_uri
const handleDisplayUri = (uri: string) => {
console.log("DISPLAY URI EVENT", "QR Code Modal open")
console.log("QR Code Modal open")
web3Modal.value?.openModal({ uri })
}

// Event handler for accountsChanged
const handleAccountsChanged = async (walletConnectAccounts: Array<string>) => {
console.log("ACCOUNTS CHANGED EVENT", walletConnectAccounts)
if (!user.value && accounts.value.length > 0) return window.location.reload()
}

// Event handler for chainChanged
const handleChainChanged = (chainId: number) => {
// console.log("CHAIN CHANGED EVENT", chainId)
}

// Event handler for session_ping
const handleSessionPing = ({ id, topic }: { id: number; topic: string }) => {
console.log("SESSION PING EVENT", "session_ping")
Expand All @@ -207,8 +196,7 @@ export default function useWalletConnectV2() {

// Event handler for session_event
const handleSessionEvent = ({ event, chainId }: { event: any; chainId: string }) => {
console.log("SESSION EVENT", "session_event")
console.log(event, chainId)
console.log("SESSION EVENT", event)
}

// Event handler for session_update
Expand All @@ -219,33 +207,36 @@ export default function useWalletConnectV2() {

// Event handler for session_delete
const handleSessionDelete = ({ id, topic }: { id: number; topic: string }) => {
console.log("DELETE SESSION EVENT", "session_deleted")
console.log(id, topic)
console.log("DELETE SESSION EVENT", "session_deleted", id, topic)
_resetApp()
}

// Attaching the event listeners
ethereumProvider.value.on("display_uri", handleDisplayUri)
ethereumProvider.value.on("accountsChanged", handleAccountsChanged)
ethereumProvider.value.on("chainChanged", handleChainChanged)
ethereumProvider.value.on("session_ping", handleSessionPing)
ethereumProvider.value.on("session_event", handleSessionEvent)
ethereumProvider.value.on("session_update", handleSessionUpdate)
ethereumProvider.value.on("session_delete", handleSessionDelete)

// Storing cleanup functions
cleanupFunctions.push(() => ethereumProvider.value.off("display_uri", handleDisplayUri))
cleanupFunctions.push(() => ethereumProvider.value.off("accountsChanged", handleAccountsChanged))
cleanupFunctions.push(() => ethereumProvider.value.off("chainChanged", handleChainChanged))
cleanupFunctions.push(() => ethereumProvider.value.off("session_ping", handleSessionPing))
cleanupFunctions.push(() => ethereumProvider.value.off("session_event", handleSessionEvent))
cleanupFunctions.push(() => ethereumProvider.value.off("session_update", handleSessionUpdate))
cleanupFunctions.push(() => ethereumProvider.value.off("session_delete", handleSessionDelete))
}

return {
walletConnectSelectedAccount,
web3Provider,
connectWalletConnectV2,
disconnectWalletConnect,
getWalletConnectSignerV2,
initializeWalletConnect,
loginWithWalletConnectV2,
uninitializeWalletConnect
}
}

0 comments on commit 3127474

Please sign in to comment.