Beta 100 (#27)

* update deps

* revert react dep updates

* chore: update deps to beta.50

* fix: get dapp running again up to Client.connect()

* save progress

* feat(debug): sets up a debug peerClient as responder

* refactor: remove more hardcoded example connect params

* fix: gets `checkPersistedState` working again

* fix: gets client.disconnect + effects working again

* feat: integrates `session_update` handling with namespaces

* fix: remove hardcoded `chains`

* stash progress

* Establish session

* save progress - established session with example dapp

* refactor: rewrite namespace helpers to handle `requiredNamespaces` (#23)

* fix: re-enables restoring persisted session

* refactor: remove debug peerClient code

* fix: re-enables restoring persisted pairings

* Save progress

* fix: re-enables pairing modal, connecting from existing pairing

* Update modals to handle new payloads

* fix(types): fix Metadata typing

* chore(deps): upgrade to beta.53

* refactor: adjusts event handler args for beta.53 `session_update`

* stash

* fix: adds missing keys for `DEFAULT_EIP155_EVENTS` enum

* stash

* chore: update comment for client.request typing FIXME

* feat: integrate beta.54

* feat: integrate beta.55, removes FIXME comments for client.request types

* chore: clean up unused import

* fix: log session_ping event

* fix: log incoming `session_event`

* chore: upgrade client@2.0.0-beta.55 -> sign-client@2.0.0-beta.56

* chore: integrate beta.57

* New beta changes (#24)

* smal lchange

* fix types

* Add package info

* format empty methods / events

* Update deps

* adjust styles

* attempt ios layout fix

* Revert "attempt ios layout fix"

This reverts commit f0176f2ef52f338980ee54e75a767b3d452733f2.

* beta.54

* fix build

* Update to beta 55

* Add todos

* update wallet to beta 56

* Update mumbai rpc add logger

* update to beta 57

* chore: adds note on beta.100 compatibility

* plock

* beta.58

* beta.100;

Co-authored-by: Ilja <idaderko@gmail.com>
Co-authored-by: Ben Kremer <ben@walletconnect.com>
Co-authored-by: Ilja <IljaDaderko@users.noreply.github.com>
This commit is contained in:
Pedro Gomes
2022-05-30 11:46:15 +02:00
committed by GitHub
co-authored by Ilja Ben Kremer Ilja
parent dc76f21c2c
commit 954831538d
44 changed files with 2048 additions and 1561 deletions
+2
View File
@@ -1,5 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.DS_Store
# dependencies
/node_modules
/.pnp
+12 -12
View File
@@ -13,13 +13,13 @@
"@cosmjs/proto-signing": "0.28.4",
"@json-rpc-tools/utils": "1.7.6",
"@nextui-org/react": "1.0.8-beta.5",
"@solana/web3.js": "1.39.1",
"@walletconnect/client": "2.0.0-beta.26",
"@walletconnect/utils": "2.0.0-beta.26",
"@solana/web3.js": "1.43.0",
"@walletconnect/sign-client": "2.0.0-beta.100",
"@walletconnect/utils": "2.0.0-beta.100",
"bs58": "5.0.0",
"cosmos-wallet": "1.2.0",
"ethers": "5.6.4",
"framer-motion": "6.3.0",
"ethers": "5.6.6",
"framer-motion": "6.3.3",
"mnemonic-keyring": "1.4.0",
"next": "12.1.5",
"react": "17.0.2",
@@ -27,16 +27,16 @@
"react-dom": "17.0.2",
"react-qr-reader-es6": "2.2.1-2",
"solana-wallet": "1.0.1",
"valtio": "1.5.2"
"valtio": "1.6.0"
},
"devDependencies": {
"@types/node": "17.0.25",
"@types/react": "17.0.40",
"@walletconnect/types": "2.0.0-beta.26",
"eslint": "8.13.0",
"eslint-config-next": "12.1.5",
"@types/node": "17.0.35",
"@types/react": "18.0.9",
"@walletconnect/types": "2.0.0-beta.100",
"eslint": "8.15.0",
"eslint-config-next": "12.1.6",
"eslint-config-prettier": "8.5.0",
"prettier": "2.6.2",
"typescript": "4.6.3"
"typescript": "4.6.4"
}
}
+2 -1
View File
@@ -17,6 +17,7 @@
.container {
width: 100%;
height: calc(100% - 220px);
display: flex;
flex: 1;
flex-direction: column;
@@ -82,4 +83,4 @@ select:hover {
i {
margin-top: -5px !important;
}
}
@@ -1,5 +1,6 @@
import ChainCard from '@/components/ChainCard'
import { truncate } from '@/utils/HelperUtil'
import { Avatar, Button, Card, Text, Tooltip } from '@nextui-org/react'
import { Avatar, Button, Text, Tooltip } from '@nextui-org/react'
import Image from 'next/image'
import { useState } from 'react'
@@ -20,50 +21,31 @@ export default function AccountCard({ name, logo, rgb, address }: Props) {
}
return (
<Card
bordered
borderWeight="light"
css={{
borderColor: `rgba(${rgb}, 0.4)`,
boxShadow: `0 0 10px 0 rgba(${rgb}, 0.15)`,
backgroundColor: `rgba(${rgb}, 0.25)`,
marginBottom: '$6',
minHeight: '70px'
}}
>
<Card.Body
css={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
overflow: 'hidden'
}}
>
<Avatar src={logo} />
<div style={{ flex: 1 }}>
<Text h5 css={{ marginLeft: '$9' }}>
{name}
</Text>
<Text weight="light" size={13} css={{ marginLeft: '$9' }}>
{truncate(address, 19)}
</Text>
</div>
<ChainCard rgb={rgb} flexDirection="row" alignItems="center">
<Avatar src={logo} />
<div style={{ flex: 1 }}>
<Text h5 css={{ marginLeft: '$9' }}>
{name}
</Text>
<Text weight="light" size={13} css={{ marginLeft: '$9' }}>
{truncate(address, 19)}
</Text>
</div>
<Tooltip content={copied ? 'Copied!' : 'Copy'} placement="left">
<Button
size="sm"
css={{ minWidth: 'auto', backgroundColor: 'rgba(255, 255, 255, 0.15)' }}
onClick={onCopy}
>
<Image
src={copied ? '/icons/checkmark-icon.svg' : '/icons/copy-icon.svg'}
width={15}
height={15}
alt="copy icon"
/>
</Button>
</Tooltip>
</Card.Body>
</Card>
<Tooltip content={copied ? 'Copied!' : 'Copy'} placement="left">
<Button
size="sm"
css={{ minWidth: 'auto', backgroundColor: 'rgba(255, 255, 255, 0.15)' }}
onClick={onCopy}
>
<Image
src={copied ? '/icons/checkmark-icon.svg' : '/icons/copy-icon.svg'}
width={15}
height={15}
alt="copy icon"
/>
</Button>
</Tooltip>
</ChainCard>
)
}
@@ -0,0 +1,36 @@
import { Card } from '@nextui-org/react'
import { ReactNode } from 'react'
interface Props {
children: ReactNode | ReactNode[]
rgb: string
flexDirection: 'row' | 'col'
alignItems: 'center' | 'flex-start'
}
export default function ChainCard({ rgb, children, flexDirection, alignItems }: Props) {
return (
<Card
bordered
borderWeight="light"
css={{
borderColor: `rgba(${rgb}, 0.4)`,
boxShadow: `0 0 10px 0 rgba(${rgb}, 0.15)`,
backgroundColor: `rgba(${rgb}, 0.25)`,
marginBottom: '$6',
minHeight: '70px'
}}
>
<Card.Body
css={{
flexDirection,
alignItems,
justifyContent: 'space-between',
overflow: 'hidden'
}}
>
{children}
</Card.Body>
</Card>
)
}
@@ -31,7 +31,7 @@ export default function Layout({ children, initialized }: Props) {
bordered={{ '@initial': false, '@xs': true }}
borderWeight={{ '@initial': 'light', '@xs': 'light' }}
css={{
height: '100vh',
height: '100%',
width: '100%',
justifyContent: initialized ? 'normal' : 'center',
alignItems: initialized ? 'normal' : 'center',
@@ -49,8 +49,10 @@ export default function Layout({ children, initialized }: Props) {
<RouteTransition>
<Card.Body
css={{
display: 'block',
paddingLeft: 2,
paddingRight: 2,
paddingBottom: '40px',
'@xs': {
padding: '20px',
paddingBottom: '40px'
@@ -69,6 +71,7 @@ export default function Layout({ children, initialized }: Props) {
justifyContent: 'flex-end',
alignItems: 'flex-end',
boxShadow: '0 -30px 20px #111111',
backgroundColor: '#111111',
zIndex: 200,
bottom: 0,
left: 0
@@ -1,11 +1,11 @@
import { Avatar, Col, Link, Row, Text } from '@nextui-org/react'
import { SessionTypes } from '@walletconnect/types'
import { SignClientTypes } from '@walletconnect/types'
/**
* Types
*/
interface IProps {
metadata: SessionTypes.Participant['metadata']
metadata: SignClientTypes.Metadata
}
/**
@@ -1,46 +1,39 @@
import AccountSelectCard from '@/components/AccountSelectCard'
import { Col, Divider, Row, Text } from '@nextui-org/react'
import { Fragment } from 'react'
import { Col, Row, Text } from '@nextui-org/react'
/**
* Types
*/
interface IProps {
name: string
chain: string
addresses: string[]
selectedAddresses: string[]
onSelect: (address: string) => void
selectedAddresses: string[] | undefined
onSelect: (chain: string, address: string) => void
}
/**
* Component
*/
export default function ProposalSelectSection({
name,
addresses,
selectedAddresses,
chain,
onSelect
}: IProps) {
return (
<Fragment>
<Divider y={2} />
<Row>
<Col>
<Text h5>{`Select ${name} Accounts`}</Text>
{addresses.map((address, index) => (
<AccountSelectCard
key={address}
address={address}
index={index}
onSelect={() => onSelect(`${chain}:${address}`)}
selected={selectedAddresses.includes(`${chain}:${address}`)}
/>
))}
</Col>
</Row>
</Fragment>
<Row>
<Col>
<Text h4 css={{ marginTop: '$5' }}>{`Choose ${chain} accounts`}</Text>
{addresses.map((address, index) => (
<AccountSelectCard
key={address}
address={address}
index={index}
onSelect={() => onSelect(chain, address)}
selected={selectedAddresses?.includes(address) ?? false}
/>
))}
</Col>
</Row>
)
}
@@ -0,0 +1,86 @@
import ChainCard from '@/components/ChainCard'
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
import { formatChainName } from '@/utils/HelperUtil'
import { Col, Row, Text } from '@nextui-org/react'
import { SessionTypes } from '@walletconnect/types'
import { Fragment } from 'react'
/**
* Utilities
*/
const CHAIN_METADATA = {
...COSMOS_MAINNET_CHAINS,
...SOLANA_MAINNET_CHAINS,
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS
}
/**
* Types
*/
interface IProps {
namespace: SessionTypes.Namespace
}
/**
* Component
*/
export default function SessionChainCard({ namespace }: IProps) {
const chains: string[] = []
// WIP
namespace.accounts.forEach(account => {
const [type, chain] = account.split(':')
const chainId = `${type}:${chain}`
chains.push(chainId)
})
return (
<Fragment>
{chains.map(chainId => {
const extensionMethods: SessionTypes.Namespace['methods'] = []
const extensionEvents: SessionTypes.Namespace['events'] = []
namespace.extension?.map(({ accounts, methods, events }) => {
accounts.forEach(account => {
const [type, chain] = account.split(':')
const chainId = `${type}:${chain}`
if (chains.includes(chainId)) {
extensionMethods.push(...methods)
extensionEvents.push(...events)
}
})
})
const allMethods = [...namespace.methods, ...extensionMethods]
const allEvents = [...namespace.events, ...extensionEvents]
// @ts-expect-error
const rgb = CHAIN_METADATA[chainId]?.rgb
return (
<ChainCard key={chainId} rgb={rgb ?? ''} flexDirection="col" alignItems="flex-start">
<Text h5 css={{ marginBottom: '$5' }}>
{formatChainName(chainId)}
</Text>
<Row>
<Col>
<Text h6>Methods</Text>
<Text color="$gray300">{allMethods.length ? allMethods.join(', ') : '-'}</Text>
</Col>
</Row>
<Row css={{ marginTop: '$5' }}>
<Col>
<Text h6>Events</Text>
<Text color="$gray300">{allEvents.length ? allEvents.join(', ') : '-'}</Text>
</Col>
</Row>
</ChainCard>
)
})}
</Fragment>
)
}
@@ -0,0 +1,72 @@
import ChainCard from '@/components/ChainCard'
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
import { formatChainName } from '@/utils/HelperUtil'
import { Col, Row, Text } from '@nextui-org/react'
import { ProposalTypes } from '@walletconnect/types'
import { Fragment } from 'react'
/**
* Utilities
*/
const CHAIN_METADATA = {
...COSMOS_MAINNET_CHAINS,
...SOLANA_MAINNET_CHAINS,
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS
}
/**
* Types
*/
interface IProps {
requiredNamespace: ProposalTypes.RequiredNamespace
}
/**
* Component
*/
export default function SessionProposalChainCard({ requiredNamespace }: IProps) {
return (
<Fragment>
{requiredNamespace.chains.map(chainId => {
const extensionMethods: ProposalTypes.RequiredNamespace['methods'] = []
const extensionEvents: ProposalTypes.RequiredNamespace['events'] = []
requiredNamespace.extension?.map(({ chains, methods, events }) => {
if (chains.includes(chainId)) {
extensionMethods.push(...methods)
extensionEvents.push(...events)
}
})
const allMethods = [...requiredNamespace.methods, ...extensionMethods]
const allEvents = [...requiredNamespace.events, ...extensionEvents]
// @ts-expect-error
const rgb = CHAIN_METADATA[chainId]?.rgb
return (
<ChainCard key={chainId} rgb={rgb ?? ''} flexDirection="col" alignItems="flex-start">
<Text h5 css={{ marginBottom: '$5' }}>
{formatChainName(chainId)}
</Text>
<Row>
<Col>
<Text h6>Methods</Text>
<Text color="$gray300">{allMethods.length ? allMethods.join(', ') : '-'}</Text>
</Col>
</Row>
<Row css={{ marginTop: '$5' }}>
<Col>
<Text h6>Events</Text>
<Text color="$gray300">{allEvents.length ? allEvents.join(', ') : '-'}</Text>
</Col>
</Row>
</ChainCard>
)
})}
</Fragment>
)
}
@@ -1,53 +0,0 @@
import AccountSelectCard from '@/components/AccountSelectCard'
import { Col, Divider, Row, Text } from '@nextui-org/react'
import { Fragment } from 'react'
/**
* Types
*/
interface IProps {
name: string
chain: string
addresses: string[]
selectedAddresses: string[]
onDelete: (address: string) => void
onAdd: (address: string) => void
}
/**
* Component
*/
export default function SessionSelectSection({
name,
addresses,
chain,
selectedAddresses,
onDelete,
onAdd
}: IProps) {
return (
<Fragment>
<Divider y={2} />
<Row>
<Col>
<Text h5>{`${name} Accounts`}</Text>
{addresses.map((address, index) => {
const fullAddress = `${chain}:${address}`
const selected = selectedAddresses.includes(fullAddress)
return (
<AccountSelectCard
key={address}
address={address}
index={index}
onSelect={() => (selected ? onDelete(fullAddress) : onAdd(fullAddress))}
selected={selected}
/>
)
})}
</Col>
</Row>
</Fragment>
)
}
@@ -55,7 +55,7 @@ export const EIP155_TEST_CHAINS = {
name: 'Polygon Mumbai',
logo: '/chain-logos/eip155-137.png',
rgb: '130, 71, 229',
rpc: 'https://rpc-mumbai.maticvigil.com/'
rpc: 'https://matic-mumbai.chainstacklabs.com'
}
}
@@ -2,7 +2,7 @@ import SettingsStore from '@/store/SettingsStore'
import { createOrRestoreCosmosWallet } from '@/utils/CosmosWalletUtil'
import { createOrRestoreEIP155Wallet } from '@/utils/EIP155WalletUtil'
import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil'
import { createWalletConnectClient } from '@/utils/WalletConnectUtil'
import { createSignClient } from '@/utils/WalletConnectUtil'
import { useCallback, useEffect, useState } from 'react'
export default function useInitialization() {
@@ -18,7 +18,7 @@ export default function useInitialization() {
SettingsStore.setCosmosAddress(cosmosAddresses[0])
SettingsStore.setSolanaAddress(solanaAddresses[0])
await createWalletConnectClient()
await createSignClient()
setInitialized(true)
} catch (err: unknown) {
@@ -2,69 +2,72 @@ import { COSMOS_SIGNING_METHODS } from '@/data/COSMOSData'
import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data'
import { SOLANA_SIGNING_METHODS } from '@/data/SolanaData'
import ModalStore from '@/store/ModalStore'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { CLIENT_EVENTS } from '@walletconnect/client'
import { SessionTypes } from '@walletconnect/types'
import { signClient } from '@/utils/WalletConnectUtil'
import { SignClientTypes } 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 })
}, [])
/******************************************************************************
* 2. [Optional] hanle session created
*****************************************************************************/
const onSessionCreated = useCallback((created: SessionTypes.Created) => {}, [])
const onSessionProposal = useCallback(
(proposal: SignClientTypes.EventArguments['session_proposal']) => {
ModalStore.open('SessionProposalModal', { proposal })
},
[]
)
/******************************************************************************
* 3. Open 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)
const onSessionRequest = useCallback(
async (requestEvent: SignClientTypes.EventArguments['session_request']) => {
console.log('session_request', requestEvent)
const { topic, params } = requestEvent
const { request } = params
const requestSession = signClient.session.get(topic)
switch (method) {
case EIP155_SIGNING_METHODS.ETH_SIGN:
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
return ModalStore.open('SessionSignModal', { requestEvent, requestSession })
switch (request.method) {
case EIP155_SIGNING_METHODS.ETH_SIGN:
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
return ModalStore.open('SessionSignModal', { requestEvent, requestSession })
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
return ModalStore.open('SessionSignTypedDataModal', { requestEvent, requestSession })
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
return ModalStore.open('SessionSignTypedDataModal', { requestEvent, requestSession })
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
return ModalStore.open('SessionSendTransactionModal', { requestEvent, requestSession })
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
return ModalStore.open('SessionSendTransactionModal', { requestEvent, requestSession })
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_DIRECT:
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_AMINO:
return ModalStore.open('SessionSignCosmosModal', { requestEvent, requestSession })
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_DIRECT:
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_AMINO:
return ModalStore.open('SessionSignCosmosModal', { requestEvent, requestSession })
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_MESSAGE:
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTION:
return ModalStore.open('SessionSignSolanaModal', { requestEvent, requestSession })
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_MESSAGE:
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTION:
return ModalStore.open('SessionSignSolanaModal', { requestEvent, requestSession })
default:
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession })
}
}, [])
default:
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession })
}
},
[]
)
/******************************************************************************
* Set up WalletConnect event listeners
*****************************************************************************/
useEffect(() => {
if (initialized) {
walletConnectClient.on(CLIENT_EVENTS.session.proposal, onSessionProposal)
walletConnectClient.on(CLIENT_EVENTS.session.created, onSessionCreated)
walletConnectClient.on(CLIENT_EVENTS.session.request, onSessionRequest)
signClient.on('session_proposal', onSessionProposal)
signClient.on('session_request', onSessionRequest)
// TODOs
signClient.on('session_ping', data => console.log('ping', data))
signClient.on('session_event', data => console.log('event', data))
signClient.on('session_update', data => console.log('update', data))
signClient.on('session_delete', data => console.log('delete', data))
}
}, [initialized, onSessionProposal, onSessionCreated, onSessionRequest])
}, [initialized, onSessionProposal, onSessionRequest])
}
+7 -10
View File
@@ -1,18 +1,15 @@
import PageHeader from '@/components/PageHeader'
import PairingCard from '@/components/PairingCard'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Text } from '@nextui-org/react'
import { ERROR } from '@walletconnect/utils'
import { Fragment, useState } from 'react'
export default function PairingsPage() {
const [pairings, setPairings] = useState(walletConnectClient.pairing.values)
const [pairings, setPairings] = useState(signClient.pairing.values)
async function onDelete(topic: string) {
await walletConnectClient.pairing.delete({
topic,
reason: ERROR.DELETED.format()
})
await signClient.disconnect({ topic, reason: ERROR.DELETED.format() })
const newPairings = pairings.filter(pairing => pairing.topic !== topic)
setPairings(newPairings)
}
@@ -22,14 +19,14 @@ export default function PairingsPage() {
<PageHeader title="Pairings" />
{pairings.length ? (
pairings.map(pairing => {
const { metadata } = pairing.state
const { peerMetadata } = pairing
return (
<PairingCard
key={pairing.topic}
logo={metadata?.icons[0]}
url={metadata?.url}
name={metadata?.name}
logo={peerMetadata?.icons[0]}
url={peerMetadata?.url}
name={peerMetadata?.name}
onDelete={() => onDelete(pairing.topic)}
/>
)
+101 -90
View File
@@ -1,15 +1,8 @@
import PageHeader from '@/components/PageHeader'
import ProjectInfoCard from '@/components/ProjectInfoCard'
import SessionSelectSection from '@/components/SessionSelectSection'
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
import { isCosmosChain, isEIP155Chain, isSolanaChain } from '@/utils/HelperUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { Button, Col, Divider, Row, Text } from '@nextui-org/react'
import SessionChainCard from '@/components/SessionChainCard'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Loading, Row, Text } from '@nextui-org/react'
import { ERROR } from '@walletconnect/utils'
import { useRouter } from 'next/router'
import { Fragment, useEffect, useState } from 'react'
@@ -21,6 +14,7 @@ export default function SessionPage() {
const [topic, setTopic] = useState('')
const [updated, setUpdated] = useState(new Date())
const { query, replace } = useRouter()
const [loading, setLoading] = useState(false)
useEffect(() => {
if (query?.topic) {
@@ -28,7 +22,7 @@ export default function SessionPage() {
}
}, [query])
const session = walletConnectClient.session.values.find(s => s.topic === topic)
const session = signClient.session.values.find(s => s.topic === topic)
if (!session) {
return null
@@ -36,116 +30,133 @@ export default function SessionPage() {
// Get necessary data from session
const expiryDate = new Date(session.expiry * 1000)
const { chains } = session.permissions.blockchain
const { methods } = session.permissions.jsonrpc
const { accounts } = session.state
const { namespaces } = session
// Handle deletion of a session
async function onDeleteSession() {
await walletConnectClient.session.delete({
topic,
reason: ERROR.DELETED.format()
})
setLoading(true)
await signClient.disconnect({ topic, reason: ERROR.DELETED.format() })
replace('/sessions')
setLoading(false)
}
// Hanlde deletion of session account
async function onDeleteAccount(account: string) {
const newAccounts = accounts.filter(a => a !== account)
await walletConnectClient.session.update({
topic,
state: {
accounts: newAccounts
}
})
setUpdated(new Date())
async function onSessionPing() {
setLoading(true)
await signClient.ping({ topic })
setLoading(false)
}
// Handle addition of account to the session
async function onAddAccount(account: string) {
await walletConnectClient.session.update({
async function onSessionEmit() {
setLoading(true)
console.log('baleg')
await signClient.emit({
topic,
state: {
accounts: [...accounts, account]
}
event: { name: 'chainChanged', data: 'Hello World' },
chainId: 'eip155:1'
})
setUpdated(new Date())
setLoading(false)
}
const newNs = {
eip155: {
accounts: [
'eip155:1:0x70012948c348CBF00806A3C79E3c5DAdFaAa347B',
'eip155:137:0x70012948c348CBF00806A3C79E3c5DAdFaAa347B'
],
methods: ['personal_sign', 'eth_signTypedData', 'eth_sendTransaction'],
events: []
}
}
async function onSessionUpdate() {
setLoading(true)
const { acknowledged } = await signClient.update({ topic, namespaces: newNs })
await acknowledged()
setUpdated(new Date())
setLoading(false)
}
// function renderAccountSelection(chain: string) {
// if (isEIP155Chain(chain)) {
// return (
// <ProposalSelectSection
// addresses={eip155Addresses}
// selectedAddresses={selectedAccounts[chain]}
// onSelect={onSelectAccount}
// chain={chain}
// />
// )
// } else if (isCosmosChain(chain)) {
// return (
// <ProposalSelectSection
// addresses={cosmosAddresses}
// selectedAddresses={selectedAccounts[chain]}
// onSelect={onSelectAccount}
// chain={chain}
// />
// )
// } else if (isSolanaChain(chain)) {
// return (
// <ProposalSelectSection
// addresses={solanaAddresses}
// selectedAddresses={selectedAccounts[chain]}
// onSelect={onSelectAccount}
// chain={chain}
// />
// )
// }
// }
return (
<Fragment>
<PageHeader title="Session Details" />
<ProjectInfoCard metadata={session.peer.metadata} />
{chains.map(chain => {
if (isEIP155Chain(chain)) {
return (
<SessionSelectSection
key={chain}
chain={chain}
name={EIP155_CHAINS[chain as TEIP155Chain]?.name}
addresses={eip155Addresses}
selectedAddresses={accounts}
onDelete={onDeleteAccount}
onAdd={onAddAccount}
/>
)
} else if (isCosmosChain(chain)) {
return (
<SessionSelectSection
key={chain}
chain={chain}
name={COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name}
addresses={cosmosAddresses}
selectedAddresses={accounts}
onDelete={onDeleteAccount}
onAdd={onAddAccount}
/>
)
} else if (isSolanaChain(chain)) {
return (
<SessionSelectSection
key={chain}
chain={chain}
name={SOLANA_CHAINS[chain as TSolanaChain]?.name}
addresses={solanaAddresses}
selectedAddresses={accounts}
onDelete={onDeleteAccount}
onAdd={onAddAccount}
/>
)
}
<Divider y={2} />
{Object.keys(namespaces).map(chain => {
return (
<Fragment key={chain}>
<Text h4 css={{ marginBottom: '$5' }}>{`Review ${chain} permissions`}</Text>
<SessionChainCard namespace={namespaces[chain]} />
{/* {renderAccountSelection(chain)} */}
<Divider y={2} />
</Fragment>
)
})}
<Divider y={1} />
<Row>
<Col>
<Text h5>Methods</Text>
<Text color="$gray400">{methods.map(method => method).join(', ')}</Text>
</Col>
</Row>
<Divider y={1} />
<Row justify="space-between">
<Text h5>Expiry</Text>
<Text css={{ color: '$gray400' }}>{expiryDate.toDateString()}</Text>
</Row>
<Divider y={1} />
<Row justify="space-between">
<Text h5>Last Updated</Text>
<Text css={{ color: '$gray400' }}>{updated.toDateString()}</Text>
</Row>
<Divider y={1} />
<Row>
<Row css={{ marginTop: '$10' }}>
<Button flat css={{ width: '100%' }} color="error" onClick={onDeleteSession}>
Delete Session
{loading ? <Loading size="sm" color="error" /> : 'Delete'}
</Button>
</Row>
<Row css={{ marginTop: '$10' }}>
<Button flat css={{ width: '100%' }} color="primary" onClick={onSessionPing}>
{loading ? <Loading size="sm" color="primary" /> : 'Ping'}
</Button>
</Row>
<Row css={{ marginTop: '$10' }}>
<Button flat css={{ width: '100%' }} color="secondary" onClick={onSessionEmit}>
{loading ? <Loading size="sm" color="secondary" /> : 'Emit'}
</Button>
</Row>
<Row css={{ marginTop: '$10' }}>
<Button flat css={{ width: '100%' }} color="warning" onClick={onSessionUpdate}>
{loading ? <Loading size="sm" color="warning" /> : 'Update'}
</Button>
</Row>
</Fragment>
@@ -1,11 +1,11 @@
import PageHeader from '@/components/PageHeader'
import SessionCard from '@/components/SessionCard'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Text } from '@nextui-org/react'
import { Fragment, useState } from 'react'
export default function SessionsPage() {
const [sessions, setSessions] = useState(walletConnectClient.session.values)
const [sessions, setSessions] = useState(signClient.session.values)
return (
<Fragment>
@@ -6,6 +6,7 @@ import { solanaWallets } from '@/utils/SolanaWalletUtil'
import { Card, Divider, Row, Switch, Text } from '@nextui-org/react'
import { Fragment } from 'react'
import { useSnapshot } from 'valtio'
import packageJSON from '../../package.json'
export default function SettingsPage() {
const { testNets, eip155Address, cosmosAddress, solanaAddress } = useSnapshot(SettingsStore.state)
@@ -14,6 +15,24 @@ export default function SettingsPage() {
<Fragment>
<PageHeader title="Settings" />
<Text h4 css={{ marginBottom: '$5' }}>
Packages
</Text>
<Row justify="space-between" align="center">
<Text color="$gray400">@walletconnect/sign-client</Text>
<Text color="$gray400">{packageJSON.dependencies['@walletconnect/sign-client']}</Text>
</Row>
<Row justify="space-between" align="center">
<Text color="$gray400">@walletconnect/utils</Text>
<Text color="$gray400">{packageJSON.dependencies['@walletconnect/utils']}</Text>
</Row>
<Row justify="space-between" align="center">
<Text color="$gray400">@walletconnect/types</Text>
<Text color="$gray400">{packageJSON.devDependencies['@walletconnect/types']}</Text>
</Row>
<Divider y={2} />
<Text h4 css={{ marginBottom: '$5' }}>
Testnets
</Text>
@@ -1,6 +1,6 @@
import PageHeader from '@/components/PageHeader'
import QrReader from '@/components/QrReader'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Input, Loading, Text } from '@nextui-org/react'
import { Fragment, useState } from 'react'
@@ -11,7 +11,7 @@ export default function WalletConnectPage() {
async function onConnect(uri: string) {
try {
setLoading(true)
await walletConnectClient.pair({ uri })
await signClient.pair({ uri })
} catch (err: unknown) {
alert(err)
} finally {
@@ -31,6 +31,7 @@ export default function WalletConnectPage() {
</Text>
<Input
css={{ width: '100%' }}
bordered
aria-label="wc url connect input"
placeholder="e.g. wc:a281567bb3e4..."
@@ -1,14 +1,13 @@
import { SessionTypes } from '@walletconnect/types'
import { SessionTypes, SignClientTypes } from '@walletconnect/types'
import { proxy } from 'valtio'
/**
* Types
*/
interface ModalData {
proposal?: SessionTypes.Proposal
created?: SessionTypes.Created
requestEvent?: SessionTypes.RequestEvent
requestSession?: SessionTypes.Settled
proposal?: SignClientTypes.EventArguments['session_proposal']
requestEvent?: SignClientTypes.EventArguments['session_request']
requestSession?: SessionTypes.Struct
}
interface State {
@@ -2,24 +2,30 @@ import { COSMOS_SIGNING_METHODS } from '@/data/COSMOSData'
import { cosmosAddresses, cosmosWallets } from '@/utils/CosmosWalletUtil'
import { getWalletAddressFromParams } from '@/utils/HelperUtil'
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
import { RequestEvent } from '@walletconnect/types'
import { SignClientTypes } from '@walletconnect/types'
import { ERROR } from '@walletconnect/utils'
import { parseSignDocValues } from 'cosmos-wallet'
export async function approveCosmosRequest(requestEvent: RequestEvent) {
const { method, params, id } = requestEvent.request
export async function approveCosmosRequest(
requestEvent: SignClientTypes.EventArguments['session_request']
) {
const { params, id } = requestEvent
const { request } = params
const wallet = cosmosWallets[getWalletAddressFromParams(cosmosAddresses, params)]
switch (method) {
switch (request.method) {
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_DIRECT:
const signedDirect = await wallet.signDirect(
params.signerAddress,
parseSignDocValues(params.signDoc)
request.params.signerAddress,
parseSignDocValues(request.params.signDoc)
)
return formatJsonRpcResult(id, signedDirect.signature)
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_AMINO:
const signedAmino = await wallet.signAmino(params.signerAddress, params.signDoc)
const signedAmino = await wallet.signAmino(
request.params.signerAddress,
request.params.signDoc
)
return formatJsonRpcResult(id, signedAmino.signature)
default:
@@ -27,7 +33,7 @@ export async function approveCosmosRequest(requestEvent: RequestEvent) {
}
}
export function rejectCosmosRequest(request: RequestEvent['request']) {
export function rejectCosmosRequest(request: SignClientTypes.EventArguments['session_request']) {
const { id } = request
return formatJsonRpcError(id, ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format().message)
@@ -6,26 +6,28 @@ import {
getWalletAddressFromParams
} from '@/utils/HelperUtil'
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
import { RequestEvent } from '@walletconnect/types'
import { SignClientTypes } from '@walletconnect/types'
import { ERROR } from '@walletconnect/utils'
import { providers } from 'ethers'
export async function approveEIP155Request(requestEvent: RequestEvent) {
const { method, params, id } = requestEvent.request
const { chainId } = requestEvent
export async function approveEIP155Request(
requestEvent: SignClientTypes.EventArguments['session_request']
) {
const { params, id } = requestEvent
const { chainId, request } = params
const wallet = eip155Wallets[getWalletAddressFromParams(eip155Addresses, params)]
switch (method) {
switch (request.method) {
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
case EIP155_SIGNING_METHODS.ETH_SIGN:
const message = getSignParamsMessage(params)
const message = getSignParamsMessage(request.params)
const signedMessage = await wallet.signMessage(message)
return formatJsonRpcResult(id, signedMessage)
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
const { domain, types, message: data } = getSignTypedDataParamsData(params)
const { domain, types, message: data } = getSignTypedDataParamsData(request.params)
// https://github.com/ethers-io/ethers.js/issues/687#issuecomment-714069471
delete types.EIP712Domain
const signedData = await wallet._signTypedData(domain, types, data)
@@ -33,13 +35,13 @@ export async function approveEIP155Request(requestEvent: RequestEvent) {
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
const provider = new providers.JsonRpcProvider(EIP155_CHAINS[chainId as TEIP155Chain].rpc)
const sendTransaction = params[0]
const sendTransaction = request.params[0]
const connectedWallet = wallet.connect(provider)
const { hash } = await connectedWallet.sendTransaction(sendTransaction)
return formatJsonRpcResult(id, hash)
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
const signTransaction = params[0]
const signTransaction = request.params[0]
const signature = await wallet.signTransaction(signTransaction)
return formatJsonRpcResult(id, signature)
@@ -48,7 +50,7 @@ export async function approveEIP155Request(requestEvent: RequestEvent) {
}
}
export function rejectEIP155Request(request: RequestEvent['request']) {
export function rejectEIP155Request(request: SignClientTypes.EventArguments['session_request']) {
const { id } = request
return formatJsonRpcError(id, ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format().message)
@@ -1,3 +1,6 @@
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { utils } from 'ethers'
/**
@@ -90,3 +93,15 @@ export function isCosmosChain(chain: string) {
export function isSolanaChain(chain: string) {
return chain.includes('solana')
}
/**
* Formats chainId to its name
*/
export function formatChainName(chainId: string) {
return (
EIP155_CHAINS[chainId as TEIP155Chain]?.name ??
COSMOS_MAINNET_CHAINS[chainId as TCosmosChain]?.name ??
SOLANA_CHAINS[chainId as TSolanaChain]?.name ??
chainId
)
}
@@ -2,23 +2,26 @@ import { SOLANA_SIGNING_METHODS } from '@/data/SolanaData'
import { getWalletAddressFromParams } from '@/utils/HelperUtil'
import { solanaAddresses, solanaWallets } from '@/utils/SolanaWalletUtil'
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
import { RequestEvent } from '@walletconnect/types'
import { SignClientTypes } from '@walletconnect/types'
import { ERROR } from '@walletconnect/utils'
export async function approveSolanaRequest(requestEvent: RequestEvent) {
const { method, params, id } = requestEvent.request
export async function approveSolanaRequest(
requestEvent: SignClientTypes.EventArguments['session_request']
) {
const { params, id } = requestEvent
const { request } = params
const wallet = solanaWallets[getWalletAddressFromParams(solanaAddresses, params)]
switch (method) {
switch (request.method) {
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_MESSAGE:
const signedMessage = await wallet.signMessage(params.message)
const signedMessage = await wallet.signMessage(request.params.message)
return formatJsonRpcResult(id, signedMessage)
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTION:
const signedTransaction = await wallet.signTransaction(
params.feePayer,
params.recentBlockhash,
params.instructions
request.params.feePayer,
request.params.recentBlockhash,
request.params.instructions
)
return formatJsonRpcResult(id, signedTransaction)
@@ -28,7 +31,7 @@ export async function approveSolanaRequest(requestEvent: RequestEvent) {
}
}
export function rejectSolanaRequest(request: RequestEvent['request']) {
export function rejectSolanaRequest(request: SignClientTypes.EventArguments['session_request']) {
const { id } = request
return formatJsonRpcError(id, ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format().message)
@@ -1,10 +1,9 @@
import WalletConnectClient from '@walletconnect/client'
import SignClient from '@walletconnect/sign-client'
export let walletConnectClient: WalletConnectClient
export let signClient: SignClient
export async function createWalletConnectClient() {
walletConnectClient = await WalletConnectClient.init({
controller: true,
export async function createSignClient() {
signClient = await SignClient.init({
projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
relayUrl: process.env.NEXT_PUBLIC_RELAY_URL ?? 'wss://relay.walletconnect.com',
metadata: {
@@ -1,25 +1,21 @@
import ProjectInfoCard from '@/components/ProjectInfoCard'
import ProposalSelectSection from '@/components/ProposalSelectSection'
import RequesDetailsCard from '@/components/RequestDetalilsCard'
import RequestMethodCard from '@/components/RequestMethodCard'
import RequestModalContainer from '@/components/RequestModalContainer'
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import SessionProposalChainCard from '@/components/SessionProposalChainCard'
import ModalStore from '@/store/ModalStore'
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
import { isCosmosChain, isEIP155Chain, isSolanaChain } from '@/utils/HelperUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { SessionTypes } from '@walletconnect/types'
import { ERROR } from '@walletconnect/utils'
import { Fragment, useState } from 'react'
export default function SessionProposalModal() {
const [selectedEIP155, setSelectedEip155] = useState<string[]>([])
const [selectedCosmos, setSelectedCosmos] = useState<string[]>([])
const [selectedSolana, setSelectedSolana] = useState<string[]>([])
const allSelected = [...selectedEIP155, ...selectedCosmos, ...selectedSolana]
const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({})
const hasSelected = Object.keys(selectedAccounts).length
// Get proposal data and wallet address from store
const proposal = ModalStore.state.data?.proposal
@@ -30,50 +26,48 @@ export default function SessionProposalModal() {
}
// Get required proposal data
const { proposer, permissions, relay } = proposal
const { chains } = permissions.blockchain
const { methods } = permissions.jsonrpc
const { id, params } = proposal
const { proposer, requiredNamespaces, relays } = params
// Add / remove address from EIP155 selection
function onSelectEIP155(address: string) {
if (selectedEIP155.includes(address)) {
const newAddresses = selectedEIP155.filter(a => a !== address)
setSelectedEip155(newAddresses)
function onSelectAccount(chain: string, account: string) {
if (selectedAccounts[chain]?.includes(account)) {
const newSelectedAccounts = selectedAccounts[chain]?.filter(a => a !== account)
setSelectedAccounts(prev => ({
...prev,
[chain]: newSelectedAccounts
}))
} else {
setSelectedEip155([...selectedEIP155, address])
const prevChainAddresses = selectedAccounts[chain] ?? []
setSelectedAccounts(prev => ({
...prev,
[chain]: [...prevChainAddresses, account]
}))
}
}
// Add / remove address from Cosmos selection
function onSelectCosmos(address: string) {
if (selectedCosmos.includes(address)) {
const newAddresses = selectedCosmos.filter(a => a !== address)
setSelectedCosmos(newAddresses)
} else {
setSelectedCosmos([...selectedCosmos, address])
}
}
// Add / remove address from Solana selection
function onSelectSolana(address: string) {
if (selectedSolana.includes(address)) {
const newAddresses = selectedSolana.filter(a => a !== address)
setSelectedSolana(newAddresses)
} else {
setSelectedSolana([...selectedSolana, address])
}
}
// Hanlde approve action
// Hanlde approve action, construct session namespace
async function onApprove() {
if (proposal) {
const accounts = allSelected
const response = {
state: {
accounts
const namespaces: SessionTypes.Namespaces = {}
Object.keys(requiredNamespaces).forEach(key => {
const accounts: string[] = []
requiredNamespaces[key].chains.map(chain => {
selectedAccounts[key].map(acc => accounts.push(`${chain}:${acc}`))
})
namespaces[key] = {
accounts,
methods: requiredNamespaces[key].methods,
events: requiredNamespaces[key].events
}
}
await walletConnectClient.approve({ proposal, response })
})
const { acknowledged } = await signClient.approve({
id,
relayProtocol: relays[0].protocol,
namespaces
})
await acknowledged()
}
ModalStore.close()
}
@@ -81,56 +75,64 @@ export default function SessionProposalModal() {
// Hanlde reject action
async function onReject() {
if (proposal) {
await walletConnectClient.reject({ proposal })
await signClient.reject({
id,
reason: ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format()
})
}
ModalStore.close()
}
// Render account selection checkboxes based on chain
function renderAccountSelection(chain: string) {
if (isEIP155Chain(chain)) {
return (
<ProposalSelectSection
addresses={eip155Addresses}
selectedAddresses={selectedAccounts[chain]}
onSelect={onSelectAccount}
chain={chain}
/>
)
} else if (isCosmosChain(chain)) {
return (
<ProposalSelectSection
addresses={cosmosAddresses}
selectedAddresses={selectedAccounts[chain]}
onSelect={onSelectAccount}
chain={chain}
/>
)
} else if (isSolanaChain(chain)) {
return (
<ProposalSelectSection
addresses={solanaAddresses}
selectedAddresses={selectedAccounts[chain]}
onSelect={onSelectAccount}
chain={chain}
/>
)
}
}
return (
<Fragment>
<RequestModalContainer title="Session Proposal">
<ProjectInfoCard metadata={proposer.metadata} />
<Divider y={2} />
<RequesDetailsCard chains={chains} protocol={relay.protocol} />
{/* TODO(ilja) Relays selection */}
<Divider y={2} />
<RequestMethodCard methods={methods} />
{chains.map(chain => {
if (isEIP155Chain(chain)) {
return (
<ProposalSelectSection
name={EIP155_CHAINS[chain as TEIP155Chain]?.name}
addresses={eip155Addresses}
selectedAddresses={selectedEIP155}
onSelect={onSelectEIP155}
chain={chain}
/>
)
} else if (isCosmosChain(chain)) {
return (
<ProposalSelectSection
name={COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name}
addresses={cosmosAddresses}
selectedAddresses={selectedCosmos}
onSelect={onSelectCosmos}
chain={chain}
/>
)
} else if (isSolanaChain(chain)) {
return (
<ProposalSelectSection
name={SOLANA_CHAINS[chain as TSolanaChain]?.name}
addresses={solanaAddresses}
selectedAddresses={selectedSolana}
onSelect={onSelectSolana}
chain={chain}
/>
)
}
{Object.keys(requiredNamespaces).map(chain => {
return (
<Fragment key={chain}>
<Text h4 css={{ marginBottom: '$5' }}>{`Review ${chain} permissions`}</Text>
<SessionProposalChainCard requiredNamespace={requiredNamespaces[chain]} />
{renderAccountSelection(chain)}
<Divider y={2} />
</Fragment>
)
})}
</RequestModalContainer>
@@ -144,10 +146,8 @@ export default function SessionProposalModal() {
flat
color="success"
onClick={onApprove}
disabled={!allSelected.length}
css={{
opacity: allSelected.length ? 1 : 0.4
}}
disabled={!hasSelected}
css={{ opacity: hasSelected ? 1 : 0.4 }}
>
Approve
</Button>
@@ -5,7 +5,7 @@ import RequestMethodCard from '@/components/RequestMethodCard'
import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Loading, Modal, Text } from '@nextui-org/react'
import { Fragment, useState } from 'react'
@@ -23,16 +23,17 @@ export default function SessionSendTransactionModal() {
// Get required proposal data
const { method, params } = requestEvent.request
const transaction = params[0]
const { topic, params } = requestEvent
const { request, chainId } = params
const transaction = request.params[0]
// Handle approve action
async function onApprove() {
if (requestEvent) {
setLoading(true)
const response = await approveEIP155Request(requestEvent)
await walletConnectClient.respond({
topic: requestEvent.topic,
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -42,9 +43,9 @@ export default function SessionSendTransactionModal() {
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectEIP155Request(requestEvent.request)
await walletConnectClient.respond({
topic: requestEvent.topic,
const response = rejectEIP155Request(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -62,14 +63,11 @@ export default function SessionSendTransactionModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
@@ -5,7 +5,7 @@ import RequestMethodCard from '@/components/RequestMethodCard'
import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { approveCosmosRequest, rejectCosmosRequest } from '@/utils/CosmosRequestHandler'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { Fragment } from 'react'
@@ -20,14 +20,15 @@ export default function SessionSignCosmosModal() {
}
// Get required request data
const { method, params } = requestEvent.request
const { topic, params } = requestEvent
const { chainId, request } = params
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveCosmosRequest(requestEvent)
await walletConnectClient.respond({
topic: requestEvent.topic,
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -37,9 +38,9 @@ export default function SessionSignCosmosModal() {
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectCosmosRequest(requestEvent.request)
await walletConnectClient.respond({
topic: requestEvent.topic,
const response = rejectCosmosRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -53,10 +54,7 @@ export default function SessionSignCosmosModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
@@ -64,7 +62,7 @@ export default function SessionSignCosmosModal() {
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
@@ -5,7 +5,7 @@ import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
import { getSignParamsMessage } from '@/utils/HelperUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Col, Divider, Modal, Row, Text } from '@nextui-org/react'
import { Fragment } from 'react'
@@ -20,17 +20,18 @@ export default function SessionSignModal() {
}
// Get required request data
const { method, params } = requestEvent.request
const { topic, params } = requestEvent
const { request, chainId } = params
// Get message, convert it to UTF8 string if it is valid hex
const message = getSignParamsMessage(params)
const message = getSignParamsMessage(request.params)
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveEIP155Request(requestEvent)
await walletConnectClient.respond({
topic: requestEvent.topic,
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -40,9 +41,9 @@ export default function SessionSignModal() {
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectEIP155Request(requestEvent.request)
await walletConnectClient.respond({
topic: requestEvent.topic,
const response = rejectEIP155Request(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -56,10 +57,7 @@ export default function SessionSignModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
@@ -72,7 +70,7 @@ export default function SessionSignModal() {
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
@@ -5,7 +5,7 @@ import RequestMethodCard from '@/components/RequestMethodCard'
import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { approveSolanaRequest, rejectSolanaRequest } from '@/utils/SolanaRequestHandlerUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { Fragment } from 'react'
@@ -20,14 +20,15 @@ export default function SessionSignSolanaModal() {
}
// Get required request data
const { method, params } = requestEvent.request
const { topic, params } = requestEvent
const { request, chainId } = params
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveSolanaRequest(requestEvent)
await walletConnectClient.respond({
topic: requestEvent.topic,
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -37,9 +38,9 @@ export default function SessionSignSolanaModal() {
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectSolanaRequest(requestEvent.request)
await walletConnectClient.respond({
topic: requestEvent.topic,
const response = rejectSolanaRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -53,10 +54,7 @@ export default function SessionSignSolanaModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
@@ -64,7 +62,7 @@ export default function SessionSignSolanaModal() {
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
@@ -6,7 +6,7 @@ import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
import { getSignTypedDataParamsData } from '@/utils/HelperUtil'
import { walletConnectClient } from '@/utils/WalletConnectUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { Fragment } from 'react'
@@ -21,17 +21,18 @@ export default function SessionSignTypedDataModal() {
}
// Get required request data
const { method, params } = requestEvent.request
const { topic, params } = requestEvent
const { request, chainId } = params
// Get data
const data = getSignTypedDataParamsData(params)
const data = getSignTypedDataParamsData(request.params)
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveEIP155Request(requestEvent)
await walletConnectClient.respond({
topic: requestEvent.topic,
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -41,9 +42,9 @@ export default function SessionSignTypedDataModal() {
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectEIP155Request(requestEvent.request)
await walletConnectClient.respond({
topic: requestEvent.topic,
const response = rejectEIP155Request(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
@@ -57,10 +58,7 @@ export default function SessionSignTypedDataModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
@@ -68,7 +66,7 @@ export default function SessionSignTypedDataModal() {
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
@@ -17,7 +17,8 @@ export default function SessionUnsuportedMethodModal() {
}
// Get required request data
const { method } = requestEvent.request
const { topic, params } = requestEvent
const { chainId, request } = params
return (
<Fragment>
@@ -26,14 +27,11 @@ export default function SessionUnsuportedMethodModal() {
<Divider y={2} />
<RequesDetailsCard
chains={[requestEvent.chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
<RequestMethodCard methods={[method]} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
File diff suppressed because it is too large Load Diff