diff --git a/wallets/react-wallet-v2/README.md b/wallets/react-wallet-v2/README.md index 52a7d64..7fee00e 100644 --- a/wallets/react-wallet-v2/README.md +++ b/wallets/react-wallet-v2/README.md @@ -1,26 +1,26 @@ -# WalletConnect React Wallet Example +# Wallet Example (React, Typescript, Ethers, NextJS, Cosmos) + +This example aims to demonstrate basic and advanced use cases enabled by WalletConnect. Please only use this for refference and development purposes, otherwise you are at risk of loosing your funds. + +# Useful links -⚠️ Wallet should only be used as a refference example & for development purposes
🔗 Live wallet app - https://react-wallet-v2.vercel.app
-🔗 Live dapp app - https://react-dapp-v2.vercel.app
+🔗 Live dapp - https://react-dapp-v2.vercel.app
📚 WalletConnect docs - https://docs.walletconnect.com/2.0 -Example wallet implementation using [WalletConnect](https://walletconnect.com/), [Ethers](https://docs.ethers.io/v5/), [React](https://reactjs.org/) and [TypeScript](https://www.typescriptlang.org) - ## Getting started -This example is built atop of [NextJS](https://nextjs.org/) in order to abstract complexity of setting up bundlers, routing etc.. So there are only few steps you need to follow in order to set everything up +Eexample is built atop of [NextJS](https://nextjs.org/) in order to abstract complexity of setting up bundlers, routing etc. So there are few steps you need to follow in order to set everything up 1. Go to [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) and obtain a project id -2. Add your project details in [WalletConnectUtil.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts) file. -3. [Optional] To use project id as environment variable follow [NextJS environment docs](https://nextjs.org/docs/basic-features/environment-variables) -4. Install dependencies `yarn install` or `npm install` -5. Run `yarn dev` or `npm run dev` to start local development +2. Add your project details in [WalletConnectUtil.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts) file +3. Install dependencies `yarn install` or `npm install` +4. Run `yarn dev` or `npm run dev` to start local development -## Navigating through this example +## Navigating through example -1. Initial setup and initializations happen in [_app.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/pages/_app.tsx) file. -2. WalletConnect client and ethers wallets are initialized in [useInitialization.ts ](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/hooks/useInitialization.ts) hook -3. Subscription and handling of WalletConnect events happens in [useWalletConnectEventsManager.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts) hook, that oppens related [Modal views](https://github.com/WalletConnect/web-examples/tree/main/wallets/react-wallet-v2/src/views) and passes them all necesary data. -4. [Modal views](https://github.com/WalletConnect/web-examples/tree/main/wallets/react-wallet-v2/src/views) are responsible for data display and handling approval or rejection actions. -5. Uppon approval or rejection modals pass request data to [RequestHandlerUtil.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts) that performs all necesary ethers work based on request method and returns formated json rpc result data that can be then used for WallteConnect client responses. +1. Initial setup and initializations happen in [_app.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/pages/_app.tsx) file +2. WalletConnect client, ethers and cosmos wallets are initialized in [useInitialization.ts ](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/hooks/useInitialization.ts) hook +3. Subscription and handling of WalletConnect events happens in [useWalletConnectEventsManager.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts) hook, that oppens related [Modal views](https://github.com/WalletConnect/web-examples/tree/main/wallets/react-wallet-v2/src/views) and passes them all necesary data +4. [Modal views](https://github.com/WalletConnect/web-examples/tree/main/wallets/react-wallet-v2/src/views) are responsible for data display and handling approval or rejection actions +5. Uppon approval or rejection modals pass request data to [RequestHandlerUtil.ts](https://github.com/WalletConnect/web-examples/blob/main/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts) that performs all necesary work based on request method and returns formated json rpc result data that can be then used for WallteConnect client responses diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index c4271fc..faf912b 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -31,7 +31,7 @@ "@types/react": "17.0.39", "eslint": "8.10.0", "eslint-config-next": "12.1.0", - "eslint-config-prettier": "8.4.0", + "eslint-config-prettier": "8.5.0", "prettier": "2.5.1", "typescript": "4.6.2" } diff --git a/wallets/react-wallet-v2/src/components/ProjectInfoCard.tsx b/wallets/react-wallet-v2/src/components/ProjectInfoCard.tsx new file mode 100644 index 0000000..9d96823 --- /dev/null +++ b/wallets/react-wallet-v2/src/components/ProjectInfoCard.tsx @@ -0,0 +1,28 @@ +import { Avatar, Col, Link, Row, Text } from '@nextui-org/react' +import { SessionTypes } from '@walletconnect/types' + +/** + * Types + */ +interface IProps { + metadata: SessionTypes.Participant['metadata'] +} + +/** + * Components + */ +export default function ProjectInfoCard({ metadata }: IProps) { + const { icons, name, url } = metadata + + return ( + + + + + + {name} + {url} + + + ) +} diff --git a/wallets/react-wallet-v2/src/components/RequestDataCard.tsx b/wallets/react-wallet-v2/src/components/RequestDataCard.tsx new file mode 100644 index 0000000..28cff88 --- /dev/null +++ b/wallets/react-wallet-v2/src/components/RequestDataCard.tsx @@ -0,0 +1,28 @@ +import { Col, Row, Text } from '@nextui-org/react' +import { CodeBlock, codepen } from 'react-code-blocks' + +/** + * Types + */ +interface IProps { + data: Record +} + +/** + * Component + */ +export default function RequestDataCard({ data }: IProps) { + return ( + + + Data + + + + ) +} diff --git a/wallets/react-wallet-v2/src/components/RequestDetalilsCard.tsx b/wallets/react-wallet-v2/src/components/RequestDetalilsCard.tsx new file mode 100644 index 0000000..2a728ab --- /dev/null +++ b/wallets/react-wallet-v2/src/components/RequestDetalilsCard.tsx @@ -0,0 +1,46 @@ +import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData' +import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' +import { Col, Divider, Row, Text } from '@nextui-org/react' +import { Fragment } from 'react' + +/** + * Types + */ +interface IProps { + chains: string[] + protocol: string +} + +/** + * Component + */ +export default function RequesDetailsCard({ chains, protocol }: IProps) { + return ( + + + + Blockchain(s) + + {chains + .map( + chain => + EIP155_CHAINS[chain as TEIP155Chain]?.name ?? + COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name ?? + chain + ) + .join(', ')} + + + + + + + + + Relay Protocol + {protocol} + + + + ) +} diff --git a/wallets/react-wallet-v2/src/components/RequestMethodCard.tsx b/wallets/react-wallet-v2/src/components/RequestMethodCard.tsx new file mode 100644 index 0000000..ee04eff --- /dev/null +++ b/wallets/react-wallet-v2/src/components/RequestMethodCard.tsx @@ -0,0 +1,22 @@ +import { Col, Row, Text } from '@nextui-org/react' + +/** + * Types + */ +interface IProps { + methods: string[] +} + +/** + * Component + */ +export default function RequestMethodCard({ methods }: IProps) { + return ( + + + Methods + {methods.map(method => method).join(', ')} + + + ) +} diff --git a/wallets/react-wallet-v2/src/components/RequestModalContainer.tsx b/wallets/react-wallet-v2/src/components/RequestModalContainer.tsx new file mode 100644 index 0000000..6d9d1e1 --- /dev/null +++ b/wallets/react-wallet-v2/src/components/RequestModalContainer.tsx @@ -0,0 +1,27 @@ +import { Container, Modal, Text } from '@nextui-org/react' +import { Fragment, ReactNode } from 'react' + +/** + * Types + */ +interface IProps { + title: string + children: ReactNode | ReactNode[] +} + +/** + * Component + */ +export default function RequestModalContainer({ children, title }: IProps) { + return ( + + + {title} + + + + {children} + + + ) +} diff --git a/wallets/react-wallet-v2/src/utils/CosmosUtil.ts b/wallets/react-wallet-v2/src/lib/Cosmos.ts similarity index 100% rename from wallets/react-wallet-v2/src/utils/CosmosUtil.ts rename to wallets/react-wallet-v2/src/lib/Cosmos.ts diff --git a/wallets/react-wallet-v2/src/pages/session.tsx b/wallets/react-wallet-v2/src/pages/session.tsx index 71ca899..deeb2b8 100644 --- a/wallets/react-wallet-v2/src/pages/session.tsx +++ b/wallets/react-wallet-v2/src/pages/session.tsx @@ -1,10 +1,11 @@ import AccountSelectCard from '@/components/AccountSelectCard' import PageHeader from '@/components/PageHeader' +import ProjectInfoCard from '@/components/ProjectInfoCard' import { cosmosAddresses } from '@/utils/CosmosWalletUtil' import { eip155Addresses } from '@/utils/EIP155WalletUtil' -import { isCosmosChain, isEIP155Chain, truncate } from '@/utils/HelperUtil' +import { isCosmosChain, isEIP155Chain } from '@/utils/HelperUtil' import { walletConnectClient } from '@/utils/WalletConnectUtil' -import { Avatar, Button, Col, Divider, Link, Row, Text } from '@nextui-org/react' +import { Button, Col, Divider, Row, Text } from '@nextui-org/react' import { ERROR } from '@walletconnect/utils' import { useRouter } from 'next/router' import { Fragment, useEffect, useState } from 'react' @@ -30,7 +31,6 @@ export default function SessionPage() { } // Get necessary data from session - const { name, url, icons } = session.peer.metadata const expiryDate = new Date(session.expiry * 1000) const { chains } = session.permissions.blockchain const { methods } = session.permissions.jsonrpc @@ -72,24 +72,14 @@ export default function SessionPage() { - - - - - - {name} - - {truncate(url?.split('https://')[1] ?? 'Unknown', 23)} - - - + + + {chains.map(chain => { if (isEIP155Chain(chain)) { return ( - - EIP155 Accounts diff --git a/wallets/react-wallet-v2/src/utils/CosmosWalletUtil.ts b/wallets/react-wallet-v2/src/utils/CosmosWalletUtil.ts index 4eb2f9f..5d988e7 100644 --- a/wallets/react-wallet-v2/src/utils/CosmosWalletUtil.ts +++ b/wallets/react-wallet-v2/src/utils/CosmosWalletUtil.ts @@ -1,4 +1,4 @@ -import { Cosmos } from '@/utils/CosmosUtil' +import { Cosmos } from '@/lib/Cosmos' export let wallet1: Cosmos export let wallet2: Cosmos diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx index 45b4bb2..872fca0 100644 --- a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -1,12 +1,14 @@ import AccountSelectCard from '@/components/AccountSelectCard' -import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData' -import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' +import ProjectInfoCard from '@/components/ProjectInfoCard' +import RequesDetailsCard from '@/components/RequestDetalilsCard' +import RequestMethodCard from '@/components/RequestMethodCard' +import RequestModalContainer from '@/components/RequestModalContainer' import ModalStore from '@/store/ModalStore' import { cosmosAddresses } from '@/utils/CosmosWalletUtil' import { eip155Addresses } from '@/utils/EIP155WalletUtil' import { isCosmosChain, isEIP155Chain } from '@/utils/HelperUtil' import { walletConnectClient } from '@/utils/WalletConnectUtil' -import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' +import { Button, Col, Divider, Modal, Row, Text } from '@nextui-org/react' import { Fragment, useState } from 'react' export default function SessionProposalModal() { @@ -23,10 +25,8 @@ export default function SessionProposalModal() { // Get required proposal data const { proposer, permissions, relay } = proposal - const { icons, name, url } = proposer.metadata const { chains } = permissions.blockchain const { methods } = permissions.jsonrpc - const { protocol } = relay // Add / remove address from EIP155 selection function onSelectEIP155(address: string) { @@ -84,105 +84,61 @@ export default function SessionProposalModal() { return ( - - Session Proposal - + + - - - - - - - - {name} - {url} - - + - + - - - Blockchains - - {chains - .map( - chain => - EIP155_CHAINS[chain as TEIP155Chain]?.name ?? - COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name ?? - chain - ) - .join(', ')} - - - + - + - - - Methods - {methods.map(method => method).join(', ')} - - + - + {chains.map(chain => { + if (isEIP155Chain(chain)) { + return ( + + + Select EIP155 Accounts + {eip155Addresses.map((address, index) => ( + onSelectEIP155(address)} + selected={selectedEIP155.includes(address)} + /> + ))} + + + ) + } else if (isCosmosChain(chain)) { + return ( + + - - - Relay Protocol - {protocol} - - - - {chains.map(chain => { - if (isEIP155Chain(chain)) { - return ( - - - - - - Select EIP155 Accounts - {eip155Addresses.map((address, index) => ( - onSelectEIP155(address)} - selected={selectedEIP155.includes(address)} - /> - ))} - - - - ) - } else if (isCosmosChain(chain)) { - return ( - - - - - - Select Cosmos Accounts - {cosmosAddresses.map((address, index) => ( - onSelectCosmos(address)} - selected={selectedCosmos.includes(address)} - /> - ))} - - - - ) - } - })} - - + + + Select Cosmos Accounts + {cosmosAddresses.map((address, index) => ( + onSelectCosmos(address)} + selected={selectedCosmos.includes(address)} + /> + ))} + + + + ) + } + })} +