WalletBridge.tsx
1 import React, { useRef } from 'react'; 2 import { BridgeProtocol } from '@agoric/web-components'; 3 import { makeReactDappWalletBridge } from '@agoric/web-components/react'; 4 import { useSetAtom, useAtomValue } from 'jotai'; 5 import { 6 bridgeHrefAtom, 7 chainConnectionAtom, 8 chainStorageWatcherAtom, 9 offerSignerAtom, 10 setIsDappApprovedAtom, 11 walletUiHrefAtom, 12 } from 'store/app'; 13 import { Box, ToastId, useToast } from '@chakra-ui/react'; 14 import { dappConfig } from 'config'; 15 16 type BridgeReadyMessage = { 17 detail: { 18 data: { 19 type: string; 20 }; 21 isDappApproved: boolean; 22 requestDappConnection: (petname: string) => void; 23 addOffer: (offer: any) => void; 24 }; 25 }; 26 27 type BridgeMessage = { 28 detail: { 29 data: { 30 type: string; 31 isDappApproved: boolean; 32 }; 33 }; 34 }; 35 36 type BridgeError = { 37 detail: { 38 type: string; 39 e: Error; 40 }; 41 }; 42 43 // Create a wrapper for dapp-wallet-bridge that is specific to 44 // the app's instance of React. 45 const DappWalletBridge = makeReactDappWalletBridge(React); 46 47 const WalletBridge = () => { 48 const setIsDappApproved = useSetAtom(setIsDappApprovedAtom); 49 const setOfferSigner = useSetAtom(offerSignerAtom); 50 const chainConnection = useAtomValue(chainConnectionAtom); 51 const bridgeHref = useAtomValue(bridgeHrefAtom); 52 const walletUiHref = useAtomValue(walletUiHrefAtom); 53 const watcher = useAtomValue(chainStorageWatcherAtom); 54 55 const toastId = useRef<ToastId | null>(null); 56 const connectionSuccessfulToastId = useRef<ToastId | null>(null); 57 const toast = useToast({ 58 position: 'bottom-right', 59 isClosable: true, 60 variant: 'left-accent', 61 }); 62 63 const clearCurrentToast = () => 64 toastId.current && toast.close(toastId.current); 65 66 const clearConnectionSuccessfulToast = () => 67 connectionSuccessfulToastId.current && 68 toast.close(connectionSuccessfulToastId.current); 69 70 const showWarningToast = () => { 71 clearConnectionSuccessfulToast(); 72 toastId.current = toast({ 73 description: ( 74 <p> 75 Dapp is in read-only mode. Enable the connection at{' '} 76 <a 77 className="underline text-blue-500" 78 href={walletUiHref} 79 target="_blank" 80 rel="noreferrer" 81 > 82 {walletUiHref} 83 </a>{' '} 84 to access markets. 85 </p> 86 ), 87 status: 'warning', 88 }); 89 }; 90 91 const showConnectionSuccessfulToast = () => { 92 clearCurrentToast(); 93 connectionSuccessfulToastId.current = toast({ 94 title: ( 95 <p> 96 Successfully connected to Agoric wallet at{' '} 97 <a 98 className="underline text-blue-500" 99 href={walletUiHref} 100 target="_blank" 101 rel="noreferrer" 102 > 103 {walletUiHref} 104 </a> 105 </p> 106 ), 107 status: 'success', 108 }); 109 }; 110 111 const onBridgeReady = (ev: BridgeReadyMessage) => { 112 const { 113 detail: { isDappApproved, requestDappConnection, addOffer }, 114 } = ev; 115 setOfferSigner({ addOffer, isDappApproved }); 116 if (isDappApproved) { 117 showConnectionSuccessfulToast(); 118 } else { 119 requestDappConnection(dappConfig.DAPP_PETNAME); 120 showWarningToast(); 121 } 122 }; 123 124 const onError = (ev: BridgeError) => { 125 const message = ev.detail.e.message; 126 //@todo clear current toast first? 127 toast({ 128 description: ( 129 <div> 130 <p> 131 Could not connect to Agoric wallet at{' '} 132 <a 133 className="underline text-blue-500" 134 href={walletUiHref} 135 target="_blank" 136 rel="noreferrer" 137 > 138 {walletUiHref} 139 </a> 140 {message && `: ${message}`} 141 </p> 142 </div> 143 ), 144 status: 'error', 145 }); 146 }; 147 148 const onBridgeMessage = (ev: BridgeMessage) => { 149 const data = ev.detail.data; 150 const type = data.type; 151 switch (type) { 152 case BridgeProtocol.dappApprovalChanged: 153 setIsDappApproved(data.isDappApproved); 154 if (data.isDappApproved) { 155 showConnectionSuccessfulToast(); 156 } else { 157 showWarningToast(); 158 } 159 break; 160 default: 161 console.warn('Unhandled bridge message', data); 162 } 163 }; 164 165 return ( 166 <Box display="none"> 167 {chainConnection && watcher && ( 168 <DappWalletBridge 169 bridgeHref={bridgeHref} 170 onBridgeMessage={onBridgeMessage} 171 onBridgeReady={onBridgeReady} 172 onError={onError} 173 address={chainConnection.address} 174 chainId={watcher.chainId} 175 // chainId={chainConnection.chainId} 176 /> 177 )} 178 </Box> 179 ); 180 }; 181 182 export default WalletBridge;