Wrap up eth_sign and personal_sign examples
This commit is contained in:
parent
de05b8c82c
commit
e2ac17957e
@ -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",
|
||||
|
@ -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,6 +11,7 @@ interface Props {
|
||||
|
||||
export default function AccountCard({ name, logo, rgb, address }: Props) {
|
||||
return (
|
||||
<Link href={`/sessions?address=${address}`} passHref>
|
||||
<Card
|
||||
bordered
|
||||
clickable
|
||||
@ -41,5 +43,6 @@ export default function AccountCard({ name, logo, rgb, address }: Props) {
|
||||
</div>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
@ -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 (
|
||||
<NextModal blur open={open} style={{ border: '1px solid rgba(139, 139, 139, 0.4)' }}>
|
||||
{view === 'SessionProposalModal' && <SessionProposalModal />}
|
||||
{view === 'SessionRequestModal' && <SessionRequestModal />}
|
||||
{view === 'SessionSignModal' && <SessionRequestModal />}
|
||||
</NextModal>
|
||||
)
|
||||
}
|
||||
|
@ -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'
|
||||
}
|
||||
|
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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 (
|
||||
<Fragment>
|
||||
<PageHeader>Accounts</PageHeader>
|
||||
{Object.values(MAINNET_CHAINS).map(({ name, logo, rgb }) => (
|
||||
{Object.values(EIP155_CHAINS).map(({ name, logo, rgb }) => (
|
||||
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={wallet.address} />
|
||||
))}
|
||||
</Fragment>
|
||||
|
20
wallets/react-wallet-v2/src/pages/sessions.tsx
Normal file
20
wallets/react-wallet-v2/src/pages/sessions.tsx
Normal file
@ -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 (
|
||||
<Fragment>
|
||||
<PageHeader>{truncate(address, 15)}</PageHeader>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
28
wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts
Normal file
28
wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts
Normal file
@ -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)
|
||||
}
|
@ -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() {
|
||||
<Col>
|
||||
<Text h5>Blockchains</Text>
|
||||
<Text color="$gray400">
|
||||
{chains.map(chain => MAINNET_CHAINS[chain as TChain]?.name ?? chain).join(', ')}
|
||||
{chains
|
||||
.map(chain => EIP155_CHAINS[chain as TEIP155Chain]?.name ?? chain)
|
||||
.join(', ')}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -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 <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// 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 (
|
||||
<Fragment>
|
||||
@ -56,7 +76,18 @@ export default function SessionRequestModal() {
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Blockchain</Text>
|
||||
<Text color="$gray400">{MAINNET_CHAINS[chainId as TChain]?.name ?? chainId}</Text>
|
||||
<Text color="$gray400">
|
||||
{EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Message</Text>
|
||||
<Text color="$gray400">{message}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user