Implement multi wallet support
This commit is contained in:
		
							parent
							
								
									c69121d673
								
							
						
					
					
						commit
						e82ca094b3
					
				| @ -1,17 +1,18 @@ | ||||
| import SettingsStore from '@/store/SettingsStore' | ||||
| import { addresses } from '@/utils/WalletUtil' | ||||
| import { useSnapshot } from 'valtio' | ||||
| 
 | ||||
| export default function AccountPicker() { | ||||
|   const { account } = useSnapshot(SettingsStore.state) | ||||
|   const { address } = useSnapshot(SettingsStore.state) | ||||
| 
 | ||||
|   return ( | ||||
|     <select | ||||
|       value={account} | ||||
|       onChange={e => SettingsStore.setAccount(e.currentTarget.value)} | ||||
|       aria-label="accounts" | ||||
|       value={address} | ||||
|       onChange={e => SettingsStore.setAddress(e.currentTarget.value)} | ||||
|       aria-label="addresses" | ||||
|     > | ||||
|       <option value={0}>Account 1</option> | ||||
|       <option value={1}>Account 2</option> | ||||
|       <option value={addresses[0]}>Account 1</option> | ||||
|       <option value={addresses[1]}>Account 2</option> | ||||
|     </select> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import SettingsStore from '@/store/SettingsStore' | ||||
| import { createWalletConnectClient } from '@/utils/WalletConnectUtil' | ||||
| import { createOrRestoreWallet } from '@/utils/WalletUtil' | ||||
| import { useCallback, useEffect, useState } from 'react' | ||||
| @ -7,7 +8,8 @@ export default function useInitialization() { | ||||
| 
 | ||||
|   const onInitialize = useCallback(async () => { | ||||
|     try { | ||||
|       createOrRestoreWallet() | ||||
|       const { addresses } = createOrRestoreWallet() | ||||
|       SettingsStore.setAddress(addresses[0]) | ||||
|       await createWalletConnectClient() | ||||
|       setInitialized(true) | ||||
|     } catch (err: unknown) { | ||||
|  | ||||
| @ -3,14 +3,12 @@ import AccountPicker from '@/components/AccountPicker' | ||||
| import PageHeader from '@/components/PageHeader' | ||||
| import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data' | ||||
| import SettingsStore from '@/store/SettingsStore' | ||||
| import { wallets } from '@/utils/WalletUtil' | ||||
| import { Text } from '@nextui-org/react' | ||||
| import { Fragment } from 'react' | ||||
| import { useSnapshot } from 'valtio' | ||||
| 
 | ||||
| export default function HomePage() { | ||||
|   const { testNets, account } = useSnapshot(SettingsStore.state) | ||||
|   const addresses = Object.keys(wallets) | ||||
|   const { testNets, address } = useSnapshot(SettingsStore.state) | ||||
| 
 | ||||
|   return ( | ||||
|     <Fragment> | ||||
| @ -21,7 +19,7 @@ export default function HomePage() { | ||||
|         Mainnets | ||||
|       </Text> | ||||
|       {Object.values(EIP155_MAINNET_CHAINS).map(({ name, logo, rgb }) => ( | ||||
|         <AccountCard key={name} name={name} logo={logo} rgb={rgb} address={addresses[account]} /> | ||||
|         <AccountCard key={name} name={name} logo={logo} rgb={rgb} address={address} /> | ||||
|       ))} | ||||
| 
 | ||||
|       {testNets ? ( | ||||
| @ -30,13 +28,7 @@ export default function HomePage() { | ||||
|             Testnets | ||||
|           </Text> | ||||
|           {Object.values(EIP155_TEST_CHAINS).map(({ name, logo, rgb }) => ( | ||||
|             <AccountCard | ||||
|               key={name} | ||||
|               name={name} | ||||
|               logo={logo} | ||||
|               rgb={rgb} | ||||
|               address={addresses[account]} | ||||
|             /> | ||||
|             <AccountCard key={name} name={name} logo={logo} rgb={rgb} address={address} /> | ||||
|           ))} | ||||
|         </Fragment> | ||||
|       ) : null} | ||||
|  | ||||
| @ -6,7 +6,7 @@ import { Fragment } from 'react' | ||||
| import { useSnapshot } from 'valtio' | ||||
| 
 | ||||
| export default function SettingsPage() { | ||||
|   const { testNets } = useSnapshot(SettingsStore.state) | ||||
|   const { testNets, address } = useSnapshot(SettingsStore.state) | ||||
| 
 | ||||
|   return ( | ||||
|     <Fragment> | ||||
| @ -15,9 +15,7 @@ export default function SettingsPage() { | ||||
|         Mnemonic | ||||
|       </Text> | ||||
|       <Card bordered borderWeight="light" css={{ minHeight: '75px' }}> | ||||
|         <Text css={{ fontFamily: '$mono' }}> | ||||
|           {wallets['0xD0712a5018b6F3401b90Cd75C15d95B3353a4088'].mnemonic.phrase} | ||||
|         </Text> | ||||
|         <Text css={{ fontFamily: '$mono' }}>{wallets[address].mnemonic.phrase}</Text> | ||||
|       </Card> | ||||
| 
 | ||||
|       <Text css={{ color: '$yellow500', marginTop: '$5', textAlign: 'center' }}> | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { proxy } from 'valtio' | ||||
|  */ | ||||
| interface State { | ||||
|   testNets: boolean | ||||
|   account: number | ||||
|   address: string | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -13,7 +13,7 @@ interface State { | ||||
|  */ | ||||
| const state = proxy<State>({ | ||||
|   testNets: typeof localStorage !== 'undefined' ? Boolean(localStorage.getItem('TEST_NETS')) : true, | ||||
|   account: 0 | ||||
|   address: '' | ||||
| }) | ||||
| 
 | ||||
| /** | ||||
| @ -22,8 +22,8 @@ const state = proxy<State>({ | ||||
| const SettingsStore = { | ||||
|   state, | ||||
| 
 | ||||
|   setAccount(value: number | string) { | ||||
|     state.account = Number(value) | ||||
|   setAddress(address: string) { | ||||
|     state.address = address | ||||
|   }, | ||||
| 
 | ||||
|   toggleTestNets() { | ||||
|  | ||||
| @ -52,3 +52,20 @@ export function getSignTypedDataParamsData(params: string[]) { | ||||
| 
 | ||||
|   return data | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Get our address from params checking if params string contains one | ||||
|  * of our wallet addresses | ||||
|  */ | ||||
| export function getWalletAddressFromParams(addresses: string[], params: any) { | ||||
|   const paramsString = JSON.stringify(params) | ||||
|   let address = '' | ||||
| 
 | ||||
|   addresses.forEach(addr => { | ||||
|     if (paramsString.includes(addr)) { | ||||
|       address = addr | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   return address | ||||
| } | ||||
|  | ||||
| @ -1,12 +1,19 @@ | ||||
| import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data' | ||||
| import { getSignParamsMessage, getSignTypedDataParamsData } from '@/utils/HelperUtil' | ||||
| import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data' | ||||
| import { | ||||
|   getSignParamsMessage, | ||||
|   getSignTypedDataParamsData, | ||||
|   getWalletAddressFromParams | ||||
| } from '@/utils/HelperUtil' | ||||
| import { addresses, wallets } from '@/utils/WalletUtil' | ||||
| import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils' | ||||
| import { RequestEvent } from '@walletconnect/types' | ||||
| import { ERROR } from '@walletconnect/utils' | ||||
| import { Wallet } from 'ethers' | ||||
| import { providers } from 'ethers' | ||||
| 
 | ||||
| export async function approveEIP155Request(request: RequestEvent['request'], wallet: Wallet) { | ||||
|   const { method, params, id } = request | ||||
| export async function approveEIP155Request(requestEvent: RequestEvent) { | ||||
|   const { method, params, id } = requestEvent.request | ||||
|   const { chainId } = requestEvent | ||||
|   const wallet = wallets[getWalletAddressFromParams(addresses, params)] | ||||
| 
 | ||||
|   switch (method) { | ||||
|     case EIP155_SIGNING_METHODS.PERSONAL_SIGN: | ||||
| @ -25,8 +32,10 @@ export async function approveEIP155Request(request: RequestEvent['request'], wal | ||||
|       return formatJsonRpcResult(id, signedData) | ||||
| 
 | ||||
|     case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION: | ||||
|       const provider = new providers.JsonRpcProvider(EIP155_CHAINS[chainId as TEIP155Chain].rpc) | ||||
|       const sendTransaction = params[0] | ||||
|       const { hash } = await wallet.sendTransaction(sendTransaction) | ||||
|       const connectedWallet = wallet.connect(provider) | ||||
|       const { hash } = await connectedWallet.sendTransaction(sendTransaction) | ||||
|       return formatJsonRpcResult(id, hash) | ||||
| 
 | ||||
|     case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION: | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { Wallet } from 'ethers' | ||||
| 
 | ||||
| export let wallets: Record<string, Wallet> | ||||
| export let addresses: string[] | ||||
| export let wallet1: Wallet | ||||
| export let wallet2: Wallet | ||||
| 
 | ||||
| @ -21,4 +22,10 @@ export function createOrRestoreWallet() { | ||||
|     [wallet1.address]: wallet1, | ||||
|     [wallet2.address]: wallet2 | ||||
|   } | ||||
|   addresses = Object.keys(wallets) | ||||
| 
 | ||||
|   return { | ||||
|     wallets, | ||||
|     addresses | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,11 +1,25 @@ | ||||
| import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' | ||||
| import ModalStore from '@/store/ModalStore' | ||||
| import { truncate } from '@/utils/HelperUtil' | ||||
| import { walletConnectClient } from '@/utils/WalletConnectUtil' | ||||
| import { wallets } from '@/utils/WalletUtil' | ||||
| import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' | ||||
| import { Fragment } from 'react' | ||||
| import { addresses } from '@/utils/WalletUtil' | ||||
| import { | ||||
|   Avatar, | ||||
|   Button, | ||||
|   Card, | ||||
|   Col, | ||||
|   Container, | ||||
|   Divider, | ||||
|   Link, | ||||
|   Modal, | ||||
|   Row, | ||||
|   Text | ||||
| } from '@nextui-org/react' | ||||
| import { Fragment, useState } from 'react' | ||||
| 
 | ||||
| export default function SessionProposalModal() { | ||||
|   const [selectedAddresses, setSelectedAddresses] = useState<string[]>([]) | ||||
| 
 | ||||
|   // Get proposal data and wallet address from store
 | ||||
|   const proposal = ModalStore.state.data?.proposal | ||||
| 
 | ||||
| @ -21,14 +35,29 @@ export default function SessionProposalModal() { | ||||
|   const { methods } = permissions.jsonrpc | ||||
|   const { protocol } = relay | ||||
| 
 | ||||
|   // Add / remove address from selection
 | ||||
|   function onSelectAddress(address: string) { | ||||
|     if (selectedAddresses.includes(address)) { | ||||
|       const newAddresses = selectedAddresses.filter(a => a !== address) | ||||
|       setSelectedAddresses(newAddresses) | ||||
|     } else { | ||||
|       setSelectedAddresses([...selectedAddresses, address]) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Hanlde approve action
 | ||||
|   async function onApprove() { | ||||
|     if (proposal) { | ||||
|       const accounts: string[] = [] | ||||
|       chains.forEach(chain => { | ||||
|         selectedAddresses.forEach(address => { | ||||
|           accounts.push(`${chain}:${address}`) | ||||
|         }) | ||||
|       }) | ||||
| 
 | ||||
|       const response = { | ||||
|         state: { | ||||
|           accounts: chains.map( | ||||
|             chain => `${chain}:${wallets['0xD0712a5018b6F3401b90Cd75C15d95B3353a4088'].address}` | ||||
|           ) | ||||
|           accounts | ||||
|         } | ||||
|       } | ||||
|       await walletConnectClient.approve({ proposal, response }) | ||||
| @ -92,6 +121,27 @@ export default function SessionProposalModal() { | ||||
|               <Text color="$gray400">{protocol}</Text> | ||||
|             </Col> | ||||
|           </Row> | ||||
| 
 | ||||
|           <Divider y={2} /> | ||||
| 
 | ||||
|           <Row> | ||||
|             <Col> | ||||
|               <Text h5>Select Accounts to Connect</Text> | ||||
|               {addresses.map((address, index) => ( | ||||
|                 <Card | ||||
|                   onClick={() => onSelectAddress(address)} | ||||
|                   clickable | ||||
|                   key={address} | ||||
|                   css={{ | ||||
|                     marginTop: '$5', | ||||
|                     backgroundColor: selectedAddresses.includes(address) ? '$green600' : '$accents2' | ||||
|                   }} | ||||
|                 > | ||||
|                   <Text>{`Acc ${index + 1} - ${truncate(address, 19)}`}</Text> | ||||
|                 </Card> | ||||
|               ))} | ||||
|             </Col> | ||||
|           </Row> | ||||
|         </Container> | ||||
|       </Modal.Body> | ||||
| 
 | ||||
| @ -99,7 +149,14 @@ export default function SessionProposalModal() { | ||||
|         <Button auto flat color="error" onClick={onReject}> | ||||
|           Reject | ||||
|         </Button> | ||||
|         <Button auto flat color="success" onClick={onApprove}> | ||||
|         <Button | ||||
|           auto | ||||
|           flat | ||||
|           color="success" | ||||
|           onClick={onApprove} | ||||
|           disabled={!selectedAddresses.length} | ||||
|           css={{ opacity: selectedAddresses.length ? 1 : 0.4 }} | ||||
|         > | ||||
|           Approve | ||||
|         </Button> | ||||
|       </Modal.Footer> | ||||
|  | ||||
| @ -3,7 +3,6 @@ import ModalStore from '@/store/ModalStore' | ||||
| import { truncate } from '@/utils/HelperUtil' | ||||
| import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' | ||||
| import { walletConnectClient } from '@/utils/WalletConnectUtil' | ||||
| import { wallets } from '@/utils/WalletUtil' | ||||
| import { | ||||
|   Avatar, | ||||
|   Button, | ||||
| @ -16,7 +15,6 @@ import { | ||||
|   Row, | ||||
|   Text | ||||
| } from '@nextui-org/react' | ||||
| import { providers } from 'ethers' | ||||
| import { Fragment, useState } from 'react' | ||||
| 
 | ||||
| export default function SessionSendTransactionModal() { | ||||
| @ -42,10 +40,7 @@ export default function SessionSendTransactionModal() { | ||||
|   async function onApprove() { | ||||
|     if (requestEvent) { | ||||
|       setLoading(true) | ||||
|       const provider = new providers.JsonRpcProvider(EIP155_CHAINS[chainId as TEIP155Chain].rpc) | ||||
|       const connectedWallet = | ||||
|         wallets['0xD0712a5018b6F3401b90Cd75C15d95B3353a4088'].connect(provider) | ||||
|       const response = await approveEIP155Request(requestEvent.request, connectedWallet) | ||||
|       const response = await approveEIP155Request(requestEvent) | ||||
|       await walletConnectClient.respond({ | ||||
|         topic: requestEvent.topic, | ||||
|         response | ||||
|  | ||||
| @ -3,7 +3,6 @@ import ModalStore from '@/store/ModalStore' | ||||
| import { getSignParamsMessage } from '@/utils/HelperUtil' | ||||
| import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' | ||||
| import { walletConnectClient } from '@/utils/WalletConnectUtil' | ||||
| import { wallets } from '@/utils/WalletUtil' | ||||
| import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' | ||||
| import { Fragment } from 'react' | ||||
| 
 | ||||
| @ -29,10 +28,7 @@ export default function SessionSignModal() { | ||||
|   // Handle approve action (logic varies based on request method)
 | ||||
|   async function onApprove() { | ||||
|     if (requestEvent) { | ||||
|       const response = await approveEIP155Request( | ||||
|         requestEvent.request, | ||||
|         wallets['0xD0712a5018b6F3401b90Cd75C15d95B3353a4088'] | ||||
|       ) | ||||
|       const response = await approveEIP155Request(requestEvent) | ||||
|       await walletConnectClient.respond({ | ||||
|         topic: requestEvent.topic, | ||||
|         response | ||||
|  | ||||
| @ -3,7 +3,6 @@ import ModalStore from '@/store/ModalStore' | ||||
| import { getSignTypedDataParamsData } from '@/utils/HelperUtil' | ||||
| import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' | ||||
| import { walletConnectClient } from '@/utils/WalletConnectUtil' | ||||
| import { wallets } from '@/utils/WalletUtil' | ||||
| import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' | ||||
| import { Fragment } from 'react' | ||||
| import { CodeBlock, codepen } from 'react-code-blocks' | ||||
| @ -30,10 +29,7 @@ export default function SessionSignTypedDataModal() { | ||||
|   // Handle approve action (logic varies based on request method)
 | ||||
|   async function onApprove() { | ||||
|     if (requestEvent) { | ||||
|       const response = await approveEIP155Request( | ||||
|         requestEvent.request, | ||||
|         wallets['0xD0712a5018b6F3401b90Cd75C15d95B3353a4088'] | ||||
|       ) | ||||
|       const response = await approveEIP155Request(requestEvent) | ||||
|       await walletConnectClient.respond({ | ||||
|         topic: requestEvent.topic, | ||||
|         response | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user