Skip to content

Commit

Permalink
feat: swap lazy loading (#1181)
Browse files Browse the repository at this point in the history
* feat: swap lazy loading

* Feat/lifi swap (#1187)

* feat: lifi swap draft, almost done

* chore: re-enable-ksm-routes (#1180)

* fix: tao staking fee estimation (#1183)

* feat: wip

* feat: lifi integration done

* fix: swap page infinite rerender (#1185)

* feat: lifi swap search

* feat: better search, category, copy address and more

* feat: safe list, better fiat value, others

* fix: ui overflow, turn off autocomplete, number notation, minor ui and etc

* feat: curated categories, added comments

* refactor: address PR comments

---------

Co-authored-by: Will Urban <[email protected]>

* fix: deploy

* fix: yarn.lock

* fix: redeploy

---------

Co-authored-by: Will Urban <[email protected]>
  • Loading branch information
chrisling-dev and UrbanWill authored Oct 17, 2024
1 parent e352e8d commit df037d7
Show file tree
Hide file tree
Showing 24 changed files with 2,177 additions and 466 deletions.
1 change: 1 addition & 0 deletions apps/portal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@chainflip/sdk": "1.3.0",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@lifi/sdk": "^3.2.3",
"@polkadot-api/descriptors": "^0.0.1",
"@polkadot-api/utils": "^0.1.0",
"@polkadot-onboard/core": "^1.1.0",
Expand Down
151 changes: 116 additions & 35 deletions apps/portal/src/components/widgets/chainflip-swap/SwapTokenRow.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,64 @@
import { SwappableAssetWithDecimals } from './swap-modules/common.swap-module'
import { uniswapExtendedTokensList, uniswapSafeTokensList } from './swaps.api'
import { selectedCurrencyState } from '@/domains/balances'
import { useCopied } from '@/hooks/useCopied'
import { truncateAddress } from '@/util/helpers'
import { useTokenRates, useTokens } from '@talismn/balances-react'
import { githubUnknownTokenLogoUrl } from '@talismn/chaindata-provider'
import { Decimal } from '@talismn/math'
import { Clickable, Skeleton, Surface } from '@talismn/ui'
import { Skeleton, toast } from '@talismn/ui'
import { Check, Copy, ExternalLink } from '@talismn/web-icons'
import { useAtomValue } from 'jotai'
import { loadable } from 'jotai/utils'
import { AlertTriangle } from 'lucide-react'
import { useCallback, useMemo } from 'react'
import { Link } from 'react-router-dom'
import { useRecoilValue } from 'recoil'

type Props = {
asset: SwappableAssetWithDecimals
networkName: string
networkLogo?: string
evmAddress?: `0x${string}`
substrateAddress?: string
onClick: (asset: SwappableAssetWithDecimals) => void
erc20Address?: string
onClick: (asset: SwappableAssetWithDecimals, showWarning: boolean) => void
balance?: Decimal
explorerUrl?: string
}

export const SwapTokenRow: React.FC<Props> = ({
asset,
balance,
networkLogo,
networkName,
erc20Address,
evmAddress,
explorerUrl,
substrateAddress,
onClick,
}) => {
const currency = useRecoilValue(selectedCurrencyState)
const rates = useTokenRates()
const tokens = useTokens()
const { copied, copy } = useCopied()
const uniswapSafeList = useAtomValue(loadable(uniswapSafeTokensList))
const uniswapExtendedList = useAtomValue(loadable(uniswapExtendedTokensList))

const isSafe = useMemo(
() =>
uniswapSafeList.state === 'hasData'
? uniswapSafeList.data.some(t => t.address.toLowerCase() === erc20Address?.toLowerCase())
: false,
[erc20Address, uniswapSafeList]
)
const isExtended = useMemo(
() =>
uniswapExtendedList.state === 'hasData'
? uniswapExtendedList.data.some(t => t.address.toLowerCase() === erc20Address?.toLowerCase())
: false,
[erc20Address, uniswapExtendedList]
)

const bestGuessRate = useMemo(() => {
if (!tokens) return undefined
Expand All @@ -35,55 +67,104 @@ export const SwapTokenRow: React.FC<Props> = ({

const rate = useMemo(() => rates?.[asset.id] ?? bestGuessRate, [asset.id, bestGuessRate, rates])

const shouldShowWarning = useMemo(
() => !isExtended && !isSafe && erc20Address !== undefined,
[erc20Address, isExtended, isSafe]
)

const handleClick = useCallback(() => {
onClick(asset)
}, [asset, onClick])
onClick(asset, shouldShowWarning)
}, [asset, onClick, shouldShowWarning])

return (
<Clickable.WithFeedback className="w-full" onClick={handleClick}>
<Surface className="!w-full !h-[72px] !rounded-[8px] grid grid-cols-3 px-[16px] gap-[8px]">
<div className="w-full flex items-center gap-[8px]">
<div
className="!w-full !h-[64px] !rounded-[12px] grid grid-cols-3 px-[16px] gap-[8px] hover:bg-gray-800 cursor-pointer"
onClick={handleClick}
>
<div className="w-full flex items-center gap-[8px]">
<div className="relative">
{networkLogo ? (
<img
src={networkLogo}
key={networkLogo}
className="border-[2px] bg-gray-800 border-gray-800 w-[12px] absolute -top-[4px] -right-[4px] h-[12px] min-w-[12px] sm:min-w-[20px] sm:w-[20px] sm:h-[20px] rounded-full"
/>
) : null}
<img
key={asset.image ?? githubUnknownTokenLogoUrl}
src={asset.image ?? githubUnknownTokenLogoUrl}
className="w-[24px] h-[24px] min-w-[24px] sm:min-w-[40px] sm:w-[40px] sm:h-[40px] rounded-full"
/>
<div className="flex flex-col gap-[4px] overflow-hidden">
</div>
<div className="flex flex-col gap-[4px] overflow-hidden">
<div className="flex items-center gap-[4px]">
<p className="text-[14px] leading-none">{asset.symbol}</p>
<p className="text-[12px] truncate leading-none !text-muted-foreground">{asset.name}</p>
{shouldShowWarning && <AlertTriangle className="text-gray-400" size={14} />}
</div>
<p className="text-[12px] truncate leading-none !text-muted-foreground">{asset.name}</p>
</div>
</div>

<div className="flex items-center">
<p className="text-[14px]">{networkName}</p>
</div>

{(asset.networkType === 'evm' && evmAddress) || (asset.networkType === 'substrate' && substrateAddress) ? (
balance ? (
<div className="flex items-end flex-col justify-center">
<p className="text-[14px] font-medium">{balance?.toLocaleString(undefined, {})}</p>
{rate ? (
<p className="text-muted-foreground text-[12px]">
{((rate[currency] ?? 0) * balance.toNumber()).toLocaleString(undefined, {
currency,
style: 'currency',
})}
<div className="flex flex-col justify-center">
<p className="text-[14px]">{networkName}</p>
{erc20Address ? (
explorerUrl ? (
<Link to={`${explorerUrl}/token/${erc20Address}`} target="_blank" onClick={e => e.stopPropagation()}>
<div className="flex items-center gap-[4px] group cursor-pointer">
<p className="text-[12px] text-muted-foreground mt-[2px] group-hover:text-primary">
{truncateAddress(erc20Address)}
</p>
) : null}
</div>
<ExternalLink className="group-hover:text-primary" size={14} />
</div>
</Link>
) : (
<div className="flex items-end flex-col justify-center">
<Skeleton.Surface className="h-[20px] w-[72px]" />
<Skeleton.Surface className="h-[16px] w-[36px] mt-[4px]" />
<div
className="flex items-center gap-[4px] group cursor-pointer"
onClick={e => {
e.stopPropagation()
copy(erc20Address)
toast('Copied token address!')
}}
>
<p className="text-[12px] text-muted-foreground mt-[2px] group-hover:text-primary">
{truncateAddress(erc20Address)}
</p>
{copied ? (
<Check size={14} className="text-green-400" />
) : (
<Copy size={14} className="group-hover:text-primary" />
)}
</div>
)
) : null}
</div>

{(asset.networkType === 'evm' && evmAddress) || (asset.networkType === 'substrate' && substrateAddress) ? (
balance ? (
<div className="flex items-end flex-col justify-center">
<p className="text-[14px] font-medium">{balance?.toLocaleString(undefined, {})}</p>
{rate ? (
<p className="text-muted-foreground text-[12px]">
{((rate[currency] ?? 0) * balance.toNumber()).toLocaleString(undefined, {
currency,
style: 'currency',
})}
</p>
) : null}
</div>
) : (
<div className="flex flex-col items-end justify-center">
<p className="font-medium text-[12px] text-right text-muted-foreground">
{rate?.[currency]?.toLocaleString(undefined, { currency, style: 'currency' }) ?? '-'}
</p>
<div className="flex items-end flex-col justify-center">
<Skeleton.Surface className="h-[20px] w-[72px]" />
<Skeleton.Surface className="h-[16px] w-[36px] mt-[4px]" />
</div>
)}
</Surface>
</Clickable.WithFeedback>
)
) : (
<div className="flex flex-col items-end justify-center">
<p className="font-medium text-[12px] text-right text-muted-foreground">
{rate?.[currency]?.toLocaleString(undefined, { currency, style: 'currency' }) ?? '-'}
</p>
</div>
)}
</div>
)
}
Loading

0 comments on commit df037d7

Please sign in to comment.