diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json
index edad553..48dbcdb 100644
--- a/wallets/react-wallet-v2/package.json
+++ b/wallets/react-wallet-v2/package.json
@@ -19,7 +19,8 @@
"react-qr-reader-es6": "2.2.1-2",
"framer-motion": "6.2.6",
"ethers": "5.5.4",
- "valtio": "1.3.0"
+ "valtio": "1.3.0",
+ "@json-rpc-tools/utils": "1.7.6"
},
"devDependencies": {
"@walletconnect/types": "2.0.0-beta.22",
diff --git a/wallets/react-wallet-v2/src/styles/main.css b/wallets/react-wallet-v2/public/main.css
similarity index 100%
rename from wallets/react-wallet-v2/src/styles/main.css
rename to wallets/react-wallet-v2/public/main.css
diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx
index fe57c11..fb6ff69 100644
--- a/wallets/react-wallet-v2/src/components/AccountCard.tsx
+++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx
@@ -1,5 +1,6 @@
import { truncate } from '@/utils/HelperUtil'
import { Avatar, Card, Text } from '@nextui-org/react'
+import Link from 'next/link'
interface Props {
name: string
@@ -10,36 +11,38 @@ interface Props {
export default function AccountCard({ name, logo, rgb, address }: Props) {
return (
-
-
+
-
-
-
- {name}
-
-
- {truncate(address, 19)}
-
-
-
-
+
+
+
+
+ {name}
+
+
+ {truncate(address, 19)}
+
+
+
+
+
)
}
diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx
index 52e5239..29f6204 100644
--- a/wallets/react-wallet-v2/src/components/Modal.tsx
+++ b/wallets/react-wallet-v2/src/components/Modal.tsx
@@ -1,6 +1,6 @@
import ModalStore from '@/store/ModalStore'
import SessionProposalModal from '@/views/SessionProposalModal'
-import SessionRequestModal from '@/views/SessionRequestModal'
+import SessionRequestModal from '@/views/SessionSignModal'
import { Modal as NextModal } from '@nextui-org/react'
import { useSnapshot } from 'valtio'
@@ -10,7 +10,7 @@ export default function Modal() {
return (
{view === 'SessionProposalModal' && }
- {view === 'SessionRequestModal' && }
+ {view === 'SessionSignModal' && }
)
}
diff --git a/wallets/react-wallet-v2/src/data/EIP155Data.ts b/wallets/react-wallet-v2/src/data/EIP155Data.ts
index 20672d8..efc5cee 100644
--- a/wallets/react-wallet-v2/src/data/EIP155Data.ts
+++ b/wallets/react-wallet-v2/src/data/EIP155Data.ts
@@ -3,20 +3,20 @@
* @url https://chainlist.org
*/
-/**
- * Types
- */
-export type TChain = keyof typeof MAINNET_CHAINS
-
/**
* Utilities
*/
-export const LOGO_BASE_URL = 'https://blockchain-api.xyz/logos/'
+const LOGO_BASE_URL = 'https://blockchain-api.xyz/logos/'
+
+/**
+ * Types
+ */
+export type TEIP155Chain = keyof typeof EIP155_CHAINS
/**
* Chains
*/
-export const MAINNET_CHAINS = {
+export const EIP155_CHAINS = {
'eip155:1': {
chainId: 1,
name: 'Ethereum',
@@ -46,11 +46,12 @@ export const MAINNET_CHAINS = {
/**
* Methods
*/
-export const SIGNING_METHODS = {
+export const EIP155_SIGNING_METHODS = {
PERSONAL_SIGN: 'personal_sign',
- SEND_TRANSACTION: 'eth_sendTransaction',
- SIGN: 'eth_sign',
- SIGN_TRANSACTION: 'eth_signTransaction',
- SIGN_TYPED_DATA: 'eth_signTypedData',
- SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4'
+ ETH_SIGN: 'eth_sign',
+ ETH_SIGN_TRANSACTION: 'eth_signTransaction',
+ ETH_SIGN_TYPED_DATA: 'eth_signTypedData',
+ ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4',
+ ETH_SIGN_RAW_TRANSACTION: 'eth_sendRawTransaction',
+ ETH_SEND_TRANSACTION: 'eth_sendTransaction'
}
diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts
index fe6f9bd..079ce4a 100644
--- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts
+++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts
@@ -1,3 +1,4 @@
+import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data'
import ModalStore from '@/store/ModalStore'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { CLIENT_EVENTS } from '@walletconnect/client'
@@ -5,28 +6,31 @@ import { SessionTypes } from '@walletconnect/types'
import { useCallback, useEffect } from 'react'
export default function useWalletConnectEventsManager(initialized: boolean) {
+ // 1. Open session proposal modal for confirmation / rejection
const onSessionProposal = useCallback((proposal: SessionTypes.Proposal) => {
ModalStore.open('SessionProposalModal', { proposal })
}, [])
- const onSessionCreated = useCallback((created: SessionTypes.Created) => {
- // TODO show successful connection feedback here
- }, [])
+ // 2. Open session created modal to show success feedback
+ const onSessionCreated = useCallback((created: SessionTypes.Created) => {}, [])
- const onSessionRequest = useCallback(async (request: SessionTypes.RequestEvent) => {
- const requestSession = await walletConnectClient.session.get(request.topic)
- ModalStore.open('SessionRequestModal', { request, requestSession })
+ // 3. Open rpc request handling modal based on method that was used
+ const onSessionRequest = useCallback(async (requestEvent: SessionTypes.RequestEvent) => {
+ const { topic, request } = requestEvent
+ const { method } = request
+ const requestSession = await walletConnectClient.session.get(topic)
+
+ if ([EIP155_SIGNING_METHODS.ETH_SIGN, EIP155_SIGNING_METHODS.PERSONAL_SIGN].includes(method)) {
+ ModalStore.open('SessionSignModal', { requestEvent, requestSession })
+ }
}, [])
useEffect(() => {
if (initialized) {
- // 1. Open session proposal modal for confirmation / rejection
walletConnectClient.on(CLIENT_EVENTS.session.proposal, onSessionProposal)
- // 2. Open session created modal to show success feedback
walletConnectClient.on(CLIENT_EVENTS.session.created, onSessionCreated)
- // 3. Open rpc request handling modal
walletConnectClient.on(CLIENT_EVENTS.session.request, onSessionRequest)
}
}, [initialized, onSessionProposal, onSessionCreated, onSessionRequest])
diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx
index 92fb4ce..a375bb2 100644
--- a/wallets/react-wallet-v2/src/pages/_app.tsx
+++ b/wallets/react-wallet-v2/src/pages/_app.tsx
@@ -2,11 +2,11 @@ import Layout from '@/components/Layout'
import Modal from '@/components/Modal'
import useInitialization from '@/hooks/useInitialization'
import useWalletConnectEventsManager from '@/hooks/useWalletConnectEventsManager'
-import '@/styles/main.css'
import { darkTheme, lightTheme } from '@/utils/ThemeUtil'
import { NextUIProvider } from '@nextui-org/react'
import { ThemeProvider } from 'next-themes'
import { AppProps } from 'next/app'
+import '../../public/main.css'
export default function App({ Component, pageProps }: AppProps) {
// Step 1 - Initialize wallets and wallet connect client
diff --git a/wallets/react-wallet-v2/src/pages/index.tsx b/wallets/react-wallet-v2/src/pages/index.tsx
index ae54a27..a1014ff 100644
--- a/wallets/react-wallet-v2/src/pages/index.tsx
+++ b/wallets/react-wallet-v2/src/pages/index.tsx
@@ -1,6 +1,6 @@
import AccountCard from '@/components/AccountCard'
import PageHeader from '@/components/PageHeader'
-import { MAINNET_CHAINS } from '@/data/EIP155Data'
+import { EIP155_CHAINS } from '@/data/EIP155Data'
import { wallet } from '@/utils/WalletUtil'
import { Fragment } from 'react'
@@ -8,7 +8,7 @@ export default function HomePage() {
return (
Accounts
- {Object.values(MAINNET_CHAINS).map(({ name, logo, rgb }) => (
+ {Object.values(EIP155_CHAINS).map(({ name, logo, rgb }) => (
))}
diff --git a/wallets/react-wallet-v2/src/pages/sessions.tsx b/wallets/react-wallet-v2/src/pages/sessions.tsx
new file mode 100644
index 0000000..5b0e968
--- /dev/null
+++ b/wallets/react-wallet-v2/src/pages/sessions.tsx
@@ -0,0 +1,20 @@
+import PageHeader from '@/components/PageHeader'
+import { truncate } from '@/utils/HelperUtil'
+import { walletConnectClient } from '@/utils/WalletConnectUtil'
+import { useRouter } from 'next/router'
+import { Fragment, useEffect } from 'react'
+
+export default function SessionsPage() {
+ const { query } = useRouter()
+ const address = (query?.address as string) ?? 'Unknown'
+
+ useEffect(() => {
+ console.log(walletConnectClient.session.values)
+ }, [])
+
+ return (
+
+ {truncate(address, 15)}
+
+ )
+}
diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts
index 789269d..b46b454 100644
--- a/wallets/react-wallet-v2/src/store/ModalStore.ts
+++ b/wallets/react-wallet-v2/src/store/ModalStore.ts
@@ -7,13 +7,13 @@ import { proxy } from 'valtio'
interface ModalData {
proposal?: SessionTypes.Proposal
created?: SessionTypes.Created
- request?: SessionTypes.RequestEvent
+ requestEvent?: SessionTypes.RequestEvent
requestSession?: SessionTypes.Settled
}
interface State {
open: boolean
- view?: 'SessionProposalModal' | 'SessionRequestModal'
+ view?: 'SessionProposalModal' | 'SessionSignModal'
data?: ModalData
}
diff --git a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts
new file mode 100644
index 0000000..640fa7a
--- /dev/null
+++ b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts
@@ -0,0 +1,28 @@
+import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data'
+import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
+import { RequestEvent } from '@walletconnect/types'
+import { ERROR } from '@walletconnect/utils'
+import { Wallet } from 'ethers'
+
+export async function approveEIP155Request(request: RequestEvent['request'], wallet: Wallet) {
+ const { method, params, id } = request
+
+ switch (method) {
+ case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
+ const personalSignResult = await wallet.signMessage(params[0])
+ return formatJsonRpcResult(id, personalSignResult)
+
+ case EIP155_SIGNING_METHODS.ETH_SIGN:
+ const ethSignResult = await wallet.signMessage(params[1])
+ return formatJsonRpcResult(id, ethSignResult)
+
+ default:
+ throw new Error(ERROR.UNKNOWN_JSONRPC_METHOD.format().message)
+ }
+}
+
+export function rejectEIP155Request(request: RequestEvent['request']) {
+ const { id } = request
+
+ return formatJsonRpcError(id, ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format().message)
+}
diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx
index d4975b5..2f9e13e 100644
--- a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx
+++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx
@@ -1,4 +1,4 @@
-import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data'
+import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import ModalStore from '@/store/ModalStore'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { wallet } from '@/utils/WalletUtil'
@@ -66,7 +66,9 @@ export default function SessionProposalModal() {
Blockchains
- {chains.map(chain => MAINNET_CHAINS[chain as TChain]?.name ?? chain).join(', ')}
+ {chains
+ .map(chain => EIP155_CHAINS[chain as TEIP155Chain]?.name ?? chain)
+ .join(', ')}
diff --git a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx
similarity index 56%
rename from wallets/react-wallet-v2/src/views/SessionRequestModal.tsx
rename to wallets/react-wallet-v2/src/views/SessionSignModal.tsx
index 93f3817..563e01c 100644
--- a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx
+++ b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx
@@ -1,37 +1,57 @@
-import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data'
+import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data'
import ModalStore from '@/store/ModalStore'
-import { getSignMessage } from '@/utils/HelperUtil'
+import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil'
+import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { wallet } from '@/utils/WalletUtil'
import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react'
+import { utils } from 'ethers'
import { Fragment } from 'react'
-export default function SessionRequestModal() {
+export default function SessionSignModal() {
// Get request and wallet data from store
- const request = ModalStore.state.data?.request
+ const requestEvent = ModalStore.state.data?.requestEvent
const requestSession = ModalStore.state.data?.requestSession
// Ensure request and wallet are defined
- if (!request || !requestSession) {
+ if (!requestEvent || !requestSession) {
return Missing request data
}
// Get required request data
- const { chainId } = request
- const { method, params } = request.request
+ const { chainId } = requestEvent
+ const { method, params } = requestEvent.request
const { protocol } = requestSession.relay
const { name, icons, url } = requestSession.peer.metadata
+ // Get message as utf string
+ let message = method === EIP155_SIGNING_METHODS.PERSONAL_SIGN ? params[0] : params[1]
+ if (utils.isHexString(message)) {
+ message = utils.toUtf8String(message)
+ }
+
// Handle approve action (logic varies based on request method)
async function onApprove() {
- // Handle sign requests
- if (['eth_sign', 'personal_sign'].includes(method)) {
- const message = getSignMessage(params, wallet.address)
- const signedMessage = wallet.signMessage(message)
+ if (requestEvent) {
+ const response = await approveEIP155Request(requestEvent.request, wallet)
+ await walletConnectClient.respond({
+ topic: requestEvent.topic,
+ response
+ })
+ ModalStore.close()
}
}
// Handle reject action
- async function onReject() {}
+ async function onReject() {
+ if (requestEvent) {
+ const response = rejectEIP155Request(requestEvent.request)
+ await walletConnectClient.respond({
+ topic: requestEvent.topic,
+ response
+ })
+ ModalStore.close()
+ }
+ }
return (
@@ -56,7 +76,18 @@ export default function SessionRequestModal() {
Blockchain
- {MAINNET_CHAINS[chainId as TChain]?.name ?? chainId}
+
+ {EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId}
+
+
+
+
+
+
+
+
+ Message
+ {message}
diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock
index 3a96e5a..439b972 100644
--- a/wallets/react-wallet-v2/yarn.lock
+++ b/wallets/react-wallet-v2/yarn.lock
@@ -417,6 +417,21 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+"@json-rpc-tools/types@^1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.6.tgz#5abd5fde01364a130c46093b501715bcce5bdc0e"
+ integrity sha512-nDSqmyRNEqEK9TZHtM15uNnDljczhCUdBmRhpNZ95bIPKEDQ+nTDmGMFd2lLin3upc5h2VVVd9tkTDdbXUhDIQ==
+ dependencies:
+ keyvaluestorage-interface "^1.0.0"
+
+"@json-rpc-tools/utils@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@json-rpc-tools/utils/-/utils-1.7.6.tgz#67f04987dbaa2e7adb6adff1575367b75a9a9ba1"
+ integrity sha512-HjA8x/U/Q78HRRe19yh8HVKoZ+Iaoo3YZjakJYxR+rw52NHo6jM+VE9b8+7ygkCFXl/EHID5wh/MkXaE/jGyYw==
+ dependencies:
+ "@json-rpc-tools/types" "^1.7.6"
+ "@pedrouid/environment" "^1.0.1"
+
"@next/env@12.0.10":
version "12.0.10"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.10.tgz#561640fd62279218ccd2798ae907bae8d94a7730"
@@ -517,6 +532,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@pedrouid/environment@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec"
+ integrity sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug==
+
"@react-aria/focus@3.5.0":
version "3.5.0"
resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.5.0.tgz#02b85f97d6114af1eccc0902ce40723b626cb7f9"