From 240817c9e6d82342118970f393eb753a094df4ad Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Thu, 2 Jan 2025 16:07:18 -0300 Subject: [PATCH 1/5] Add DrawerParagraph component --- .../connectWallets/connectWalletsDrawer.tsx | 14 +++++++------- webapp/components/customTokenDrawer/index.tsx | 6 ++---- .../components/customTokenDrawer/tokenSection.tsx | 5 ++--- webapp/components/drawer.tsx | 4 ++++ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/webapp/components/connectWallets/connectWalletsDrawer.tsx b/webapp/components/connectWallets/connectWalletsDrawer.tsx index b7e8972e..482405ac 100644 --- a/webapp/components/connectWallets/connectWalletsDrawer.tsx +++ b/webapp/components/connectWallets/connectWalletsDrawer.tsx @@ -4,7 +4,7 @@ import { useConnectModal, } from '@rainbow-me/rainbowkit' import { featureFlags } from 'app/featureFlags' -import { Drawer, DrawerTitle } from 'components/drawer' +import { Drawer, DrawerParagraph, DrawerTitle } from 'components/drawer' import { useNetworkType } from 'hooks/useNetworkType' import { useUmami } from 'hooks/useUmami' import { useTranslations } from 'next-intl' @@ -12,10 +12,6 @@ import { CloseIcon } from 'ui-common/components/closeIcon' import { BtcWallet, EvmWallet } from './wallets' -const P = ({ text }: { text: string }) => ( -

{text}

-) - type Props = { closeDrawer: () => void } @@ -53,7 +49,9 @@ export const ConnectWalletsDrawer = function ({ closeDrawer }: Props) { {featureFlags.btcTunnelEnabled ? ( -

+ + {t('connect-wallets.description')} + ) : ( // Prevent layout shift when text is not shown

@@ -64,7 +62,9 @@ export const ConnectWalletsDrawer = function ({ closeDrawer }: Props) { {featureFlags.btcTunnelEnabled && ( <> -

+ + {t('connect-wallets.btc-wallet-requirement')} + )} diff --git a/webapp/components/customTokenDrawer/index.tsx b/webapp/components/customTokenDrawer/index.tsx index c0b33139..df020e2d 100644 --- a/webapp/components/customTokenDrawer/index.tsx +++ b/webapp/components/customTokenDrawer/index.tsx @@ -2,7 +2,7 @@ import { useQueryClient } from '@tanstack/react-query' import { Button } from 'components/button' -import { Drawer, DrawerTitle } from 'components/drawer' +import { Drawer, DrawerParagraph, DrawerTitle } from 'components/drawer' import { useChain } from 'hooks/useChain' import { useCustomTokenAddress } from 'hooks/useCustomTokenAddress' import { useL2Token } from 'hooks/useL2Token' @@ -181,9 +181,7 @@ export const CustomTokenDrawer = function ({ -

- {t('subheading')} -

+ {t('subheading')} -

- {t('layer-token-address', { layer })} -

+ {t('layer-token-address', { layer })}
diff --git a/webapp/components/drawer.tsx b/webapp/components/drawer.tsx index ea8f6389..779c6b3b 100644 --- a/webapp/components/drawer.tsx +++ b/webapp/components/drawer.tsx @@ -39,6 +39,10 @@ export const Drawer = function ({ children, onClose }: Props) { ) } +export const DrawerParagraph = ({ children }: { children: string }) => ( +

{children}

+) + export const DrawerTitle = ({ children }: { children: string }) => (

{children}

) From c18945095109c78cdcbaa84740131f96ab1a7338 Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Fri, 3 Jan 2025 10:57:22 -0300 Subject: [PATCH 2/5] Remove redundant tailwind class in drawer --- webapp/components/connectWallets/connectWalletsDrawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/components/connectWallets/connectWalletsDrawer.tsx b/webapp/components/connectWallets/connectWalletsDrawer.tsx index 482405ac..950f22f3 100644 --- a/webapp/components/connectWallets/connectWalletsDrawer.tsx +++ b/webapp/components/connectWallets/connectWalletsDrawer.tsx @@ -40,7 +40,7 @@ export const ConnectWalletsDrawer = function ({ closeDrawer }: Props) { return ( -
+
{t('common.connect-wallets')} From 6177d6942366ebbc5ab686ba63a5b97b11ed684b Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Fri, 3 Jan 2025 16:02:12 -0300 Subject: [PATCH 3/5] Add Drawer for partners for deposit op --- .../tunnel/_components/evmDeposit.tsx | 155 +++++++++++------- .../customTunnelsThroughPartner/index.tsx | 63 +++++++ .../partnerLink.tsx | 23 +++ .../partnerLogos/stargate.svg | 82 +++++++++ .../customTunnelsThroughPartner/stargate.tsx | 25 +++ webapp/messages/en.json | 13 ++ webapp/messages/es.json | 13 ++ 7 files changed, 311 insertions(+), 63 deletions(-) create mode 100644 webapp/components/customTunnelsThroughPartner/index.tsx create mode 100644 webapp/components/customTunnelsThroughPartner/partnerLink.tsx create mode 100644 webapp/components/customTunnelsThroughPartner/partnerLogos/stargate.svg create mode 100644 webapp/components/customTunnelsThroughPartner/stargate.tsx diff --git a/webapp/app/[locale]/tunnel/_components/evmDeposit.tsx b/webapp/app/[locale]/tunnel/_components/evmDeposit.tsx index 22f55cf2..0c5ba4fb 100644 --- a/webapp/app/[locale]/tunnel/_components/evmDeposit.tsx +++ b/webapp/app/[locale]/tunnel/_components/evmDeposit.tsx @@ -2,6 +2,10 @@ import { useUmami } from 'app/analyticsEvents' import { Button } from 'components/button' +import { + CustomTunnelsThroughPartner, + tunnelsThroughPartner, +} from 'components/customTunnelsThroughPartner' import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance' import { useChain } from 'hooks/useChain' import { useNetworkType } from 'hooks/useNetworkType' @@ -85,6 +89,7 @@ export const EvmDeposit = function ({ state }: EvmDepositProps) { // use this state to toggle the Erc20 token approval const [extendedErc20Approval, setExtendedErc20Approval] = useState(false) + const [isPartnersDrawerOpen, setIsPartnersDrawerOpen] = useState(false) const t = useTranslations() const { track } = useUmami() @@ -242,73 +247,97 @@ export const EvmDeposit = function ({ state }: EvmDepositProps) { symbol: fromChain?.nativeCurrency.symbol, } - return ( - - ) : null - } - formContent={ - setIsPartnersDrawerOpen(true)} type="button"> + {t('tunnel-page.tunnel-partners.tunnel-with-our-partners')} + + ) + } + if (walletIsConnected(status)) { + return ( + updateFromInput(maxBalance)} + needsApproval={needsApproval} + operationRunning={operationRunning} + /> + ) + } + return + } + + return ( + <> + - } - tokenApproval={ - operatesNativeToken ? null : ( - setExtendedErc20Approval(prev => !prev)} + ) : null + } + formContent={ + updateFromInput(maxBalance)} /> - ) - } - tunnelState={{ - ...state, - // patch these events to update the extendedErc20Approval state - toggleInput() { - // toToken becomes fromToken, so we must check that one - if (isNativeToken(state.toToken)) { + } + tokenApproval={ + operatesNativeToken ? null : ( + + setExtendedErc20Approval(prev => !prev) + } + /> + ) + } + tunnelState={{ + ...state, + // patch these events to update the extendedErc20Approval state + toggleInput() { + // toToken becomes fromToken, so we must check that one + if (isNativeToken(state.toToken)) { + setExtendedErc20Approval(false) + } + state.toggleInput() + }, + updateFromNetwork(payload: number) { setExtendedErc20Approval(false) - } - state.toggleInput() - }, - updateFromNetwork(payload: number) { - setExtendedErc20Approval(false) - state.updateFromNetwork(payload) - }, - updateFromToken(from, to) { - if (isNativeToken(from)) { - setExtendedErc20Approval(false) - } - state.updateFromToken(from, to) - }, - }} - /> - } - onSubmit={handleDeposit} - submitButton={ - walletIsConnected(status) ? ( - - ) : ( - - ) - } - /> + } + onSubmit={handleDeposit} + submitButton={getSubmitButton()} + /> + {isPartnersDrawerOpen && ( + setIsPartnersDrawerOpen(false)} + operation="deposit" + token={fromToken} + /> + )} + ) } diff --git a/webapp/components/customTunnelsThroughPartner/index.tsx b/webapp/components/customTunnelsThroughPartner/index.tsx new file mode 100644 index 00000000..5a794a46 --- /dev/null +++ b/webapp/components/customTunnelsThroughPartner/index.tsx @@ -0,0 +1,63 @@ +import { Drawer, DrawerParagraph, DrawerTitle } from 'components/drawer' +import { ExternalLink } from 'components/externalLink' +import hemiSocials from 'hemi-socials' +import { hemiMainnet } from 'networks/hemiMainnet' +import { mainnet } from 'networks/mainnet' +import { useTranslations } from 'next-intl' +import { Token } from 'types/token' +import { CloseIcon } from 'ui-common/components/closeIcon' +import { isEvmToken } from 'utils/token' + +import { Stargate } from './stargate' + +const customTunnelTokens = ['USDC', 'USDT'] + +export const tunnelsThroughPartner = (token: Token) => + customTunnelTokens.includes(token.symbol) && + isEvmToken(token) && + [hemiMainnet.id, mainnet.id].includes(token.chainId) + +type Props = { + onClose: () => void + operation: 'deposit' | 'withdraw' + token: Token +} + +export const CustomTunnelsThroughPartner = function ({ + onClose, + operation, + token, +}: Props) { + const t = useTranslations('tunnel-page.tunnel-partners') + + return ( + +
+
+ + {t(`${operation}.heading`, { symbol: token.symbol })} + + +
+ + {t(`${operation}.subheading`, { symbol: token.symbol })} + + +

+ {t.rich('description', { + contact: (chunk: string) => ( + + {chunk} + + ), + })} +

+
+
+ ) +} diff --git a/webapp/components/customTunnelsThroughPartner/partnerLink.tsx b/webapp/components/customTunnelsThroughPartner/partnerLink.tsx new file mode 100644 index 00000000..3c2a2f45 --- /dev/null +++ b/webapp/components/customTunnelsThroughPartner/partnerLink.tsx @@ -0,0 +1,23 @@ +import { ExternalLink } from 'components/externalLink' +import { Chevron } from 'components/icons/chevron' +import { ReactNode } from 'react' + +export const PartnerLink = ({ + icon, + text, + url, +}: { + icon: ReactNode + text: string + url: string +}) => ( + + {icon} + {text} + + +) diff --git a/webapp/components/customTunnelsThroughPartner/partnerLogos/stargate.svg b/webapp/components/customTunnelsThroughPartner/partnerLogos/stargate.svg new file mode 100644 index 00000000..2e431cdc --- /dev/null +++ b/webapp/components/customTunnelsThroughPartner/partnerLogos/stargate.svg @@ -0,0 +1,82 @@ + + + + + + + + diff --git a/webapp/components/customTunnelsThroughPartner/stargate.tsx b/webapp/components/customTunnelsThroughPartner/stargate.tsx new file mode 100644 index 00000000..119a5b28 --- /dev/null +++ b/webapp/components/customTunnelsThroughPartner/stargate.tsx @@ -0,0 +1,25 @@ +import Image from 'next/image' +import { useTranslations } from 'next-intl' + +import { PartnerLink } from './partnerLink' +import stargateLogo from './partnerLogos/stargate.svg' + +export const Stargate = function () { + const t = useTranslations('tunnel-page.tunnel-partners') + return ( + + } + text={t('tunnel-with-stargate')} + // URL is TBD, see https://github.com/hemilabs/ui-monorepo/issues/719 + url="https://stargate.finance" + /> + ) +} diff --git a/webapp/messages/en.json b/webapp/messages/en.json index f0ea96b9..77769506 100644 --- a/webapp/messages/en.json +++ b/webapp/messages/en.json @@ -313,6 +313,19 @@ "withdrawal-proved": "Withdrawal proved", "withdrawing": "Withdrawing {fromInput} {symbol}", "withdrawn": "{fromInput} {symbol} withdrawn" + }, + "tunnel-partners": { + "deposit": { + "heading": "Deposit {symbol}", + "subheading": "To deposit {symbol}, you’ll be redirected to one of our trusted partner bridges. Choose a bridge below to continue." + }, + "description": "Once selected, you’ll be redirected to complete your deposit. For assistance, contact us.", + "tunnel-with-our-partners": "Tunnel with our partners", + "tunnel-with-stargate": "Tunnel with our partner Stargate", + "withdraw": { + "heading": "Withdraw {symbol}", + "subheading": "To withdraw {symbol}, you’ll be redirected to one of our trusted partner bridges. Choose a bridge below to continue." + } } } } diff --git a/webapp/messages/es.json b/webapp/messages/es.json index d475736f..6a5f97bc 100644 --- a/webapp/messages/es.json +++ b/webapp/messages/es.json @@ -313,6 +313,19 @@ "withdrawal-proved": "Retiro probado", "withdrawing": "Retirando {fromInput} {symbol}", "withdrawn": "{fromInput} {symbol} retirado" + }, + "tunnel-partners": { + "deposit": { + "heading": "Depositar {symbol}", + "subheading": "Para depositar {symbol}, será redirigido a uno de nuestros puentes asociados de confianza. Elija un puente a continuación para continuar." + }, + "description": "Una vez seleccionado, será redirigido para completar su depósito. Para asistencia, contáctenos.", + "tunnel-with-our-partners": "Tunelizar con nuestros socios", + "tunnel-with-stargate": "Tunelizar con nuestro socio Stargate", + "withdraw": { + "heading": "Retirar {symbol}", + "subheading": "Para retirar {symbol}, será redirigido a uno de nuestros puentes asociados de confianza. Elija un puente a continuación para continuar." + } } } } From 0e0034c5d8003d14de16fb61f661861860d508ef Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Fri, 3 Jan 2025 16:13:45 -0300 Subject: [PATCH 4/5] Add Drawer for partners for withdraw op --- .../[locale]/tunnel/_components/withdraw.tsx | 60 ++++++++++++++----- webapp/tokenList.ts | 1 + 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/webapp/app/[locale]/tunnel/_components/withdraw.tsx b/webapp/app/[locale]/tunnel/_components/withdraw.tsx index e167d003..e6e08f87 100644 --- a/webapp/app/[locale]/tunnel/_components/withdraw.tsx +++ b/webapp/app/[locale]/tunnel/_components/withdraw.tsx @@ -1,5 +1,9 @@ import { Big } from 'big.js' import { Button } from 'components/button' +import { + CustomTunnelsThroughPartner, + tunnelsThroughPartner, +} from 'components/customTunnelsThroughPartner' import { useAccounts } from 'hooks/useAccounts' import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance' import { useWithdrawBitcoin } from 'hooks/useBtcTunnel' @@ -254,6 +258,7 @@ type EvmWithdrawProps = { const EvmWithdraw = function ({ state }: EvmWithdrawProps) { const [isWithdrawing, setIsWithdrawing] = useState(false) + const [isPartnersDrawerOpen, setIsPartnersDrawerOpen] = useState(false) const t = useTranslations() @@ -345,6 +350,30 @@ const EvmWithdraw = function ({ state }: EvmWithdrawProps) { symbol: fromChain?.nativeCurrency.symbol, } + const getSubmitButton = function () { + if (tunnelsThroughPartner(fromToken)) { + return ( + + ) + } + + if (walletIsConnected(status)) { + return ( + + ) + } + + return + } + return ( <> updateFromInput(maxBalance)} /> } - tunnelState={state} + tunnelState={{ + ...state, + updateFromToken(from, to) { + if (tunnelsThroughPartner(from)) { + setIsPartnersDrawerOpen(true) + } + state.updateFromToken(from, to) + }, + }} /> } onSubmit={handleWithdraw} - submitButton={ - walletIsConnected(status) ? ( - - ) : ( - - ) - } + submitButton={getSubmitButton()} /> + {isPartnersDrawerOpen && ( + setIsPartnersDrawerOpen(false)} + operation="withdraw" + token={fromToken} + /> + )} ) } diff --git a/webapp/tokenList.ts b/webapp/tokenList.ts index 839ae783..c1dabc3f 100644 --- a/webapp/tokenList.ts +++ b/webapp/tokenList.ts @@ -48,6 +48,7 @@ const hemiTokens: Token[] = (hemilabsTokenList.tokens as EvmToken[]) .filter(t => t.chainId === hemiMainnet.id || t.chainId === hemiTestnet.id) // WETH cannot be tunneled, so we must exclude it .filter(t => t.symbol !== 'WETH') + .map(t => ({ ...t, symbol: t.symbol.replace('.e', '').trim() })) // the hemiTokens only contains definitions for Hemi tokens, but we can create the L1 version with the extensions field info const tokens: Token[] = hemiTokens.concat(hemiTokens.flatMap(getRemoteTokens)) From c9176750633ee75a00a30eadb652f59207f5cdfb Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Fri, 3 Jan 2025 18:19:51 -0300 Subject: [PATCH 5/5] Use TODO format for linking issue in stargate.tsx --- webapp/components/customTunnelsThroughPartner/stargate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/components/customTunnelsThroughPartner/stargate.tsx b/webapp/components/customTunnelsThroughPartner/stargate.tsx index 119a5b28..b806733b 100644 --- a/webapp/components/customTunnelsThroughPartner/stargate.tsx +++ b/webapp/components/customTunnelsThroughPartner/stargate.tsx @@ -18,7 +18,7 @@ export const Stargate = function () { /> } text={t('tunnel-with-stargate')} - // URL is TBD, see https://github.com/hemilabs/ui-monorepo/issues/719 + // TODO URL is TBD, see https://github.com/hemilabs/ui-monorepo/issues/719 url="https://stargate.finance" /> )