Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[STK-153][POC] - Add Shutter RPC button #1926

Merged
merged 9 commits into from
Oct 14, 2024
13 changes: 13 additions & 0 deletions src/assets/images/shutter-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ export const ButtonPurpleDim = styled(Base)`

export const ButtonInvisible = styled.button`
border: none;
outline: none;
background: transparent;
display: flex;
outline: none;
`

export const ButtonDark = styled(Base)`
Expand Down
90 changes: 85 additions & 5 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ChainId } from '@swapr/sdk'

import { useEffect, useState } from 'react'
import { ChevronUp } from 'react-feather'
import { useTranslation } from 'react-i18next'
Expand All @@ -6,15 +8,19 @@ import { Flex, Text } from 'rebass'
import styled from 'styled-components'

import { ReactComponent as GasInfoSvg } from '../../assets/images/gas-info.svg'
import ShutterLogo from '../../assets/images/shutter-logo.svg'
import { LIQUIDITY_V3_INFO_POOLS_LINK, STACKLY_URL } from '../../constants'
import { useActiveWeb3React, useUnsupportedChainIdError } from '../../hooks'
import { useGasInfo } from '../../hooks/useGasInfo'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen } from '../../state/application/hooks'
import { useDarkModeManager, useUpdateSelectedChartOption } from '../../state/user/hooks'
import { ChartOption } from '../../state/user/reducer'
import { CloseIcon } from '../../theme'
import { breakpoints } from '../../utils/theme'
import { ButtonPrimary } from '../Button'
import { UnsupportedNetworkPopover } from '../NetworkUnsupportedPopover'
import QuestionHelper from '../QuestionHelper'
import Row, { RowFixed, RowFlat } from '../Row'
import { Settings } from '../Settings'
import { SwaprVersionLogo } from '../SwaprVersionLogo'
Expand All @@ -39,6 +45,33 @@ const HeaderFrame = styled.div`
height: 100px;
`

const ShutterButton = styled(ButtonPrimary)`
align-items: center;
display: flex;
font-size: 10px;
justify-content: space-between;
height: 22px;
margin-right: 8px;
max-width: 235px;
padding: 0px 8px 0px 16px;
text-transform: none !important;

.shutter-button-content-wrapper {
align-items: center;
display: flex;
gap: 4px;
}

img {
height: 12px;
width: 12px;
}

svg {
stroke: white;
}
`

const HeaderControls = styled.div<{ isConnected: boolean }>`
${({ theme }) => theme.mediaWidth.upToMedium`
position: fixed;
Expand Down Expand Up @@ -205,20 +238,29 @@ const NewBadge = styled.p`
margin-left: 10px;
`

function Header() {
const { account, chainId } = useActiveWeb3React()
const SHUTTER_HELP_TEXT =
'Shutter protects you against malicious MEV and provides censorship resistance. Transactions with this RPC are encrypted before going into the public mempool and are kept encrypted until the order is finalized.'

const { t } = useTranslation('common')
function Header() {
const [isGasInfoOpen, setIsGasInfoOpen] = useState(false)
const { gas } = useGasInfo()
const [showShutterButton, setShowShutterButton] = useState(true)
const { account, chainId } = useActiveWeb3React()
const [isDark] = useDarkModeManager()
const { gas } = useGasInfo()
const { t } = useTranslation('common')

/* Expeditions hidden by SWA-27 request
* const toggleExpeditionsPopup = useToggleShowExpeditionsPopup()
*/
const isUnsupportedNetworkModal = useModalOpen(ApplicationModal.UNSUPPORTED_NETWORK)
const isUnsupportedChainIdError = useUnsupportedChainIdError()

const handleShutterCloseClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
event.preventDefault()
event.stopPropagation()
setShowShutterButton(false)
}

const onScrollHander = () => {
const headerControls = document.getElementById('header-controls')
if (headerControls) {
Expand All @@ -242,6 +284,35 @@ function Header() {

const swapRoute = selectedChartTab === ChartOption.PRO ? '/swap/pro' : '/swap'

async function changeOrAddNetwork() {
const chainId = '0x64'
if (window.ethereum && window.ethereum.request) {
try {
const chainParams = {
chainId: chainId,
rpcUrls: ['https://erpc.gnosis.shutter.network'],
chainName: 'Shutterized Gnosis Chain',
nativeCurrency: {
name: 'xDai',
symbol: 'xDAI',
decimals: 18,
},
blockExplorerUrls: ['https://www.gnosisscan.com'],
}

await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [chainParams],
})
console.log('Network added and switched to:', chainParams.chainName)
} catch (addError) {
console.error('Failed to add the network:', addError)
}
} else {
console.error('MetaMask is not installed!')
}
}
Diogomartf marked this conversation as resolved.
Show resolved Hide resolved

return (
<HeaderFrame>
{/* Expeditions hidden by SWA-27 request */}
Expand Down Expand Up @@ -316,13 +387,22 @@ function Header() {
<Settings />
</HeaderSubRow>

<Flex maxHeight={'22px'} justifyContent={'end'}>
<Flex maxHeight="22px" justifyContent="end" width="345px">
{account && (
<>
{/* Expeditions hidden by SWA-27 request */}
{/* <HeaderButton onClick={toggleExpeditionsPopup} style={{ marginRight: '7px' }}>
&#10024;&nbsp;Expeditions
</HeaderButton> */}
{chainId === ChainId.GNOSIS && showShutterButton && (
<ShutterButton onClick={changeOrAddNetwork}>
<div className="shutter-button-content-wrapper">
Add <img src={ShutterLogo} alt="Shutter RPC connector" /> Shutter Gnosis RPC{' '}
<QuestionHelper iconWrapperWidth="auto" size={14} text={SHUTTER_HELP_TEXT} />
</div>
<CloseIcon onClick={handleShutterCloseClick} size={14} />
</ShutterButton>
)}
<Balances />
</>
)}
Expand Down
27 changes: 21 additions & 6 deletions src/components/QuestionHelper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import styled from 'styled-components'

import Tooltip from '../Tooltip'

const QuestionWrapper = styled.div`
const QuestionWrapper = styled.div<{ width?: string }>`
display: flex;
align-items: center;
justify-content: flex-end;
background: none;
color: ${({ theme }) => theme.purple3};
transition: opacity 0.3s ease;
width: 20px;
width: ${({ width }) => width ?? 20}px;
height: 16px;
margin-left: 4;

:hover,
:focus {
Expand All @@ -36,16 +35,32 @@ const QuestionMark = styled.span`
font-size: 1rem;
`

export default function QuestionHelper({ text, className }: { text: string; className?: string }) {
export default function QuestionHelper({
iconWrapperWidth = '20',
text,
className,
size = 16,
}: {
iconWrapperWidth?: string
text: string
className?: string
size?: number
}) {
const [show, setShow] = useState<boolean>(false)

const open = useCallback(() => setShow(true), [setShow])
const close = useCallback(() => setShow(false), [setShow])

return (
<Tooltip text={text} show={show}>
<QuestionWrapper onClick={open} onMouseEnter={open} onMouseLeave={close} className={className}>
<Question size={16} />
<QuestionWrapper
onClick={open}
onMouseEnter={open}
onMouseLeave={close}
className={className}
width={iconWrapperWidth}
>
<Question size={size} />
</QuestionWrapper>
</Tooltip>
)
Expand Down
13 changes: 8 additions & 5 deletions src/theme/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,19 @@ export const Button = styled.button.attrs<{ warning: boolean }, { backgroundColo
}
`

const StyledCloseIcon = styled(X)`
const StyledCloseIcon = styled(X)<{ size?: number | string }>`
color: ${({ theme }) => theme.purple3};
width: 16px;
height: 16px;
width: ${({ size }) => size ?? 16}px;
height: ${({ size }) => size ?? 16}px;
cursor: pointer;
`
export const CloseIcon = (props: ButtonProps) => {
interface CloseIconProps extends ButtonProps {
size?: number | string
}
export const CloseIcon = ({ size, ...props }: CloseIconProps) => {
return (
<ButtonInvisible {...props}>
<StyledCloseIcon />
<StyledCloseIcon size={size} />
</ButtonInvisible>
)
}
Expand Down