diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx index 9769432..81f489e 100644 --- a/wallets/react-wallet-v2/src/components/Modal.tsx +++ b/wallets/react-wallet-v2/src/components/Modal.tsx @@ -1,15 +1,16 @@ import ModalStore from '@/store/ModalStore' +import SessionProposalModal from '@/views/SessionProposalModal' import { Modal as NextModal } from '@nextui-org/react' import { useSnapshot } from 'valtio' export default function Modal() { - const { open } = useSnapshot(ModalStore.state) + const { open, view } = useSnapshot(ModalStore.state) + + console.log(open) return ( - - - - + + {view === 'SessionProposalModal' && } ) } diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index c3ea9d9..22d720d 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -1,16 +1,26 @@ +import ModalStore from '@/store/ModalStore' import { client } from '@/utils/WalletConnectUtil' import { CLIENT_EVENTS } from '@walletconnect/client' import { SessionTypes } from '@walletconnect/types' import { useCallback, useEffect } from 'react' export default function useWalletConnectEventsManager(initialized: boolean) { - const onPairingProposal = useCallback((proposal: SessionTypes.Proposal) => { + const onSessionProposal = useCallback((proposal: SessionTypes.Proposal) => { console.log(proposal) + ModalStore.open('SessionProposalModal', { proposal }) + }, []) + + const onSessionCreated = useCallback((created: SessionTypes.Created) => { + // ModalStore.open('SessionCreatedModal', { created }) }, []) useEffect(() => { - if (initialized) { - client?.on(CLIENT_EVENTS.pairing.proposal, onPairingProposal) + if (initialized && client) { + // 1. Open session proposal modal for confirmation / rejection + client.on(CLIENT_EVENTS.session.proposal, onSessionProposal) + + // 2. Open session created modal to show success feedback + client.on(CLIENT_EVENTS.session.created, onSessionCreated) } - }, [initialized, onPairingProposal]) + }, [initialized, onSessionProposal, onSessionCreated]) } diff --git a/wallets/react-wallet-v2/src/pages/walletconnect.tsx b/wallets/react-wallet-v2/src/pages/walletconnect.tsx index a17dab5..7180319 100644 --- a/wallets/react-wallet-v2/src/pages/walletconnect.tsx +++ b/wallets/react-wallet-v2/src/pages/walletconnect.tsx @@ -15,6 +15,7 @@ export default function WalletConnectPage() { } catch (err: unknown) { alert(err) } finally { + setUri('') setLoading(false) } } diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts index da0a18c..2293b49 100644 --- a/wallets/react-wallet-v2/src/store/ModalStore.ts +++ b/wallets/react-wallet-v2/src/store/ModalStore.ts @@ -1,17 +1,27 @@ +import { SessionTypes } from '@walletconnect/types' import { proxy } from 'valtio' /** * Types */ +interface ModalData { + proposal?: SessionTypes.Proposal + created?: SessionTypes.Created +} + interface State { open: boolean + view?: 'SessionProposalModal' | 'SessionCreatedModal' + data?: ModalData } /** * State */ const state = proxy({ - open: false + view: undefined, + open: false, + data: undefined }) /** @@ -20,7 +30,9 @@ const state = proxy({ const ModalStore = { state, - open() { + open(view: State['view'], data: State['data']) { + state.view = view + state.data = data state.open = true }, diff --git a/wallets/react-wallet-v2/src/utils/EIP155ChainsUtil.ts b/wallets/react-wallet-v2/src/utils/EIP155ChainsUtil.ts index 1423110..9753f9d 100644 --- a/wallets/react-wallet-v2/src/utils/EIP155ChainsUtil.ts +++ b/wallets/react-wallet-v2/src/utils/EIP155ChainsUtil.ts @@ -3,30 +3,31 @@ * @url https://chainlist.org */ +export type CHAIN = keyof typeof MAINNET_CHAINS + export const LOGO_BASE_URL = 'https://blockchain-api.xyz/logos/' export const MAINNET_CHAINS = { - '1': { + 'eip155:1': { + chainId: 1, name: 'Ethereum', logo: LOGO_BASE_URL + 'eip155:1.png', rgb: '99, 125, 234' }, - '10': { + 'eip155:10': { + chainId: 10, name: 'Optimism', logo: LOGO_BASE_URL + 'eip155:10.png', rgb: '233, 1, 1' }, - '100': { - name: 'Gnosis', - logo: LOGO_BASE_URL + 'eip155:100.png', - rgb: '73, 169, 166' - }, - '137': { + 'eip155:137': { + chainId: 137, name: 'Polygon', logo: LOGO_BASE_URL + 'eip155:137.png', rgb: '130, 71, 229' }, - '42161': { + 'eip155:42161': { + chainId: 42161, name: 'Arbitrum', logo: LOGO_BASE_URL + 'eip155:42161.png', rgb: '44, 55, 75' diff --git a/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts index 6212035..aaf43fa 100644 --- a/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts +++ b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts @@ -5,7 +5,6 @@ export let client: WalletConnectClient | undefined = undefined export async function createClient() { client = await WalletConnectClient.init({ controller: true, - logger: 'debug', projectId: '8f331b9812e0e5b8f2da2c7203624869', relayUrl: 'wss://relay.walletconnect.com', metadata: { diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx new file mode 100644 index 0000000..76ec238 --- /dev/null +++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -0,0 +1,105 @@ +import ModalStore from '@/store/ModalStore' +import WalletStore from '@/store/WalletStore' +import { CHAIN, MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' +import { client } from '@/utils/WalletConnectUtil' +import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' +import { Fragment } from 'react' + +export default function SessionProposalModal() { + // Get proposal data and wallet address from store + const proposal = ModalStore.state.data?.proposal + const address = WalletStore.state.wallet?.address + + // Ensure proposal and client are defined + if (!proposal || !client) { + return Missing proposal data + } + + // Get data to display + const { proposer, permissions, relay } = proposal + const { icons, name, url } = proposer.metadata + const { chains } = permissions.blockchain + const { methods } = permissions.jsonrpc + const { protocol } = relay + + // Hanlde approve action + async function onApprove() { + if (client && proposal && address) { + const response = { + state: { + accounts: chains.map(chain => `${chain}:${address}`) + } + } + await client.approve({ proposal, response }) + } + ModalStore.close() + } + + // Hanlde reject action + async function onReject() { + if (client && proposal) { + await client.reject({ proposal }) + } + ModalStore.close() + } + + return ( + + + Session Proposal + + + + + + + + + + {name} + {url} + + + + + + + + Blockchains + + {chains.map(chain => MAINNET_CHAINS[chain as CHAIN]?.name ?? chain).join(', ')} + + + + + + + + + Methods + {methods.map(method => method).join(', ')} + + + + + + + + Relay Protocol + {protocol} + + + + + + + + + + + ) +}