From 12b4073187e553c8173a426b0dc6d0b6a9f14b04 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz <43585069+Sharqiewicz@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:39:20 +0200 Subject: [PATCH] Update the EUR icon and name on Vortex UI (#95) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add EUR icon * show fiat icons in pool selector modal * improve code readability of SelectionModal * implement showing FIAT * simplify useGetIcon hook * Simplify and streamline icon definition * Fix bug for invalid token storage items --------- Co-authored-by: Torsten Stùˆber <15174476+TorstenStueber@users.noreply.github.com> --- src/assets/coins/EUR.svg | 34 ++++++++++++++ src/components/AssetNumericInput/index.tsx | 32 +++---------- src/components/ExchangeRate/index.tsx | 16 +++---- src/components/FeeCollapse/index.tsx | 8 ++-- .../InputKeys/PoolListItem/index.tsx | 6 ++- src/components/InputKeys/SelectionModal.tsx | 12 ++--- src/components/Nabla/useSwapForm.tsx | 8 +++- src/components/buttons/AssetButton/index.tsx | 15 +++---- src/constants/tokenConfig.ts | 21 ++++++--- src/hooks/useGetIcon.tsx | 45 ++++--------------- src/pages/swap/index.tsx | 45 ++++++++++--------- 11 files changed, 121 insertions(+), 121 deletions(-) create mode 100644 src/assets/coins/EUR.svg diff --git a/src/assets/coins/EUR.svg b/src/assets/coins/EUR.svg new file mode 100644 index 00000000..405d6472 --- /dev/null +++ b/src/assets/coins/EUR.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/AssetNumericInput/index.tsx b/src/components/AssetNumericInput/index.tsx index da752c2c..e9b35755 100644 --- a/src/components/AssetNumericInput/index.tsx +++ b/src/components/AssetNumericInput/index.tsx @@ -1,48 +1,29 @@ import { FC, useMemo } from 'preact/compat'; import { UseFormRegisterReturn } from 'react-hook-form'; -import { ConnectButton } from '@rainbow-me/rainbowkit'; -import { InputTokenType, OutputTokenType } from '../../constants/tokenConfig'; import { AssetButton } from '../buttons/AssetButton'; import { SwapFormValues } from '../Nabla/schema'; import { NumericInput } from '../NumericInput'; - -export const ChainName = () => ( - - {({ account, chain, openChainModal, openConnectModal, authenticationStatus, mounted }) => { - const ready = mounted && authenticationStatus !== 'loading'; - const connected = - ready && account && chain && (!authenticationStatus || authenticationStatus === 'authenticated'); - - return ( - - ); - }} - -); +import { AssetIconType } from '../../hooks/useGetIcon'; interface AssetNumericInputProps { - tokenType?: InputTokenType | OutputTokenType; - tokenSymbol?: string; + assetIcon: AssetIconType; + tokenSymbol: string; onClick: () => void; - additionalText?: string; disabled?: boolean; readOnly?: boolean; registerInput: UseFormRegisterReturn; } export const AssetNumericInput: FC = ({ - additionalText, - tokenType, + assetIcon, tokenSymbol, onClick, registerInput, ...rest }) => { const memoizedAssetButton = useMemo( - () => , - [tokenType, tokenSymbol, onClick], + () => , + [assetIcon, tokenSymbol, onClick], ); return ( @@ -55,7 +36,6 @@ export const AssetNumericInput: FC = ({
{memoizedAssetButton}
- {additionalText ?

{additionalText}

: }
= ({ tokenOutData, fromToken, toToken }) => { +export const ExchangeRate: FC = ({ tokenOutData, fromToken, toTokenSymbol }) => { const exchangeRate = - fromToken !== undefined && toToken !== undefined && !tokenOutData.isLoading && tokenOutData.data ? ( - <>{`1 ${fromToken.assetSymbol} = ${Number(tokenOutData.data.effectiveExchangeRate).toFixed(2)} ${ - toToken.stellarAsset.code.string - }`} + fromToken !== undefined && !tokenOutData.isLoading && tokenOutData.data ? ( + <>{`1 ${fromToken.assetSymbol} = ${Number(tokenOutData.data.effectiveExchangeRate).toFixed( + 2, + )} ${toTokenSymbol}`} ) : ( `-` ); diff --git a/src/components/FeeCollapse/index.tsx b/src/components/FeeCollapse/index.tsx index 65de11bd..b11cabfc 100644 --- a/src/components/FeeCollapse/index.tsx +++ b/src/components/FeeCollapse/index.tsx @@ -23,10 +23,10 @@ function calculateFeesUSD(fromAmount: string): string { interface CollapseProps { fromAmount?: string; toAmount?: string; - toCurrency?: OutputTokenType; + toTokenSymbol: string; } -export const FeeCollapse: FC = ({ fromAmount, toAmount, toCurrency }) => { +export const FeeCollapse: FC = ({ fromAmount, toAmount, toTokenSymbol }) => { const [isOpen, setIsOpen] = useState(false); const { trackEvent } = useEventsContext(); @@ -35,8 +35,6 @@ export const FeeCollapse: FC = ({ fromAmount, toAmount, toCurrenc setIsOpen((state) => !state); }; - const outputToken = toCurrency ? OUTPUT_TOKEN_CONFIG[toCurrency] : undefined; - const chevron = isOpen ? ( ) : ( @@ -52,7 +50,7 @@ export const FeeCollapse: FC = ({ fromAmount, toAmount, toCurrenc

- {totalReceive} {outputToken?.stellarAsset.code.string} + {totalReceive} {toTokenSymbol}  is what you will receive, after fees

diff --git a/src/components/InputKeys/PoolListItem/index.tsx b/src/components/InputKeys/PoolListItem/index.tsx index 02fa83e5..19ecf805 100644 --- a/src/components/InputKeys/PoolListItem/index.tsx +++ b/src/components/InputKeys/PoolListItem/index.tsx @@ -1,6 +1,6 @@ import { Avatar, AvatarProps, Button } from 'react-daisyui'; import { CheckIcon } from '@heroicons/react/20/solid'; -import { useGetIcon } from '../../../hooks/useGetIcon'; +import { AssetIconType, useGetIcon } from '../../../hooks/useGetIcon'; import { InputTokenType, OutputTokenType } from '../../../constants/tokenConfig'; interface PoolListItemProps { @@ -8,6 +8,7 @@ interface PoolListItemProps { tokenSymbol: string; isSelected?: boolean; onSelect: (tokenType: T) => void; + assetIcon: AssetIconType; } export function PoolListItem({ @@ -15,8 +16,9 @@ export function PoolListItem({ tokenSymbol, isSelected, onSelect, + assetIcon, }: PoolListItemProps) { - const tokenIcon = useGetIcon(tokenType); + const tokenIcon = useGetIcon(assetIcon); return ( ); } diff --git a/src/constants/tokenConfig.ts b/src/constants/tokenConfig.ts index 1873e893..47e4e2d8 100644 --- a/src/constants/tokenConfig.ts +++ b/src/constants/tokenConfig.ts @@ -1,5 +1,4 @@ -import UsdcIcon from '../assets/coins/USDC.png'; -import EurcIcon from '../assets/coins/EURC.png'; +import { AssetIconType } from '../hooks/useGetIcon'; export interface InputTokenDetails { assetSymbol: string; @@ -9,15 +8,21 @@ export interface InputTokenDetails { pendulumCurrencyId: { XCM: number }; pendulumAssetSymbol: string; }; + polygonAssetIcon: AssetIconType; decimals: number; - icon: string; } export type InputTokenType = 'usdc' | 'usdce'; +export interface Fiat { + assetIcon: AssetIconType; + symbol: string; +} + export interface OutputTokenDetails { tomlFileUrl: string; decimals: number; + fiat: Fiat; stellarAsset: { code: { hex: string; @@ -32,7 +37,6 @@ export interface OutputTokenDetails { minWithdrawalAmountRaw: string; maxWithdrawalAmountRaw: string; erc20WrapperAddress: string; - icon: string; } export const INPUT_TOKEN_CONFIG: Record = { usdc: { @@ -43,8 +47,8 @@ export const INPUT_TOKEN_CONFIG: Record = { pendulumCurrencyId: { XCM: 12 }, pendulumAssetSymbol: 'USDC.axl', }, + polygonAssetIcon: 'polygonUSDC', decimals: 6, - icon: UsdcIcon, }, usdce: { assetSymbol: 'USDC.e', @@ -54,8 +58,8 @@ export const INPUT_TOKEN_CONFIG: Record = { pendulumCurrencyId: { XCM: 12 }, pendulumAssetSymbol: 'USDC.axl', }, + polygonAssetIcon: 'polygonUSDC', decimals: 6, - icon: UsdcIcon, }, }; @@ -64,6 +68,10 @@ export const OUTPUT_TOKEN_CONFIG: Record = eurc: { tomlFileUrl: 'https://mykobo.co/.well-known/stellar.toml', decimals: 12, + fiat: { + assetIcon: 'eur', + symbol: 'EUR', + }, stellarAsset: { code: { hex: '0x45555243', @@ -78,7 +86,6 @@ export const OUTPUT_TOKEN_CONFIG: Record = erc20WrapperAddress: '6fA9DRKJ12oTXfSAU7ZZGZ9gEQ92YnyRXeJzW1wXekPzeXZC', minWithdrawalAmountRaw: '10000000000000', maxWithdrawalAmountRaw: '10000000000000000', - icon: EurcIcon, }, }; diff --git a/src/hooks/useGetIcon.tsx b/src/hooks/useGetIcon.tsx index b20723ee..40343de5 100644 --- a/src/hooks/useGetIcon.tsx +++ b/src/hooks/useGetIcon.tsx @@ -1,47 +1,18 @@ -import { useChainId } from 'wagmi'; -import { polygon } from 'wagmi/chains'; - import EURC from '../assets/coins/EURC.png'; +import EUR from '../assets/coins/EUR.svg'; import USDC from '../assets/coins/USDC.png'; import USDC_POLYGON from '../assets/coins/USDC_POLYGON.svg'; import DefaultIcon from '../assets/coins/PEN.png'; -import { InputTokenType, OutputTokenType } from '../constants/tokenConfig'; - -type IconMap = Partial>; -const icons: IconMap = { +const ICONS = { eurc: EURC, - usdce: USDC, + eur: EUR, + usdc: USDC, + polygonUSDC: USDC_POLYGON, }; -const polygonIcons: IconMap = { - usdc: USDC_POLYGON, - usdce: USDC_POLYGON, -}; - -const IconMaps: Record = { - [polygon.id]: polygonIcons, - default: icons, -}; - -export function useGetIcon(token?: InputTokenType | OutputTokenType, defaultIcon = DefaultIcon) { - const currentChainId = useChainId(); - const currentIconMap = IconMaps[currentChainId] || IconMaps.default; - - if (!token) return defaultIcon; - - // map(key => key.toLowerCase()) is used to make the comparison case-insensitive - const currentChainIconMapHasTokenIcon = Object.keys(currentIconMap) - .map((key) => key.toLowerCase()) - .includes(token.toLowerCase()); - - const defaultChainIconMapHasTokenIcon = Object.keys(IconMaps.default) - .map((key) => key.toLowerCase()) - .includes(token.toLowerCase()); +export type AssetIconType = keyof typeof ICONS; - return currentChainIconMapHasTokenIcon - ? currentIconMap[token] - : defaultChainIconMapHasTokenIcon - ? IconMaps.default[token] - : defaultIcon; +export function useGetIcon(assetIcon: AssetIconType, defaultIcon = DefaultIcon) { + return ICONS[assetIcon]; } diff --git a/src/pages/swap/index.tsx b/src/pages/swap/index.tsx index f0c5fb39..b8e71110 100644 --- a/src/pages/swap/index.tsx +++ b/src/pages/swap/index.tsx @@ -134,31 +134,27 @@ export const SwapPage = () => { const ReceiveNumericInput = useMemo( () => ( setModalType('to')} registerInput={form.register('toAmount')} disabled={isQuoteSubmitted || tokenOutData.isLoading} readOnly={true} /> ), - [to, toToken?.stellarAsset.code.string, form, isQuoteSubmitted, tokenOutData.isLoading, setModalType], + [toToken.fiat.symbol, toToken.fiat.assetIcon, to, form, isQuoteSubmitted, tokenOutData.isLoading, setModalType], ); const WidthrawNumericInput = useMemo( () => ( - <> - setIsQuoteSubmitted(true) })} - tokenType={from} - tokenSymbol={fromToken?.assetSymbol} - onClick={() => setModalType('from')} - /> - - + setIsQuoteSubmitted(true) })} + tokenSymbol={fromToken.assetSymbol} + assetIcon={fromToken.polygonAssetIcon} + onClick={() => setModalType('from')} + /> ), - [form, from, fromToken, setModalType], + [form, fromToken.polygonAssetIcon, fromToken.polygonAssetIcon, setModalType], ); function getCurrentErrorMessage() { @@ -173,21 +169,21 @@ export const SwapPage = () => { const amountOut = tokenOutData.data?.amountOut; - if (amountOut !== undefined && toToken !== undefined) { + if (amountOut !== undefined) { const maxAmountRaw = Big(toToken.maxWithdrawalAmountRaw); const minAmountRaw = Big(toToken.minWithdrawalAmountRaw); if (maxAmountRaw.lt(Big(amountOut.rawBalance))) { const maxAmountUnits = multiplyByPowerOfTen(maxAmountRaw, -toToken.decimals); return `Maximum withdrawal amount is ${stringifyBigWithSignificantDecimals(maxAmountUnits, 2)} ${ - toToken.stellarAsset.code.string + toToken.fiat.symbol }.`; } if (config.test.overwriteMinimumTransferAmount === false && minAmountRaw.gt(Big(amountOut.rawBalance))) { const minAmountUnits = multiplyByPowerOfTen(minAmountRaw, -toToken.decimals); return `Minimum withdrawal amount is ${stringifyBigWithSignificantDecimals(minAmountUnits, 2)} ${ - toToken.stellarAsset.code.string + toToken.fiat.symbol }.`; } } @@ -200,10 +196,12 @@ export const SwapPage = () => { ? Object.entries(INPUT_TOKEN_CONFIG).map(([key, value]) => ({ type: key as InputTokenType, assetSymbol: value.assetSymbol, + assetIcon: value.polygonAssetIcon, })) : Object.entries(OUTPUT_TOKEN_CONFIG).map(([key, value]) => ({ type: key as OutputTokenType, - assetSymbol: value.stellarAsset.code.string, + assetSymbol: value.fiat.symbol, + assetIcon: value.fiat.assetIcon, })); const modals = ( @@ -213,7 +211,6 @@ export const SwapPage = () => { definitions={definitions} selected={modalType === 'from' ? from : to} onClose={() => setModalType(undefined)} - isLoading={false} /> ); @@ -241,11 +238,17 @@ export const SwapPage = () => {

{getCurrentErrorMessage()}

- +