Merge pull request #543 from mars-protocol/develop
This commit is contained in:
commit
7272b1eee0
@ -14,15 +14,28 @@ jest.mock('hooks/useHealthComputer', () =>
|
|||||||
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
||||||
|
|
||||||
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
||||||
const mockedAccount = { id: '1', deposits: [], lends: [], debts: [], vaults: [] }
|
const mockedAccounts = [
|
||||||
|
{ id: '1', deposits: [], lends: [], debts: [], vaults: [] },
|
||||||
|
{ id: '2', deposits: [], lends: [], debts: [], vaults: [] },
|
||||||
|
]
|
||||||
jest.mock('hooks/useAccountId', () => jest.fn(() => '1'))
|
jest.mock('hooks/useAccountId', () => jest.fn(() => '1'))
|
||||||
jest.mock('hooks/useAccounts', () => jest.fn(() => [mockedAccount]))
|
jest.mock('hooks/useAccounts', () =>
|
||||||
|
jest.fn(() => ({
|
||||||
|
data: mockedAccounts,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
jest.mock('hooks/useAccountIds', () =>
|
||||||
|
jest.fn(() => ({
|
||||||
|
data: ['1', '2'],
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
jest.mock('hooks/useCurrentAccount', () => jest.fn(() => mockedAccounts[0]))
|
||||||
|
|
||||||
describe('<AccountDetails />', () => {
|
describe('<AccountDetails />', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
useStore.setState({
|
useStore.setState({
|
||||||
address: 'walletAddress',
|
address: 'walletAddress',
|
||||||
accounts: [mockedAccount],
|
accounts: mockedAccounts,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -31,7 +44,7 @@ describe('<AccountDetails />', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('renders account details WHEN account is selected', () => {
|
it('renders account details WHEN account is selected', () => {
|
||||||
mockedUseCurrentAccount.mockReturnValue(mockedAccount)
|
mockedUseCurrentAccount.mockReturnValue(mockedAccounts)
|
||||||
render(<AccountDetails />)
|
render(<AccountDetails />)
|
||||||
|
|
||||||
const container = screen.queryByTestId('account-details')
|
const container = screen.queryByTestId('account-details')
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
productionBrowserSourceMaps: true,
|
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
images: {
|
images: {
|
||||||
domains: [
|
domains: [
|
||||||
@ -26,6 +25,31 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
async headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/(.*)?',
|
||||||
|
headers: [
|
||||||
|
{
|
||||||
|
key: 'Referrer-Policy',
|
||||||
|
value: 'origin-when-cross-origin',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'Pragma',
|
||||||
|
value: 'no-cache',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'Expires',
|
||||||
|
value: new Date().toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'X-Content-Type-Options',
|
||||||
|
value: 'nosniff',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -5,8 +5,8 @@ export default async function getAccountIds(
|
|||||||
address?: string,
|
address?: string,
|
||||||
previousResults?: string[],
|
previousResults?: string[],
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
try {
|
|
||||||
if (!address) return []
|
if (!address) return []
|
||||||
|
try {
|
||||||
const accountNftQueryClient = await getAccountNftQueryClient()
|
const accountNftQueryClient = await getAccountNftQueryClient()
|
||||||
|
|
||||||
const lastItem = previousResults && previousResults.at(-1)
|
const lastItem = previousResults && previousResults.at(-1)
|
||||||
|
@ -17,6 +17,7 @@ import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
|||||||
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useAccountIds from 'hooks/useAccountIds'
|
||||||
import useAccounts from 'hooks/useAccounts'
|
import useAccounts from 'hooks/useAccounts'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
@ -34,12 +35,15 @@ import {
|
|||||||
|
|
||||||
export default function AccountDetailsController() {
|
export default function AccountDetailsController() {
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
const { isLoading } = useAccounts(address)
|
const { data: accounts, isLoading } = useAccounts(address)
|
||||||
|
const { data: accountIds } = useAccountIds(address, false)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
const account = useCurrentAccount()
|
const account = useCurrentAccount()
|
||||||
const focusComponent = useStore((s) => s.focusComponent)
|
|
||||||
|
|
||||||
if (!address || focusComponent) return null
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
|
const isOwnAccount = accountId && accountIds?.includes(accountId)
|
||||||
|
|
||||||
|
if (!address || focusComponent || !isOwnAccount) return null
|
||||||
|
|
||||||
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import AccountStats from 'components/Account/AccountList/AccountStats'
|
import AccountStats from 'components/Account/AccountList/AccountStats'
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
@ -26,7 +26,7 @@ export default function AccountList(props: Props) {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const currentAccountId = useAccountId()
|
const currentAccountId = useAccountId()
|
||||||
const { address } = useParams()
|
const address = useStore((s) => s.address)
|
||||||
const { data: accountIds } = useAccountIds(address)
|
const { data: accountIds } = useAccountIds(address)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -37,7 +37,7 @@ export default function AccountList(props: Props) {
|
|||||||
}
|
}
|
||||||
}, [currentAccountId])
|
}, [currentAccountId])
|
||||||
|
|
||||||
if (!accountIds?.length) return null
|
if (!accountIds || !accountIds.length) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full p-4'>
|
<div className='flex flex-wrap w-full p-4'>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
||||||
import AccountFund from 'components/Account/AccountFund/AccountFundFullPage'
|
import AccountFund from 'components/Account/AccountFund/AccountFundFullPage'
|
||||||
@ -30,7 +30,7 @@ const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
|||||||
export default function AccountMenuContent() {
|
export default function AccountMenuContent() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { address } = useParams()
|
const address = useStore((s) => s.address)
|
||||||
const { data: accountIds } = useAccountIds(address)
|
const { data: accountIds } = useAccountIds(address)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
|
|
||||||
@ -42,8 +42,9 @@ export default function AccountMenuContent() {
|
|||||||
const [lendAssets] = useLocalStorage<boolean>(LEND_ASSETS_KEY, DEFAULT_SETTINGS.lendAssets)
|
const [lendAssets] = useLocalStorage<boolean>(LEND_ASSETS_KEY, DEFAULT_SETTINGS.lendAssets)
|
||||||
const { enableAutoLendAccountId } = useAutoLend()
|
const { enableAutoLendAccountId } = useAutoLend()
|
||||||
|
|
||||||
const hasCreditAccounts = !!accountIds.length
|
const hasCreditAccounts = !!accountIds?.length
|
||||||
const isAccountSelected = isNumber(accountId)
|
const isAccountSelected =
|
||||||
|
hasCreditAccounts && accountId && isNumber(accountId) && accountIds.includes(accountId)
|
||||||
|
|
||||||
const checkHasFunds = useCallback(() => {
|
const checkHasFunds = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -23,7 +23,7 @@ export default function ActionButton(props: ButtonProps) {
|
|||||||
|
|
||||||
if (!address) return <WalletConnectButton {...defaultProps} />
|
if (!address) return <WalletConnectButton {...defaultProps} />
|
||||||
|
|
||||||
if (accountIds.length === 0) {
|
if (accountIds && accountIds.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleCreateAccountClick}
|
onClick={handleCreateAccountClick}
|
||||||
|
@ -28,7 +28,7 @@ export default function FarmIntro() {
|
|||||||
leftIcon={<PlusSquared />}
|
leftIcon={<PlusSquared />}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
window.open(DocURL.ROVER_INTRO_URL, '_blank')
|
window.open(DocURL.FARM_INTRO_URL, '_blank')
|
||||||
}}
|
}}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
/>
|
/>
|
||||||
|
@ -8,7 +8,8 @@ const underlineClasses =
|
|||||||
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
|
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isFarm?: boolean
|
tabs: Tab[]
|
||||||
|
activeTabIdx: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Tab(props: Props) {
|
export default function Tab(props: Props) {
|
||||||
@ -17,24 +18,18 @@ export default function Tab(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative w-full'>
|
<div className='relative w-full'>
|
||||||
|
{props.tabs.map((tab, index) => (
|
||||||
<NavLink
|
<NavLink
|
||||||
to={getRoute('lend', address, accountId)}
|
key={tab.page}
|
||||||
|
to={getRoute(tab.page, address, accountId)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
props.isFarm ? 'text-white/40' : underlineClasses,
|
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
|
||||||
'relative mr-8 text-xl ',
|
'relative mr-8 text-xl ',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Lend
|
{tab.name}
|
||||||
</NavLink>
|
|
||||||
<NavLink
|
|
||||||
to={getRoute('farm', address, accountId)}
|
|
||||||
className={classNames(
|
|
||||||
!props.isFarm ? 'text-white/40' : underlineClasses,
|
|
||||||
'relative text-xl',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Farm
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,14 @@ import Settings from 'components/Settings'
|
|||||||
import Wallet from 'components/Wallet'
|
import Wallet from 'components/Wallet'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { ENABLE_HLS } from 'utils/constants'
|
||||||
|
|
||||||
export const menuTree: { pages: Page[]; label: string }[] = [
|
export const menuTree: { pages: Page[]; label: string }[] = [
|
||||||
{ pages: ['trade'], label: 'Trade' },
|
{ pages: ['trade'], label: 'Trade' },
|
||||||
{ pages: ['lend', 'farm'], label: 'Earn' },
|
{ pages: ['lend', 'farm'], label: 'Earn' },
|
||||||
{ pages: ['borrow'], label: 'Borrow' },
|
{ pages: ['borrow'], label: 'Borrow' },
|
||||||
{ pages: ['portfolio'], label: 'Portfolio' },
|
{ pages: ['portfolio'], label: 'Portfolio' },
|
||||||
|
...(ENABLE_HLS ? [{ pages: ['hls-farm', 'hls-staking'] as Page[], label: 'High Leverage' }] : []),
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function DesktopHeader() {
|
export default function DesktopHeader() {
|
||||||
|
6
src/components/Icons/Chain.svg
Normal file
6
src/components/Icons/Chain.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 512 512">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M459.654,233.373l-90.531,90.5c-49.969,50-131.031,50-181,0c-7.875-7.844-14.031-16.688-19.438-25.813 l42.063-42.063c2-2.016,4.469-3.172,6.828-4.531c2.906,9.938,7.984,19.344,15.797,27.156c24.953,24.969,65.563,24.938,90.5,0 l90.5-90.5c24.969-24.969,24.969-65.563,0-90.516c-24.938-24.953-65.531-24.953-90.5,0l-32.188,32.219 c-26.109-10.172-54.25-12.906-81.641-8.891l68.578-68.578c50-49.984,131.031-49.984,181.031,0 C509.623,102.342,509.623,183.389,459.654,233.373z M220.326,382.186l-32.203,32.219c-24.953,24.938-65.563,24.938-90.516,0 c-24.953-24.969-24.953-65.563,0-90.531l90.516-90.5c24.969-24.969,65.547-24.969,90.5,0c7.797,7.797,12.875,17.203,15.813,27.125 c2.375-1.375,4.813-2.5,6.813-4.5l42.063-42.047c-5.375-9.156-11.563-17.969-19.438-25.828c-49.969-49.984-131.031-49.984-181.016,0 l-90.5,90.5c-49.984,50-49.984,131.031,0,181.031c49.984,49.969,131.031,49.969,181.016,0l68.594-68.594 C274.561,395.092,246.42,392.342,220.326,382.186z"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
7
src/components/Icons/Twitter.svg
Normal file
7
src/components/Icons/Twitter.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 120 120">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M0.3,3.8l46.3,61.9L0,116.2h10.5l40.8-44.1l33,44.1H120L71.1,50.7l43.4-46.9H104L66.4,44.5L36,3.8
|
||||||
|
H0.3z M15.7,11.6h16.4l72.4,96.9H88.2L15.7,11.6z"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 289 B |
@ -7,6 +7,7 @@ export { default as ArrowCircledTopRight } from 'components/Icons/ArrowCircledTo
|
|||||||
export { default as ArrowDownLine } from 'components/Icons/ArrowDownLine.svg'
|
export { default as ArrowDownLine } from 'components/Icons/ArrowDownLine.svg'
|
||||||
export { default as ArrowRight } from 'components/Icons/ArrowRight.svg'
|
export { default as ArrowRight } from 'components/Icons/ArrowRight.svg'
|
||||||
export { default as ArrowUpLine } from 'components/Icons/ArrowUpLine.svg'
|
export { default as ArrowUpLine } from 'components/Icons/ArrowUpLine.svg'
|
||||||
|
export { default as Chain } from 'components/Icons/Chain.svg'
|
||||||
export { default as Check } from 'components/Icons/Check.svg'
|
export { default as Check } from 'components/Icons/Check.svg'
|
||||||
export { default as CheckCircled } from 'components/Icons/CheckCircled.svg'
|
export { default as CheckCircled } from 'components/Icons/CheckCircled.svg'
|
||||||
export { default as ChevronDown } from 'components/Icons/ChevronDown.svg'
|
export { default as ChevronDown } from 'components/Icons/ChevronDown.svg'
|
||||||
@ -54,6 +55,7 @@ export { default as SwapIcon } from 'components/Icons/SwapIcon.svg'
|
|||||||
export { default as ThreeDots } from 'components/Icons/ThreeDots.svg'
|
export { default as ThreeDots } from 'components/Icons/ThreeDots.svg'
|
||||||
export { default as TooltipArrow } from 'components/Icons/TooltipArrow.svg'
|
export { default as TooltipArrow } from 'components/Icons/TooltipArrow.svg'
|
||||||
export { default as TrashBin } from 'components/Icons/TrashBin.svg'
|
export { default as TrashBin } from 'components/Icons/TrashBin.svg'
|
||||||
|
export { default as Twitter } from 'components/Icons/Twitter.svg'
|
||||||
export { default as VerticalThreeLine } from 'components/Icons/VerticalThreeLine.svg'
|
export { default as VerticalThreeLine } from 'components/Icons/VerticalThreeLine.svg'
|
||||||
export { default as Wallet } from 'components/Icons/Wallet.svg'
|
export { default as Wallet } from 'components/Icons/Wallet.svg'
|
||||||
// @endindex
|
// @endindex
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useParams } from 'react-router-dom'
|
|
||||||
|
|
||||||
import { menuTree } from 'components/Header/DesktopHeader'
|
import { menuTree } from 'components/Header/DesktopHeader'
|
||||||
import { Logo } from 'components/Icons'
|
import { Logo } from 'components/Icons'
|
||||||
@ -9,13 +8,14 @@ import useStore from 'store'
|
|||||||
import { getRoute } from 'utils/route'
|
import { getRoute } from 'utils/route'
|
||||||
|
|
||||||
export default function DesktopNavigation() {
|
export default function DesktopNavigation() {
|
||||||
const { address } = useParams()
|
const address = useStore((s) => s.address)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
|
|
||||||
const focusComponent = useStore((s) => s.focusComponent)
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
|
|
||||||
function getIsActive(pages: string[]) {
|
function getIsActive(pages: string[]) {
|
||||||
return pages.some((page) => location.pathname.includes(page))
|
const segments = location.pathname.split('/')
|
||||||
|
return pages.some((page) => segments.includes(page))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -25,7 +25,7 @@ export default function DesktopNavigation() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<NavLink href={getRoute('trade', address, accountId)}>
|
<NavLink href={getRoute('trade', address, accountId)}>
|
||||||
<span className='block h-10 w-10'>
|
<span className='block w-10 h-10'>
|
||||||
<Logo className='text-white' />
|
<Logo className='text-white' />
|
||||||
</span>
|
</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import React, { ReactNode, useMemo } from 'react'
|
import { ReactNode, useMemo } from 'react'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
@ -30,6 +30,7 @@ interface Props {
|
|||||||
export default function PortfolioCard(props: Props) {
|
export default function PortfolioCard(props: Props) {
|
||||||
const { data: account } = useAccount(props.accountId)
|
const { data: account } = useAccount(props.accountId)
|
||||||
const { health } = useHealthComputer(account)
|
const { health } = useHealthComputer(account)
|
||||||
|
const { address: urlAddress } = useParams()
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const currentAccountId = useAccountId()
|
const currentAccountId = useAccountId()
|
||||||
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
||||||
@ -91,7 +92,7 @@ export default function PortfolioCard(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink
|
<NavLink
|
||||||
to={getRoute(`portfolio/${props.accountId}` as Page, address, currentAccountId)}
|
to={getRoute(`portfolio/${props.accountId}` as Page, urlAddress, currentAccountId)}
|
||||||
className={classNames('w-full hover:bg-white/5', !reduceMotion && 'transition-all')}
|
className={classNames('w-full hover:bg-white/5', !reduceMotion && 'transition-all')}
|
||||||
>
|
>
|
||||||
<Skeleton
|
<Skeleton
|
||||||
|
@ -42,7 +42,7 @@ export default function AccountSummary() {
|
|||||||
|
|
||||||
if (!walletAddress && !urlAddress) return <ConnectInfo />
|
if (!walletAddress && !urlAddress) return <ConnectInfo />
|
||||||
|
|
||||||
if (!isLoading && accountIds?.length === 0) {
|
if (!isLoading && accountIds && accountIds.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className='w-full h-fit bg-white/5'
|
className='w-full h-fit bg-white/5'
|
||||||
@ -72,7 +72,7 @@ export default function AccountSummary() {
|
|||||||
<div
|
<div
|
||||||
className={classNames('grid w-full grid-cols-1 gap-6', 'md:grid-cols-2', 'lg:grid-cols-3')}
|
className={classNames('grid w-full grid-cols-1 gap-6', 'md:grid-cols-2', 'lg:grid-cols-3')}
|
||||||
>
|
>
|
||||||
{accountIds.map((accountId: string, index: number) => {
|
{accountIds?.map((accountId: string, index: number) => {
|
||||||
return <PortfolioCard key={accountId} accountId={accountId} />
|
return <PortfolioCard key={accountId} accountId={accountId} />
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,17 +4,18 @@ import Intro from 'components/Intro'
|
|||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
export default function PortfolioIntro() {
|
export default function PortfolioIntro() {
|
||||||
const { address } = useParams()
|
const { address: urlAddress } = useParams()
|
||||||
const walletAddress = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
const isCurrentWalllet = !urlAddress || urlAddress === address
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Intro
|
<Intro
|
||||||
text={
|
text={
|
||||||
address && !walletAddress ? (
|
!isCurrentWalllet ? (
|
||||||
<>
|
<>
|
||||||
This is the <span className='text-white'>Portfolio</span> of the address{' '}
|
This is the <span className='text-white'>Portfolio</span> of the address{' '}
|
||||||
<span className='text-white'>{address}</span>. You can see all Credit Accounts of this
|
<span className='text-white'>{urlAddress}</span>. You can see all Credit Accounts of
|
||||||
address, but you can't interact with them.
|
this address, but you can't interact with them.
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@ -3,6 +3,8 @@ import { Navigate, Outlet, Route, Routes as RoutesWrapper } from 'react-router-d
|
|||||||
import Layout from 'pages/_layout'
|
import Layout from 'pages/_layout'
|
||||||
import BorrowPage from 'pages/BorrowPage'
|
import BorrowPage from 'pages/BorrowPage'
|
||||||
import FarmPage from 'pages/FarmPage'
|
import FarmPage from 'pages/FarmPage'
|
||||||
|
import HLSFarmPage from 'pages/HLSFarmPage'
|
||||||
|
import HLSStakingPage from 'pages/HLSStakingPage'
|
||||||
import LendPage from 'pages/LendPage'
|
import LendPage from 'pages/LendPage'
|
||||||
import MobilePage from 'pages/MobilePage'
|
import MobilePage from 'pages/MobilePage'
|
||||||
import PortfolioAccountPage from 'pages/PortfolioAccountPage'
|
import PortfolioAccountPage from 'pages/PortfolioAccountPage'
|
||||||
@ -25,6 +27,8 @@ export default function Routes() {
|
|||||||
<Route path='/borrow' element={<BorrowPage />} />
|
<Route path='/borrow' element={<BorrowPage />} />
|
||||||
<Route path='/portfolio' element={<PortfolioPage />} />
|
<Route path='/portfolio' element={<PortfolioPage />} />
|
||||||
<Route path='/mobile' element={<MobilePage />} />
|
<Route path='/mobile' element={<MobilePage />} />
|
||||||
|
<Route path='/hls-staking' element={<HLSStakingPage />} />
|
||||||
|
<Route path='/hls-farm' element={<HLSFarmPage />} />
|
||||||
<Route path='/' element={<TradePage />} />
|
<Route path='/' element={<TradePage />} />
|
||||||
<Route path='/wallets/:address'>
|
<Route path='/wallets/:address'>
|
||||||
<Route path='trade' element={<TradePage />} />
|
<Route path='trade' element={<TradePage />} />
|
||||||
@ -35,6 +39,8 @@ export default function Routes() {
|
|||||||
<Route path='portfolio/:accountId'>
|
<Route path='portfolio/:accountId'>
|
||||||
<Route path='' element={<PortfolioAccountPage />} />
|
<Route path='' element={<PortfolioAccountPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path='hls-staking' element={<HLSStakingPage />} />
|
||||||
|
<Route path='hls-farm' element={<HLSFarmPage />} />
|
||||||
<Route path='' element={<TradePage />} />
|
<Route path='' element={<TradePage />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path='*' element={<Navigate to='/' />} />
|
<Route path='*' element={<Navigate to='/' />} />
|
||||||
|
55
src/components/ShareBar.tsx
Normal file
55
src/components/ShareBar.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import { useLocation, useParams } from 'react-router-dom'
|
||||||
|
import useClipboard from 'react-use-clipboard'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import { Chain, Check, Twitter } from 'components/Icons'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import { Tooltip } from 'components/Tooltip'
|
||||||
|
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||||
|
import { DocURL } from 'types/enums/docURL'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ShareBar(props: Props) {
|
||||||
|
const { address } = useParams()
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const currentUrl = `https://${location.host}${pathname}`
|
||||||
|
const [isCopied, setCopied] = useClipboard(currentUrl, {
|
||||||
|
successDuration: 1000 * 5,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!window || !address) return null
|
||||||
|
return (
|
||||||
|
<div className='flex justify-end w-full gap-4'>
|
||||||
|
<ConditionalWrapper
|
||||||
|
condition={isCopied}
|
||||||
|
wrapper={(children) => (
|
||||||
|
<Tooltip type='info' content={<Text size='2xs'>Link copied!</Text>}>
|
||||||
|
{children}
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color='secondary'
|
||||||
|
iconClassName='w-4 h-4'
|
||||||
|
className={classNames('!p-2', isCopied && '!bg-transparent')}
|
||||||
|
leftIcon={isCopied ? <Check /> : <Chain />}
|
||||||
|
onClick={setCopied}
|
||||||
|
/>
|
||||||
|
</ConditionalWrapper>
|
||||||
|
<Button
|
||||||
|
color='secondary'
|
||||||
|
iconClassName='w-4 h-4'
|
||||||
|
className='!p-2'
|
||||||
|
leftIcon={<Twitter />}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
window.open(`${DocURL.X_SHARE_URL}?text=${props.text} ${currentUrl}`, '_blank')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -224,7 +224,8 @@ export class OsmosisTheGraphDataFeed implements IDatafeedChartApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filler = Array.from({ length: this.batchSize - bars.length }).map((_, index) => ({
|
const filler = Array.from({ length: this.batchSize - bars.length }).map((_, index) => ({
|
||||||
time: (bars[0]?.time || new Date().getTime()) - index * this.minutesPerInterval[resolution],
|
time:
|
||||||
|
(bars[0]?.time || new Date().getTime()) - index * this.minutesPerInterval[resolution],
|
||||||
close: 0,
|
close: 0,
|
||||||
open: 0,
|
open: 0,
|
||||||
high: 0,
|
high: 0,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Suspense, useEffect, useMemo } from 'react'
|
import { Suspense, useEffect, useMemo } from 'react'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
@ -27,6 +27,7 @@ function FetchLoading() {
|
|||||||
|
|
||||||
function Content() {
|
function Content() {
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
const { address: urlAddress } = useParams()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { data: accountIds, isLoading: isLoadingAccounts } = useAccountIds(address || '')
|
const { data: accountIds, isLoading: isLoadingAccounts } = useAccountIds(address || '')
|
||||||
@ -39,18 +40,26 @@ function Content() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const page = getPage(pathname)
|
||||||
|
if (page === 'portfolio' && urlAddress && urlAddress !== address) {
|
||||||
|
navigate(getRoute(page, urlAddress as string))
|
||||||
|
useStore.setState({ balances: walletBalances, focusComponent: null })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
accountIds &&
|
||||||
accountIds.length !== 0 &&
|
accountIds.length !== 0 &&
|
||||||
BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount)
|
BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount)
|
||||||
) {
|
) {
|
||||||
navigate(getRoute(getPage(pathname), address, accountIds[0]))
|
navigate(getRoute(page, address, accountIds[0]))
|
||||||
useStore.setState({ balances: walletBalances, focusComponent: null })
|
useStore.setState({ balances: walletBalances, focusComponent: null })
|
||||||
}
|
}
|
||||||
}, [accountIds, baseBalance, navigate, pathname, address, walletBalances])
|
}, [accountIds, baseBalance, navigate, pathname, address, walletBalances, urlAddress])
|
||||||
|
|
||||||
if (isLoadingAccounts || isLoadingBalances) return <FetchLoading />
|
if (isLoadingAccounts || isLoadingBalances) return <FetchLoading />
|
||||||
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) return <WalletBridges />
|
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) return <WalletBridges />
|
||||||
if (accountIds.length === 0) return <AccountCreateFirst />
|
if (accountIds && accountIds.length === 0) return <AccountCreateFirst />
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
src/constants/pages.ts
Normal file
9
src/constants/pages.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const EARN_TABS: Tab[] = [
|
||||||
|
{ page: 'lend', name: 'Lend' },
|
||||||
|
{ page: 'farm', name: 'Farm' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const HLS_TABS: Tab[] = [
|
||||||
|
{ page: 'hls-farm', name: 'Farm' },
|
||||||
|
{ page: 'hls-staking', name: 'Staking' },
|
||||||
|
]
|
@ -2,9 +2,9 @@ import useSWR from 'swr'
|
|||||||
|
|
||||||
import getAccountIds from 'api/wallets/getAccountIds'
|
import getAccountIds from 'api/wallets/getAccountIds'
|
||||||
|
|
||||||
export default function useAccountIds(address?: string) {
|
export default function useAccountIds(address?: string, suspense = true) {
|
||||||
return useSWR(`wallets/${address}/account-ids`, () => getAccountIds(address), {
|
return useSWR(`wallets/${address}/account-ids`, () => getAccountIds(address), {
|
||||||
suspense: true,
|
suspense: suspense,
|
||||||
fallback: [] as string[],
|
fallback: [] as string[],
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
})
|
})
|
||||||
|
@ -2,12 +2,13 @@ import FarmIntro from 'components/Earn/Farm/FarmIntro'
|
|||||||
import { AvailableVaults, DepositedVaults } from 'components/Earn/Farm/Vaults'
|
import { AvailableVaults, DepositedVaults } from 'components/Earn/Farm/Vaults'
|
||||||
import Tab from 'components/Earn/Tab'
|
import Tab from 'components/Earn/Tab'
|
||||||
import MigrationBanner from 'components/MigrationBanner'
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
|
import { EARN_TABS } from 'constants/pages'
|
||||||
|
|
||||||
export default function FarmPage() {
|
export default function FarmPage() {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
<MigrationBanner />
|
<MigrationBanner />
|
||||||
<Tab isFarm />
|
<Tab tabs={EARN_TABS} activeTabIdx={1} />
|
||||||
<FarmIntro />
|
<FarmIntro />
|
||||||
<DepositedVaults />
|
<DepositedVaults />
|
||||||
<AvailableVaults />
|
<AvailableVaults />
|
||||||
|
12
src/pages/HLSFarmPage.tsx
Normal file
12
src/pages/HLSFarmPage.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Tab from 'components/Earn/Tab'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
|
import { HLS_TABS } from 'constants/pages'
|
||||||
|
|
||||||
|
export default function HLSFarmPage() {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
|
<Tab tabs={HLS_TABS} activeTabIdx={0} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
12
src/pages/HLSStakingPage.tsx
Normal file
12
src/pages/HLSStakingPage.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Tab from 'components/Earn/Tab'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
|
import { HLS_TABS } from 'constants/pages'
|
||||||
|
|
||||||
|
export default function HLSStakingPage() {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
|
<Tab tabs={HLS_TABS} activeTabIdx={1} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
import LendIntro from 'components/Earn/Lend/LendIntro'
|
|
||||||
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
|
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
|
||||||
|
import LendIntro from 'components/Earn/Lend/LendIntro'
|
||||||
import Tab from 'components/Earn/Tab'
|
import Tab from 'components/Earn/Tab'
|
||||||
import MigrationBanner from 'components/MigrationBanner'
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
|
import { EARN_TABS } from 'constants/pages'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
|
|
||||||
export default function LendPage() {
|
export default function LendPage() {
|
||||||
@ -9,7 +10,7 @@ export default function LendPage() {
|
|||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
<MigrationBanner />
|
<MigrationBanner />
|
||||||
<Tab />
|
<Tab tabs={EARN_TABS} activeTabIdx={0} />
|
||||||
<LendIntro />
|
<LendIntro />
|
||||||
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />
|
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />
|
||||||
<LendingMarketsTable data={availableAssets} title='Available Markets' />
|
<LendingMarketsTable data={availableAssets} title='Available Markets' />
|
||||||
|
@ -4,6 +4,7 @@ import MigrationBanner from 'components/MigrationBanner'
|
|||||||
import Balances from 'components/Portfolio/Account/Balances'
|
import Balances from 'components/Portfolio/Account/Balances'
|
||||||
import BreadCrumbs from 'components/Portfolio/Account/BreadCrumbs'
|
import BreadCrumbs from 'components/Portfolio/Account/BreadCrumbs'
|
||||||
import Summary from 'components/Portfolio/Account/Summary'
|
import Summary from 'components/Portfolio/Account/Summary'
|
||||||
|
import ShareBar from 'components/ShareBar'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import { getRoute } from 'utils/route'
|
import { getRoute } from 'utils/route'
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ export default function PortfolioAccountPage() {
|
|||||||
<BreadCrumbs accountId={accountId} />
|
<BreadCrumbs accountId={accountId} />
|
||||||
<Summary accountId={accountId} />
|
<Summary accountId={accountId} />
|
||||||
<Balances accountId={accountId} />
|
<Balances accountId={accountId} />
|
||||||
|
<ShareBar text={`Have a look at Credit Account ${accountId} on @mars_protocol!`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import MigrationBanner from 'components/MigrationBanner'
|
|||||||
import AccountOverview from 'components/Portfolio/Overview'
|
import AccountOverview from 'components/Portfolio/Overview'
|
||||||
import PortfolioSummary from 'components/Portfolio/Overview/Summary'
|
import PortfolioSummary from 'components/Portfolio/Overview/Summary'
|
||||||
import PortfolioIntro from 'components/Portfolio/PortfolioIntro'
|
import PortfolioIntro from 'components/Portfolio/PortfolioIntro'
|
||||||
|
import ShareBar from 'components/ShareBar'
|
||||||
|
|
||||||
export default function PortfolioPage() {
|
export default function PortfolioPage() {
|
||||||
return (
|
return (
|
||||||
@ -10,6 +11,7 @@ export default function PortfolioPage() {
|
|||||||
<PortfolioIntro />
|
<PortfolioIntro />
|
||||||
<PortfolioSummary />
|
<PortfolioSummary />
|
||||||
<AccountOverview />
|
<AccountOverview />
|
||||||
|
<ShareBar text='Have a look at this @mars_protocol portfolio!' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ export enum DocURL {
|
|||||||
BORROW_LENDING_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/borrow',
|
BORROW_LENDING_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/borrow',
|
||||||
COOKIE_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/cookie-policy',
|
COOKIE_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/cookie-policy',
|
||||||
DOCS_URL = 'https://docs.marsprotocol.io/',
|
DOCS_URL = 'https://docs.marsprotocol.io/',
|
||||||
|
FARM_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/farming/farming-intro',
|
||||||
MANAGE_ACCOUNT_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/credit-accounts/credit-accounts-intro',
|
MANAGE_ACCOUNT_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/credit-accounts/credit-accounts-intro',
|
||||||
ROVER_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/credit-accounts',
|
ROVER_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/credit-accounts',
|
||||||
PRIVACY_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/privacy-policy',
|
PRIVACY_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/privacy-policy',
|
||||||
@ -10,4 +11,5 @@ export enum DocURL {
|
|||||||
TRADING_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/trading/trading-intro',
|
TRADING_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/trading/trading-intro',
|
||||||
V1_URL = 'https://v1.marsprotocol.io',
|
V1_URL = 'https://v1.marsprotocol.io',
|
||||||
WALLET_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/basics/connecting-your-wallet',
|
WALLET_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/basics/connecting-your-wallet',
|
||||||
|
X_SHARE_URL = 'https://x.com/intent/tweet',
|
||||||
}
|
}
|
||||||
|
4
src/types/interfaces/components/Tab.d.ts
vendored
Normal file
4
src/types/interfaces/components/Tab.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface Tab {
|
||||||
|
page: Page
|
||||||
|
name: string
|
||||||
|
}
|
10
src/types/interfaces/route.d.ts
vendored
10
src/types/interfaces/route.d.ts
vendored
@ -1 +1,9 @@
|
|||||||
type Page = 'trade' | 'borrow' | 'farm' | 'lend' | 'portfolio' | 'portfolio/{accountId}'
|
type Page =
|
||||||
|
| 'trade'
|
||||||
|
| 'borrow'
|
||||||
|
| 'farm'
|
||||||
|
| 'lend'
|
||||||
|
| 'portfolio'
|
||||||
|
| 'portfolio/{accountId}'
|
||||||
|
| 'hls-farm'
|
||||||
|
| 'hls-staking'
|
||||||
|
@ -22,3 +22,5 @@ export const DEFAULT_PORTFOLIO_STATS = [
|
|||||||
{ title: null, sub: 'APR' },
|
{ title: null, sub: 'APR' },
|
||||||
{ title: null, sub: 'Account Leverage' },
|
{ title: null, sub: 'Account Leverage' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const ENABLE_HLS = false
|
||||||
|
Loading…
Reference in New Issue
Block a user