Compare commits

..
98 changed files with 791 additions and 377 deletions
+1
View File
@@ -1,6 +1,7 @@
{
"name": "mars-v2-frontend",
"version": "2.2.4",
"v1version": "1.7.5",
"homepage": "./",
"private": false,
"license": "SEE LICENSE IN LICENSE FILE",
+63
View File
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
opacity="0.05"
viewBox="0 0 1440 819.8"
>
<path
stroke="#FFF"
d="M-41.5,81c20,17.3,62.5,51.4,71.8,49.5s27.7,13.3,35.6,21.1
c19.3,16.7,58.9,49.8,62.9,48.9c1.2-0.3,5.1-0.3,10.8-0.2c17.4,0.1,51.4,0.4,76.6-8.2c33.4-11.5,50.7-6.6,61.8,0s71.8,37.4,82.4,35
c3.5-0.8,14-0.1,26.7,0.7c25.2,1.7,59.4,3.9,66.8-3.7c11.1-11.5,204.9-19.3,223.3-9.7c14.7,7.7,34.1,7.8,42.7,7.8s28-0.1,42.7-7.8
c18.4-9.7,212.2-1.8,223.3,9.7c7.4,7.6,41.6,5.4,66.8,3.7c12.7-0.8,23.2-1.5,26.7-0.7c10.6,2.4,71.3-28.4,82.4-35
c11.1-6.6,28.4-11.5,61.8,0c25.2,8.6,59.3,8.4,76.6,8.2c5.7,0,9.6-0.1,10.8,0.2c4,1,43.6-32.2,62.9-48.9c8-7.8,26.3-23.1,35.6-21.1
c9.4,1.9,51.8-32.2,71.8-49.5"
/>
<path
stroke="#FFF"
d="M-39.8,340.5c8.1,0.1,15.5,0.1,21.7,0.1
c18.9,0,60.1,10.9,95.2,30.4c2.9,0.7,5.7,1.4,8.3,2c17.6,4.3,28.9,7.1,50.7,7.1l152,3c2.6-0.4,8.9-2.6,13.4-7.9
c4.5-5.3,15.6-14.4,20.6-18.2c3.5-2.2,13.6-6.7,25.6-6.7c9.5,0,21.5,0.7,30.3,1.3c5.1,0.3,9.1,0.6,10.9,0.6c5,0,17.3-3,21.7-7.9
c3.6-3.9,39.4-47,56.8-68c6.1-6.9,22.4-19.3,38.4-14c20,6.7,75.2,6.7,84.1,0c8.9-6.7,29.5-18.2,49.6-14.6c2.2,0.4,4.8,0.9,7.8,1.4
c24.2,4.4,70.3,12.8,72.8,12.8s48.6-8.4,72.8-12.8c3-0.5,5.6-1,7.8-1.4c20-3.6,40.6,7.9,49.6,14.6c8.9,6.7,64,6.7,84.1,0
c16-5.3,32.3,7.1,38.4,14c17.4,21.1,53.2,64.1,56.8,68c4.5,4.9,16.7,7.9,21.7,7.9c1.8,0,5.8-0.2,10.9-0.6c8.8-0.5,20.8-1.3,30.3-1.3
c12,0,22.1,4.5,25.6,6.7c5,3.8,16.1,12.9,20.6,18.2c4.4,5.3,10.8,7.5,13.4,7.9l152-3c21.8,0,33.1-2.8,50.7-7.1
c2.6-0.6,5.4-1.3,8.3-2c35.1-19.4,76.3-30.4,95.2-30.4c6.2,0,13.6-0.1,21.7-0.1"
/>
<path
stroke="#FFF"
d="M-56.4,455c79.7-9.9,188.1-23.3,214.2-34.7
c17-2.8,93.6,6,161.8,13.8c52.2,6,99.5,11.3,111.1,10.5c8.2-0.6,28.2-8.6,55.3-19.5C546.6,400.7,642.6,362,720,362
s173.4,38.7,234.1,63.1c27,10.9,47,19,55.3,19.5c11.6,0.8,58.8-4.6,111.1-10.5c68.1-7.8,144.8-16.5,161.8-13.8
c26.1,11.4,134.5,24.8,214.2,34.7"
/>
<path
stroke="#FFF"
d="M-22.1,455.3c12.3,3,52.3,21.3,64,37.1
c11.7,15.8,33.3,14.7,35.1,12.8c1.7-1.8,16.7-13,24.5-18.2c4.6-2.4,16.8-5.8,28.4,0s79.4,39.7,111.9,55.9c4.3,2.4,13.1,7.3,14.5,7.3
c0.2,0,0.8,0.1,1.6,0.1c4.7,0.4,17.3,1.6,20.7-2.6c3.1-3.9,20.6-17.4,29-23.7c6.1-4,20.9-12.1,31.2-12.1s82.6,4,117.5,6.1
c20.2-0.4,61.8-1.3,66.3-1.8c3.3-0.4,34.5,1.6,60.7,3.3c17.8,1.1,33.4,2.1,36.2,2.1c3.4,0,13.7-7.1,26.7-16.3
c23.1-16.1,55-38.4,73.8-38.4s50.8,22.3,73.8,38.4c13.1,9.1,23.3,16.3,26.7,16.3c2.8,0,18.4-1,36.2-2.1c26.2-1.7,57.4-3.7,60.7-3.3
c4.5,0.5,46,1.4,66.3,1.8c34.9-2,107.2-6.1,117.5-6.1c10.2,0,25.1,8.1,31.2,12.1c8.3,6.3,25.8,19.8,29,23.7c3.3,4.1,16,3,20.7,2.6
c0.8-0.1,1.4-0.1,1.6-0.1c1.3,0,10.2-4.9,14.5-7.3c32.5-16.2,100.3-50.1,111.9-55.9c11.6-5.8,23.8-2.4,28.4,0
c7.8,5.3,22.8,16.4,24.5,18.2c1.8,1.9,23.4,3,35.1-12.8c11.7-15.8,51.8-34,64-37.1"
/>
<path
stroke="#FFF"
d="M-48.7,749.9c4.2,0.6,7.8,1.2,10.5,1.2c3.3,0,5.6-2.4,8-5
c2.8-3,5.8-6.3,10.9-5.9c7.6,0.5,75.5,0.2,108.6,0l11.7,2.4l53.5,35.8l6.1,10.9l34.5,3l35.6,12.8c13,3.4,40.2,10.1,45.1,9.1
c3.1-0.6,12.4-7.5,21.6-14.4c9-6.7,17.9-13.3,21.2-14.2c6.7-1.8,27.3-11.5,30.6-14.6c0.3-0.3,0.7-0.7,1.3-1.2
c5.5-5.3,22.7-21.6,33.8-18.8c5.1,1.3,10,4.1,14.9,6.8c6.9,3.9,13.4,7.6,19.6,6.5c7.1-1.2,29.3-20.4,44.1-33.1
c7.3-6.3,12.8-11,13.8-11.2c2.2-0.5,38.4-39.1,56.2-58.3c5.9-6.3,23.6-14.8,42.3-6.1c18.7,8.7,46,9.1,57.9,9.1l67.9,6.1l18.7-0.1
l18.7,0.1l67.9-6.1c11.9,0,39.2-0.4,57.9-9.1c18.7-8.7,36.4-0.2,42.3,6.1c17.8,19.2,54,57.8,56.2,58.3c0.9,0.2,6.4,4.9,13.8,11.2
c14.8,12.7,37.1,31.9,44.1,33.1c6.2,1.1,12.8-2.7,19.6-6.5c4.8-2.7,9.8-5.6,14.9-6.8c11.1-2.8,28.2,13.6,33.8,18.8
c0.6,0.5,1,0.9,1.3,1.2c3.3,3,23.9,12.8,30.6,14.6c3.3,0.9,12.3,7.5,21.2,14.2c9.2,6.9,18.5,13.7,21.6,14.4c4.9,1,32.1-5.7,45.1-9.1
l35.6-12.8l34.5-3l6.1-10.9l53.5-35.8l11.7-2.4c33,0.2,101,0.5,108.6,0c5.1-0.3,8.1,2.9,10.9,5.9c2.4,2.6,4.7,5,8,5
c2.7,0,6.3-0.5,10.5-1.2"
/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+42
View File
@@ -0,0 +1,42 @@
<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100.881 178.044C144.869 178.044 180.531 142.388 180.531 98.4C180.531 54.4124 144.869 18.75 100.881 18.75C56.8939 18.75 21.2378 54.4124 21.2378 98.4C21.2378 142.388 56.8939 178.044 100.881 178.044Z"
fill="#2E3148"
/>
<path
d="M100.694 143.475C126.106 143.475 146.712 122.869 146.712 97.4562C146.712 72.0437 126.106 51.4375 100.694 51.4375C75.2749 51.4375 54.6748 72.0437 54.6748 97.4562C54.6748 122.869 75.2749 143.475 100.694 143.475Z"
fill="#1B1E36"
/>
<path
d="M200 97.5C200 110.631 197.412 123.631 192.387 135.769C187.362 147.9 179.994 158.925 170.712 168.206C161.425 177.494 150.4 184.862 138.269 189.887C126.137 194.912 113.131 197.5 100 197.5C86.8687 197.5 73.8625 194.912 61.7313 189.887C49.6001 184.862 38.5748 177.494 29.2873 168.206C20.0061 158.925 12.6376 147.9 7.61262 135.769C2.58761 123.631 0 110.631 0 97.5H23.9689C23.9689 107.481 25.9312 117.369 29.7562 126.594C33.5749 135.819 39.1751 144.2 46.2376 151.262C53.3001 158.319 61.6811 163.925 70.9063 167.744C80.1313 171.563 90.0125 173.531 100 173.531C109.988 173.531 119.869 171.563 129.094 167.744C138.319 163.925 146.7 158.319 153.762 151.262C160.825 144.2 166.425 135.819 170.244 126.594C174.069 117.369 176.031 107.481 176.031 97.5H200Z"
fill="#C73238"
/>
<path
d="M178.95 97.5C178.95 107.869 176.906 118.131 172.937 127.712C168.969 137.287 163.156 145.994 155.825 153.325C148.494 160.656 139.794 166.469 130.212 170.438C120.637 174.406 110.369 176.444 99.9998 176.444C89.631 176.444 79.3685 174.406 69.7873 170.438C60.2124 166.469 51.506 160.656 44.1747 153.325C36.8435 145.994 31.0312 137.287 27.0624 127.712C23.0937 118.131 21.0562 107.869 21.0562 97.5H99.9998H178.95Z"
fill="#070B09"
/>
<path
d="M99.2748 28.6934C90.8686 28.6934 84.0498 59.1809 84.0498 96.7934C84.0498 134.406 90.8686 164.893 99.2748 164.893C107.681 164.893 114.5 134.406 114.5 96.7934C114.5 59.1809 107.681 28.6934 99.2748 28.6934ZM100.325 161.05C99.3623 162.331 98.3998 161.368 98.3998 161.368C94.5311 156.887 92.5936 148.55 92.5936 148.55C85.8248 126.762 87.4373 79.9684 87.4373 79.9684C90.6186 42.8247 96.4061 34.0495 98.3748 32.0995C98.5811 31.8995 98.8436 31.7808 99.1248 31.7558C99.4061 31.737 99.6873 31.8121 99.9186 31.9746C102.775 33.9996 105.175 42.4745 105.175 42.4745C112.256 68.7496 111.612 93.4309 111.612 93.4309C112.256 114.9 108.069 138.937 108.069 138.937C104.844 157.2 100.325 161.05 100.325 161.05Z"
fill="white"
/>
<path
d="M158.338 62.9C154.156 55.6063 124.319 64.8687 91.6814 83.5812C59.0376 102.3 36.0126 123.387 40.2001 130.675C44.3814 137.969 74.2189 128.713 106.856 109.994C139.5 91.275 162.525 70.1875 158.338 62.9ZM44.0564 129.675C42.4564 129.475 42.8189 128.156 42.8189 128.156C44.7814 122.569 51.0377 116.744 51.0377 116.744C66.5814 100.025 107.969 78.1375 107.969 78.1375C141.769 62.4126 152.269 63.075 154.931 63.8062C155.206 63.8875 155.444 64.0562 155.6 64.2875C155.763 64.525 155.831 64.8062 155.806 65.0875C155.481 68.5812 149.313 74.8687 149.313 74.8687C130.056 94.1 108.331 105.825 108.331 105.825C90.0252 117.069 67.0939 125.394 67.0939 125.394C49.6437 131.681 44.0564 129.675 44.0564 129.675Z"
fill="white"
/>
<path
d="M158.194 130.919C162.412 123.644 139.45 102.457 106.925 83.6007C74.3998 64.7445 44.5623 55.3695 40.3498 62.657C36.1373 69.9445 59.1 91.1132 91.6436 109.969C124.187 128.832 153.981 138.207 158.194 130.919ZM43.1437 65.4695C42.5249 63.9882 43.8373 63.6382 43.8373 63.6382C49.6623 62.5382 57.8376 65.0382 57.8376 65.0382C80.0873 70.107 119.769 94.9632 119.769 94.9632C150.312 116.338 155 125.751 155.7 128.426C155.775 128.701 155.744 128.988 155.625 129.244C155.5 129.501 155.294 129.707 155.037 129.819C151.85 131.282 143.319 129.107 143.319 129.107C117.025 122.057 95.9936 109.138 95.9936 109.138C77.0998 98.9507 58.4124 83.2695 58.4124 83.2695C44.2187 71.3132 43.1498 65.482 43.1498 65.482L43.1437 65.4695Z"
fill="white"
/>
<path
d="M99.1126 104.63C103.538 104.63 107.125 101.043 107.125 96.618C107.125 92.193 103.538 88.6055 99.1126 88.6055C94.6876 88.6055 91.1001 92.193 91.1001 96.618C91.1001 101.043 94.6876 104.63 99.1126 104.63Z"
fill="white"
/>
<path
d="M131.969 70.6691C134.531 70.6691 136.613 68.5191 136.613 65.8628C136.613 63.2066 134.531 61.0566 131.969 61.0566C129.4 61.0566 127.319 63.2066 127.319 65.8628C127.319 68.5191 129.4 70.6691 131.969 70.6691Z"
fill="white"
/>
<path
d="M55.6873 87.0133C58.2498 87.0133 60.3313 84.857 60.3313 82.207C60.3313 79.5508 58.2498 77.3945 55.6873 77.3945C53.1185 77.3945 51.0376 79.5508 51.0376 82.207C51.0376 84.857 53.1185 87.0133 55.6873 87.0133Z"
fill="white"
/>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

+26
View File
@@ -0,0 +1,26 @@
<svg viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="512" height="512" rx="256" fill="#00A3FF" />
<path
opacity="0.6"
d="M361.012 237.812L363.878 242.209C396.204 291.798 388.984 356.742 346.52 398.348C321.539 422.826 288.798 435.066 256.056 435.069C256.056 435.069 256.056 435.069 361.012 237.812Z"
fill="white"
/>
<path
opacity="0.2"
d="M256.044 297.764L361 237.812C256.045 435.069 256.044 435.069 256.044 435.069C256.044 392.108 256.044 342.88 256.044 297.764Z"
fill="white"
/>
<path
d="M150.988 237.812L148.122 242.209C115.796 291.798 123.016 356.742 165.48 398.348C190.461 422.826 223.202 435.066 255.944 435.069C255.944 435.069 255.944 435.069 150.988 237.812Z"
fill="white"
/>
<path
opacity="0.6"
d="M255.914 297.764L150.958 237.812C255.914 435.069 255.914 435.069 255.914 435.069C255.914 392.108 255.914 342.88 255.914 297.764Z"
fill="white"
/>
<path opacity="0.2" d="M256.083 163.833V267.233L346.491 215.566L256.083 163.833Z" fill="white" />
<path opacity="0.6" d="M256.056 163.833L165.583 215.565L256.056 267.233V163.833Z" fill="white" />
<path d="M256.056 76.875L165.583 215.599L256.056 163.722V76.875Z" fill="white" />
<path opacity="0.6" d="M256.083 163.706L346.56 215.585L256.083 76.7916V163.706Z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

-19
View File
@@ -1,19 +0,0 @@
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs'
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
Sentry.init({
dsn: SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_SENTRY_ENV,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 0.5,
enabled: process.env.NODE_ENV !== 'development',
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})
-4
View File
@@ -1,4 +0,0 @@
defaults.url=https://sentry.io/
defaults.org=delphi-mars
defaults.project=mars-v2
cli.executable=../../../.npm/_npx/a8388072043b4cbc/node_modules/@sentry/cli/bin/sentry-cli
-19
View File
@@ -1,19 +0,0 @@
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs'
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
Sentry.init({
dsn: SENTRY_DSN,
environment: process.env.NEXT_PUBLIC_SENTRY_ENV,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 0.5,
enabled: process.env.NODE_ENV !== 'development',
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})
@@ -15,6 +15,7 @@ interface Props {
color?: ButtonProps['color']
variant?: ButtonProps['variant']
size?: ButtonProps['size']
short?: boolean
}
export default function WalletConnectButton(props: Props) {
@@ -29,7 +29,7 @@ function FetchLoading() {
function Content() {
const address = useStore((s) => s.address)
const [searchParams] = useSearchParams()
const isV1 = useStore((s) => s.isV1)
const { address: urlAddress } = useParams()
const urlAccountId = useAccountId()
const navigate = useNavigate()
@@ -62,7 +62,7 @@ function Content() {
) {
const currentAccountIsHLS = urlAccountId && !accountIds.includes(urlAccountId)
const currentAccount = currentAccountIsHLS || !urlAccountId ? accountIds[0] : urlAccountId
navigate(getRoute(page, searchParams, address, currentAccount))
navigate(getRoute(page, searchParams, address, isV1 ? undefined : currentAccount))
useStore.setState({ balances: walletBalances, focusComponent: null })
}
}, [
@@ -75,11 +75,12 @@ function Content() {
urlAddress,
urlAccountId,
searchParams,
isV1,
])
if (isLoadingAccounts || isLoadingBalances) return <FetchLoading />
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) return <WalletBridges />
if (accountIds && accountIds.length === 0) return <AccountCreateFirst />
if (accountIds && accountIds.length === 0 && !isV1) return <AccountCreateFirst />
return null
}
+1 -1
View File
@@ -13,7 +13,7 @@ export default function Wallet() {
const address = useStore((s) => s.address)
useEffect(() => {
if (address && address === currentWallet?.account.address) return
if (address) return
useStore.setState({
address: undefined,
userDomain: undefined,
@@ -47,7 +47,7 @@ export default function AccountBalancesTable(props: Props) {
const columns = useAccountBalancesColumns(account, showLiquidationPrice)
if (accountBalanceData.length === 0 && account.id !== address)
if (accountBalanceData.length === 0)
return (
<ConditionalWrapper
condition={!hideCard}
@@ -75,6 +75,7 @@ export default function AccountBalancesTable(props: Props) {
},
})
}}
short
/>
</div>
</ConditionalWrapper>
@@ -7,7 +7,7 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight } from 'components/common/Icons'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets'
+14 -17
View File
@@ -12,19 +12,18 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ThreeDots } from 'components/common/Icons'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import { ORACLE_DENOM } from 'constants/oracle'
import useAccount from 'hooks/accounts/useAccount'
import useAccountIds from 'hooks/accounts/useAccountIds'
import useAccounts from 'hooks/accounts/useAccounts'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store'
@@ -34,7 +33,6 @@ import {
calculateAccountBalanceValue,
calculateAccountLeverage,
} from 'utils/accounts'
import { getPage } from 'utils/route'
export default function AccountDetailsController() {
const address = useStore((s) => s.address)
@@ -42,32 +40,28 @@ export default function AccountDetailsController() {
const isV1 = useStore((s) => s.isV1)
const { data: _, isLoading } = useAccounts('default', address)
const { data: accountIds } = useAccountIds(address, false, true)
const accountId = useAccountId()
const currentAccount = useCurrentAccount()
const { data: v1Account } = useAccount(address)
const { pathname } = useLocation()
const page = getPage(pathname)
const account = isV1 && page !== 'trade' ? v1Account : currentAccount
const accountId = useAccountId()
const account = useCurrentAccount()
const focusComponent = useStore((s) => s.focusComponent)
const isOwnAccount = (accountId && accountIds?.includes(accountId)) || account?.id === address
const hideAccountDetails =
!address || focusComponent || !isOwnAccount || isHLS || page.includes('portfolio')
const isOwnAccount = accountId && accountIds?.includes(accountId)
const hideAccountDetails = !address || focusComponent || !isOwnAccount || isHLS || isV1
const isLoadingAccountDetails = (isLoading && accountId && !focusComponent) || !account
if (hideAccountDetails) return null
if (isLoadingAccountDetails) return <Skeleton />
return <AccountDetails account={account} page={page} />
return <AccountDetails account={account} />
}
interface Props {
account: Account
page: Page
}
function AccountDetails(props: Props) {
const { account, page } = props
const { account } = props
const location = useLocation()
const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const [reduceMotion] = useLocalStorage<boolean>(
@@ -132,7 +126,10 @@ function AccountDetails(props: Props) {
vaultAprs,
],
)
const isFullWidth = page === 'trade' || page === 'perps'
const isFullWidth =
location.pathname.includes('trade') ||
location.pathname === '/' ||
location.pathname.includes('perps')
return (
<>
@@ -6,7 +6,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
import Button from 'components/common/Button'
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/common/Icons'
import SwitchAutoLend from 'components/common/Switch/SwitchAutoLend'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useHealthComputer from 'hooks/useHealthComputer'
@@ -42,7 +42,6 @@ export default function AccountSummaryHeader(props: Props) {
updatedHealthFactor,
isAccountDetails,
} = props
const address = useStore((s) => s.address)
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
const accountBalance = useMemo(
() => (account ? calculateAccountBalanceValue(account, prices, assets) : BN_ZERO),
@@ -69,9 +68,10 @@ export default function AccountSummaryHeader(props: Props) {
/>
)}
{isAccountDetails && (
<Text size='sm' className='w-full pb-1 text-white/50'>
{account.id === address ? 'Red Bank' : `Credit Account ${account.id}`}
</Text>
<Text
size='sm'
className='w-full pb-1 text-white/50'
>{`Credit Account ${account.id}`}</Text>
)}
<div className='flex items-end w-full gap-2 pb-2 border-b border-white/5'>
<DisplayCurrency
@@ -7,7 +7,7 @@ import AccountStrategiesTable from 'components/account/AccountStrategiesTable'
import AccountSummaryHeader from 'components/account/AccountSummary/AccountSummaryHeader'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import Accordion from 'components/common/Accordion'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import { BN_ZERO } from 'constants/math'
@@ -13,7 +13,7 @@ type Props = {
}
export default function AvailableBorrowingsTable(props: Props) {
const columns = useAvailableColumns()
const columns = useAvailableColumns({ v1: false })
const renderExpanded = useCallback(
(row: Row<BorrowMarketTableData>, _: TanstackTable<BorrowMarketTableData>) => {
@@ -54,6 +54,7 @@ export default function BorrowButton(props: Props) {
e.stopPropagation()
}}
text='Borrow'
short
/>
</ConditionalWrapper>
</div>
+6 -1
View File
@@ -5,6 +5,7 @@ export const NAME_META = { accessorKey: 'asset.symbol', header: 'Asset', id: 'sy
interface Props {
data: BorrowMarketTableData
v1?: boolean
}
export default function Name(props: Props) {
@@ -12,7 +13,11 @@ export default function Name(props: Props) {
return (
<div className='flex items-center flex-1 gap-3'>
<AssetImage asset={asset} size={32} />
<TitleAndSubCell title={asset.symbol} sub={asset.name} className='text-left min-w-15' />
<TitleAndSubCell
title={asset.symbol}
sub={props.v1 ? '' : asset.name}
className='text-left min-w-15'
/>
</div>
)
}
@@ -24,7 +24,7 @@ export default function useActiveColumns(props: Props) {
return [
{
...NAME_META,
cell: ({ row }) => <Name data={row.original} />,
cell: ({ row }) => <Name data={row.original} v1={props.v1} />,
},
{
...DEBT_VALUE_META,
@@ -10,12 +10,16 @@ import Liquidity, {
} from 'components/borrow/Table/Columns/Liquidity'
import Name, { NAME_META } from 'components/borrow/Table/Columns/Name'
export default function useAvailableColumns() {
interface Props {
v1?: boolean
}
export default function useAvailableColumns(props: Props) {
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
return [
{
...NAME_META,
cell: ({ row }) => <Name data={row.original} />,
cell: ({ row }) => <Name data={row.original} v1={props.v1} />,
},
{
...BORROW_RATE_META,
@@ -35,5 +39,5 @@ export default function useAvailableColumns() {
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
},
]
}, [])
}, [props.v1])
}
+8 -5
View File
@@ -15,27 +15,30 @@ export default function Background() {
)
const { pathname } = useLocation()
const page = getPage(pathname)
const [isHLS] = useMemo(() => [page.split('-')[0] === 'hls'], [page])
const [isHLS, isV1] = useMemo(() => [page.split('-')[0] === 'hls', page === 'v1'], [page])
useEffect(() => {
useStore.setState({ isHLS: isHLS })
}, [isHLS])
useStore.setState({ isHLS: isHLS, isV1: isV1 })
}, [isHLS, isV1])
const [primaryOrbClassName, secondaryOrbClassName, tertiaryOrbClassName, bodyClassName] =
useMemo(() => {
if (isHLS) {
return ['bg-orb-primary-hls', 'bg-orb-secondary-hls', 'bg-orb-tertiary-hls', 'bg-body-hls']
}
if (isV1) {
return ['bg-transparent', 'bg-transparent', 'bg-transparent', 'bg-body bg-v1 blur-[2px]']
}
return ['bg-orb-primary', 'bg-orb-secondary', 'bg-orb-tertiary', 'bg-body']
}, [isHLS])
}, [isHLS, isV1])
return (
<div
className={classNames(
'fixed inset-0',
'w-full h-full',
'overflow-hidden pointer-events-none background ',
'overflow-hidden pointer-events-none background',
bodyClassName,
!reduceMotion && 'transition-bg duration-1000 delay-300',
)}
+10 -4
View File
@@ -9,10 +9,15 @@ import useAccountIds from 'hooks/accounts/useAccountIds'
import useAccountId from 'hooks/useAccountId'
import useStore from 'store'
export default function ActionButton(props: ButtonProps) {
const { className, color, variant, size } = props
interface Props extends ButtonProps {
short?: boolean
}
export default function ActionButton(props: Props) {
const { className, color, variant, size, short } = props
const defaultProps = { className, color, variant, size }
const address = useStore((s) => s.address)
const isV1 = useStore((s) => s.isV1)
const { data: accountIds } = useAccountIds(address || '')
const selectedAccountId = useAccountId()
@@ -21,7 +26,8 @@ export default function ActionButton(props: ButtonProps) {
useStore.setState({ focusComponent: { component: <AccountCreateFirst /> } })
}, [])
if (!address) return <WalletConnectButton {...defaultProps} />
if (!address)
return <WalletConnectButton {...defaultProps} textOverride={short ? 'Connect' : undefined} />
if (accountIds && accountIds.length === 0) {
return (
@@ -34,7 +40,7 @@ export default function ActionButton(props: ButtonProps) {
)
}
if (!selectedAccountId) {
if (!selectedAccountId && !isV1) {
return (
<Button
text='Select Account'
+3 -1
View File
@@ -1,10 +1,12 @@
import { TextLink } from 'components/common/TextLink'
import { DocURL } from 'types/enums/docURL'
import useStore from 'store'
import packageInfo from '../../../package.json'
export default function Footer() {
const version = `v${packageInfo.version}`
const isV1 = useStore((s) => s.isV1)
const version = isV1 ? `v${packageInfo.v1version}` : `v${packageInfo.version}`
const flatVersion = packageInfo.version.split('.').join('')
return (
<footer className='flex items-center justify-center w-full h-6 -mt-6'>
-7
View File
@@ -9,7 +9,6 @@ import {
GridPlanet,
GridTire,
GridWeb,
Wallet,
} from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
@@ -53,12 +52,6 @@ function IntroBackground(props: { bg: Props['bg'] }) {
<GridPlanet />
</div>
)
case 'v1':
return (
<div className='absolute top-0 right-0 block w-80 opacity-5'>
<Wallet />
</div>
)
default:
return (
<div className='absolute bottom-0 right-0 block w-3/4 md:w-120 opacity-5'>
+1 -1
View File
@@ -118,7 +118,7 @@ export default function MarketDetails({ row, type }: Props) {
<TitleAndSubCell
key={index}
className='text-center'
containerClassName='m-5 ml-10 mr-10 space-y-1'
containerClassName='m-5 mx-auto space-y-1'
title={
<FormattedNumber
className='text-xs text-center'
+47
View File
@@ -0,0 +1,47 @@
import Card from 'components/common/Card'
import { Cross, ExclamationMarkCircled } from 'components/common/Icons'
import Text from 'components/common/Text'
import { TextLink } from 'components/common/TextLink'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useStore from 'store'
import { DocURL } from 'types/enums/docURL'
export default function MigrationBanner() {
const [_, setMigrationBanner] = useLocalStorage<boolean>(
LocalStorageKeys.MIGRATION_BANNER,
DEFAULT_SETTINGS.migrationBanner,
)
const showMigrationBanner = useStore((s) => s.migrationBanner)
if (!showMigrationBanner) return null
return (
<Card
className='relative w-full bg-info-bg/20 text-info'
contentClassName='flex w-full gap-2 px-4 py-3 items-center'
>
<div className='flex w-6 h-6 p-1 text-white rounded bg-info'>
<ExclamationMarkCircled />
</div>
<Text className='flex flex-grow' size='sm'>
If you have funds on{' '}
<TextLink
href={DocURL.V1_URL}
externalLink
className='mx-1 text-white no-underline hover:underline'
>
Mars v1,
</TextLink>
please withdraw them and deposit them on Mars v2 to migrate.
</Text>
<div
className='absolute right-0 flex items-center h-full px-4 w-11 opacity-80 hover:cursor-pointer hover:opacity-100'
onClick={() => setMigrationBanner(false)}
>
<Cross className='w-3 h-3' />
</div>
</Card>
)
}
@@ -12,12 +12,11 @@ interface Props {
className?: string
tooltip?: string
disabled?: boolean
placement?: 'top' | 'bottom' | 'left' | 'right'
}
export default function SwitchWithLabel(props: Props) {
return (
<div className={classNames('flex w-full items-center ', props.className)}>
<div className={classNames('flex w-full', props.className)}>
<div className='flex flex-1'>
<Text className='mr-2 text-white/70' size='sm'>
{props.label}
@@ -25,9 +24,8 @@ export default function SwitchWithLabel(props: Props) {
{props.tooltip && (
<Tooltip
type='info'
placement={props.placement ?? 'top'}
content={
<Text size='sm' className='px-2 py-3 max-w-[320px]'>
<Text size='sm' className='px-2 py-3'>
{props.tooltip}
</Text>
}
-65
View File
@@ -1,65 +0,0 @@
import classNames from 'classnames'
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import { useMemo } from 'react'
import SwitchWithLabel from 'components/common/Switch/SwitchWithLabel'
import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig'
import useStore from 'store'
import { getRoute } from 'utils/route'
const underlineClasses =
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
interface Props {
tabs: Tab[]
activeTabIdx: number
showV1Toggle?: boolean
}
export default function Tab(props: Props) {
const accountId = useAccountId()
const { address } = useParams()
const [searchParams] = useSearchParams()
const chainConfig = useChainConfig()
const isV1 = useStore((s) => s.isV1)
const filteredTabs = useMemo(
() =>
props.tabs.map((tab) => (tab.name === 'Farm' && (!chainConfig.farm || isV1) ? null : tab)),
[chainConfig, props.tabs, isV1],
)
return (
<div className='relative flex w-full'>
<div className='flex flex-grow'>
{filteredTabs.map((tab, index) =>
tab ? (
<NavLink
key={tab.page}
to={getRoute(tab.page, searchParams, address, accountId)}
className={classNames(
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
'relative mr-8 text-xl ',
)}
>
{tab.name}
</NavLink>
) : null,
)}
</div>
{props.showV1Toggle && (
<div className='flex items-center w-40 h-full'>
<SwitchWithLabel
name='v1-toggle'
label='Wallet Mode'
value={isV1}
onChange={() => useStore.setState({ isV1: !isV1 })}
tooltip='The Wallet Mode allows you to interact with the Red Bank without the use of a Credit Account. Funds will be deposited and borrowed directly from and to your Wallet. However you will not be able to use the deposited funds for trading or farming.'
placement='bottom'
/>
</div>
)}
</div>
)
}
+1 -1
View File
@@ -66,7 +66,7 @@ export default function Row<T>(props: Props<T>) {
spacingClassName ?? 'px-3 py-4',
type && type !== 'strategies' && isSymbolOrName && 'border-l',
type && type !== 'strategies' && getBorderColor(type, cell.row.original as any),
cell.column.columnDef.meta?.className ?? 'w-min',
cell.column.columnDef.meta?.className,
)}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
-1
View File
@@ -76,7 +76,6 @@ export default function Table<T>(props: Props<T>) {
props.spacingClassName ?? 'px-4 py-3',
header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right',
'w-min',
header.column.columnDef.meta?.className,
)}
>
+1 -1
View File
@@ -38,7 +38,7 @@ export const Tooltip = (props: Props) => {
placement={props.placement ?? 'top'}
render={() => (
<TooltipContent
hideArrow={props.placement === 'bottom' ? true : props.hideArrow}
hideArrow={props.hideArrow}
type={props.type}
content={props.content}
className={props.contentClassName}
+36
View File
@@ -0,0 +1,36 @@
import classNames from 'classnames'
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import useAccountId from 'hooks/useAccountId'
import { getRoute } from 'utils/route'
const underlineClasses =
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
interface Props {
tabs: Tab[]
activeTabIdx: number
}
export default function Tab(props: Props) {
const accountId = useAccountId()
const { address } = useParams()
const [searchParams] = useSearchParams()
return (
<div className='relative w-full'>
{props.tabs.map((tab, index) => (
<NavLink
key={tab.page}
to={getRoute(tab.page, searchParams, address, accountId)}
className={classNames(
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
'relative mr-8 text-xl ',
)}
>
{tab.name}
</NavLink>
))}
</div>
)
}
@@ -1,5 +1,7 @@
import React from 'react'
import useAvailableColumns from 'components/earn/farm/Table/Columns/useAvailableColumns'
import Table from 'components/common/Table'
import useAvailableColumns from 'components/farm/Table/Columns/useAvailableColumns'
type Props = {
data: Vault[]
@@ -34,6 +34,7 @@ export const Deposit = (props: Props) => {
color='tertiary'
text='Deposit'
leftIcon={<Plus />}
short
/>
</div>
)
@@ -1,15 +1,15 @@
import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy'
import { Deposit, DEPOSIT_META } from 'components/farm/Table/Columns/Deposit'
import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
import { Deposit, DEPOSIT_META } from 'components/earn/farm/Table/Columns/Deposit'
import DepositCap, {
DEPOSIT_CAP_META,
depositCapSortingFn,
} from 'components/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
} from 'components/earn/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
interface Props {
isLoading: boolean
@@ -1,16 +1,18 @@
import { ColumnDef, Row } from '@tanstack/react-table'
import { useMemo } from 'react'
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy'
import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
import DepositCap, {
DEPOSIT_CAP_META,
depositCapSortingFn,
} from 'components/farm/Table/Columns/DepositCap'
import Manage, { MANAGE_META } from 'components/farm/Table/Columns/Manage'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
import PositionValue, { POSITION_VALUE_META } from 'components/farm/Table/Columns/PositionValue'
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
} from 'components/earn/farm/Table/Columns/DepositCap'
import Manage, { MANAGE_META } from 'components/earn/farm/Table/Columns/Manage'
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import PositionValue, {
POSITION_VALUE_META,
} from 'components/earn/farm/Table/Columns/PositionValue'
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
interface Props {
isLoading: boolean
@@ -1,5 +1,7 @@
import React from 'react'
import Table from 'components/common/Table'
import useDepositedColumns from 'components/farm/Table/Columns/useDepositedColumns'
import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
type Props = {
data: DepositedVault[]
@@ -1,8 +1,8 @@
import { Suspense, useMemo } from 'react'
import AvailableVaultsTable from 'components/farm/Table/AvailableVaultsTable'
import DepositedVaultsTable from 'components/farm/Table/DepositedVaultsTable'
import VaultUnlockBanner from 'components/farm/VaultUnlockBanner'
import AvailableVaultsTable from 'components/earn/farm/Table/AvailableVaultsTable'
import DepositedVaultsTable from 'components/earn/farm/Table/DepositedVaultsTable'
import VaultUnlockBanner from 'components/earn/farm/VaultUnlockBanner'
import { BN_ZERO } from 'constants/math'
import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig'
@@ -1,6 +1,6 @@
import AvailableLendsTable from 'components/lend/Table/AvailableLendsTable'
import DepositedLendsTable from 'components/lend/Table/DepositedLendsTable'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import AvailableLendsTable from 'components/earn/lend/Table/AvailableLendsTable'
import DepositedLendsTable from 'components/earn/lend/Table/DepositedLendsTable'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO } from 'constants/math'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
@@ -3,8 +3,8 @@ import { useCallback } from 'react'
import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table'
import { NAME_META } from 'components/lend/Table/Columns/Name'
import useAvailableColumns from 'components/lend/Table/Columns/useAvailableColumns'
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
type Props = {
data: LendingMarketTableData[]
@@ -1,7 +1,7 @@
import AssetRate from 'components/common/assets/AssetRate'
import Loading from 'components/common/Loading'
export const APY_META = { accessorKey: 'apy.deposit', header: 'APY', meta: { className: 'w-40' } }
export const APY_META = { accessorKey: 'apy.deposit', header: 'APY' }
interface Props {
apy: number
@@ -10,6 +10,9 @@ export const DEPOSIT_CAP_META = {
accessorKey: 'marketDepositCap',
header: 'Deposit Cap',
id: 'marketDepositCap',
meta: {
className: 'w-50',
},
}
export const marketDepositCapSortingFn = (
@@ -13,6 +13,9 @@ export const LEND_BUTTON_META = {
accessorKey: 'lend',
enableSorting: false,
header: '',
meta: {
className: 'w-40',
},
}
interface Props {
@@ -53,6 +56,7 @@ export default function LendButton(props: Props) {
e.stopPropagation()
}}
text='Lend'
short
/>
</ConditionalWrapper>
</div>
@@ -13,6 +13,9 @@ export const MANAGE_META = {
accessorKey: 'manage',
enableSorting: false,
header: '',
meta: {
className: 'w-40',
},
}
interface Props {
@@ -75,7 +78,7 @@ export default function Manage(props: Props) {
if (!address) return null
return (
<div className='flex justify-end z-10'>
<div className='z-10 flex justify-end'>
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div>
)
@@ -4,13 +4,18 @@ import TitleAndSubCell from 'components/common/TitleAndSubCell'
export const NAME_META = { accessorKey: 'asset.symbol', header: 'Asset', id: 'symbol' }
interface Props {
asset: Asset
v1?: boolean
}
export default function Name(props: Props) {
const { asset } = props
return (
<div className='flex items-center flex-1 gap-3'>
<AssetImage asset={asset} size={32} />
<TitleAndSubCell title={asset.symbol} sub={asset.name} className='text-left min-w-15' />
<TitleAndSubCell
title={asset.symbol}
sub={props.v1 ? '' : asset.name}
className='text-left min-w-15'
/>
</div>
)
}
@@ -1,17 +1,18 @@
import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
import DepositCap, {
DEPOSIT_CAP_META,
marketDepositCapSortingFn,
} from 'components/lend/Table/Columns/DepositCap'
import LendButton, { LEND_BUTTON_META } from 'components/lend/Table/Columns/LendButton'
import Name, { NAME_META } from 'components/lend/Table/Columns/Name'
} from 'components/earn/lend/Table/Columns/DepositCap'
import LendButton, { LEND_BUTTON_META } from 'components/earn/lend/Table/Columns/LendButton'
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
interface Props {
isLoading: boolean
v1?: boolean
}
export default function useAvailableColumns(props: Props) {
@@ -19,7 +20,7 @@ export default function useAvailableColumns(props: Props) {
return [
{
...NAME_META,
cell: ({ row }) => <Name asset={row.original.asset} />,
cell: ({ row }) => <Name asset={row.original.asset} v1={props.v1} />,
},
{
...APY_META,
@@ -45,5 +46,5 @@ export default function useAvailableColumns(props: Props) {
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
},
]
}, [props.isLoading])
}, [props.isLoading, props.v1])
}
@@ -1,18 +1,18 @@
import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
import DepositCap, {
DEPOSIT_CAP_META,
marketDepositCapSortingFn,
} from 'components/lend/Table/Columns/DepositCap'
} from 'components/earn/lend/Table/Columns/DepositCap'
import DepositValue, {
DEPOSIT_VALUE_META,
depositedSortingFn,
} from 'components/lend/Table/Columns/DepositValue'
import Manage, { MANAGE_META } from 'components/lend/Table/Columns/Manage'
import Name, { NAME_META } from 'components/lend/Table/Columns/Name'
} from 'components/earn/lend/Table/Columns/DepositValue'
import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage'
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import Action from 'components/v1/Table/deposits/Columns/Action'
interface Props {
@@ -25,7 +25,7 @@ export default function useDepositedColumns(props: Props) {
return [
{
...NAME_META,
cell: ({ row }) => <Name asset={row.original.asset} />,
cell: ({ row }) => <Name asset={row.original.asset} v1={props.v1} />,
},
{
...DEPOSIT_VALUE_META,
@@ -3,9 +3,9 @@ import { useCallback } from 'react'
import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table'
import { DEPOSIT_VALUE_META } from 'components/lend/Table/Columns/DepositValue'
import { NAME_META } from 'components/lend/Table/Columns/Name'
import useDepositedColumns from 'components/lend/Table/Columns/useDepositedColumns'
import { DEPOSIT_VALUE_META } from 'components/earn/lend/Table/Columns/DepositValue'
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
type Props = {
data: LendingMarketTableData[]
+125 -66
View File
@@ -1,11 +1,12 @@
import classNames from 'classnames'
import { useCallback, useMemo } from 'react'
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom'
import React, { useCallback, useMemo } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { useSWRConfig } from 'swr'
import Button from 'components/common/Button'
import { ExternalLink } from 'components/common/Icons'
import Overlay from 'components/common/Overlay'
import Radio from 'components/common/Radio'
import Text from 'components/common/Text'
import ChainLogo from 'components/common/chain/ChainLogo'
import chains from 'configs/chains'
@@ -15,11 +16,52 @@ import useToggle from 'hooks/useToggle'
import useStore from 'store'
import { NETWORK } from 'types/enums/network'
import { ChainInfoID } from 'types/enums/wallet'
import { getPage, getRoute } from 'utils/route'
import { getRoute } from 'utils/route'
const v1Outposts = [
{ chainId: ChainInfoID.Neutron1, name: 'Neutron', url: 'https://neutron.marsprotocol.io' },
{ chainId: ChainInfoID.Osmosis1, name: 'Osmosis', url: 'https://v1.marsprotocol.io' },
interface V1Outpost {
chainId: ChainInfoID
name: string
url: string
network: NETWORK.MAINNET | NETWORK.TESTNET
target: '_blank' | '_self'
}
interface ChainOptionProps {
chainConfig?: ChainConfig
onSelect?: (chain: ChainConfig) => void
active: boolean
outpost?: V1Outpost
}
const v1Outposts: V1Outpost[] = [
{
chainId: ChainInfoID.Neutron1,
name: 'Neutron',
url: 'https://neutron.marsprotocol.io',
network: NETWORK.MAINNET,
target: '_blank',
},
{
chainId: ChainInfoID.Pion1,
name: 'Neutron Testnet',
url: '/v1',
network: NETWORK.TESTNET,
target: '_self',
},
{
chainId: ChainInfoID.Osmosis1,
name: 'Osmosis',
url: '/v1',
network: NETWORK.MAINNET,
target: '_self',
},
{
chainId: ChainInfoID.OsmosisDevnet,
name: 'Osmosis Devnet',
network: NETWORK.TESTNET,
url: '/v1',
target: '_self',
},
]
export default function ChainSelect() {
@@ -27,8 +69,8 @@ export default function ChainSelect() {
const chainConfig = useChainConfig()
const { mutate } = useSWRConfig()
const navigate = useNavigate()
const { pathname } = useLocation()
const [searchParams] = useSearchParams()
const isV1 = useStore((s) => s.isV1)
const [_, setCurrentChainId] = useCurrentChainId()
@@ -39,20 +81,65 @@ export default function ChainSelect() {
mutate(() => true)
useStore.setState({
chainConfig,
isV1: false,
client: undefined,
address: undefined,
userDomain: undefined,
balances: [],
})
navigate(getRoute(getPage(pathname), searchParams))
navigate(getRoute('trade', searchParams))
},
[setCurrentChainId, setShowMenu, mutate, navigate, pathname, searchParams],
[setCurrentChainId, setShowMenu, mutate, navigate, searchParams],
)
const currentChains = useMemo(() => {
const currentNetworkType = process.env.NEXT_PUBLIC_NETWORK ?? NETWORK.TESTNET
const ChainOption = (props: ChainOptionProps) => {
const { onSelect, active, outpost, chainConfig } = props
return (
<div
className={classNames(
'w-full px-4 py-3 flex gap-3 group/chain text-white items-center',
active ? 'pointer-events-none' : 'opacity-60 hover:opacity-100',
)}
role='button'
onClick={
onSelect && chainConfig
? () => onSelect(chainConfig)
: () => {
if (chainConfig) {
setCurrentChainId(chainConfig.id)
useStore.setState({
chainConfig,
})
}
window.open(outpost?.url, outpost?.target)
}
}
>
<Radio active={active} className='group-hover/account:opacity-100' />
<Text size='sm'>{outpost ? 'v1' : 'v2'} Outpost</Text>
{outpost && outpost.target !== '_self' && <ExternalLink className='inline w-4 -mb-0.5' />}
</div>
)
}
return Object.entries(chains).filter(([_, chain]) => chain.network === currentNetworkType)
const availableChains = useMemo(() => {
const currentNetworkType = process.env.NEXT_PUBLIC_NETWORK ?? NETWORK.TESTNET
const availableChains: { chainId: ChainInfoID; name: string }[] = []
Object.entries(chains).forEach(([chainId, chainConfig]) => {
if (chainConfig.network !== currentNetworkType) return
availableChains.push({ chainId: chainId as ChainInfoID, name: chainConfig.name })
})
if (currentNetworkType === NETWORK.TESTNET) return availableChains
v1Outposts.forEach((v1Outpost) => {
if (
!availableChains.find((chain) => chain.chainId === v1Outpost.chainId) &&
v1Outpost.network === currentNetworkType
)
availableChains.push({ chainId: v1Outpost.chainId, name: v1Outpost.name })
})
return availableChains
}, [])
return (
@@ -63,65 +150,37 @@ export default function ChainSelect() {
color='secondary'
onClick={() => setShowMenu()}
className={classNames('!p-0 w-8 flex items-center justify-center')}
></Button>
<Overlay show={showMenu} setShow={setShowMenu} className='right-0 w-[180px] mt-2'>
<div
className={classNames(
'flex w-full items-center bg-white/5 px-4 py-3',
'border border-transparent border-b-white/10',
)}
>
<Text size='lg' className='font-bold'>
Select Chain
</Text>
</div>
<ul className='w-full px-4 py-3 list-none'>
{currentChains.map(([name, chain]) => (
<li
className={classNames(
'w-full py-2 flex gap-3 group/chain text-white items-center',
chainConfig.name === chain.name
? 'pointer-events-none'
: 'opacity-60 hover:opacity-100',
)}
role='button'
key={name}
onClick={() => selectChain(chain)}
>
<ChainLogo chainID={chain.id} className='w-6' />
<Text size='sm'>{chain.name}</Text>
</li>
))}
</ul>
{process.env.NEXT_PUBLIC_NETWORK === NETWORK.MAINNET && (
<>
/>
<Overlay
show={showMenu}
setShow={setShowMenu}
className='right-0 w-[200px] mt-2 overflow-hidden'
>
{availableChains.map((chain, index) => (
<React.Fragment key={chain.chainId}>
<div
className={classNames(
'flex w-full items-center bg-white/5 px-4 py-3',
'border border-transparent border-y-white/10',
'flex items-center gap-2 px-4 py-3 border-b bg-white/10 border-white/20',
index > 0 && 'border-t',
)}
>
<Text size='lg' className='font-bold'>
V1 Outposts
</Text>
<ChainLogo chainID={chain.chainId} className='w-5' />
<Text>{chain.name}</Text>
</div>
<ul className='w-full px-4 py-3 list-none'>
{v1Outposts.map((outpost) => (
<li
className='flex items-center w-full gap-3 py-2 text-white group/chain opacity-60 hover:opacity-100'
role='button'
onClick={() => window.open(outpost.url, '_blank')}
key={outpost.name}
>
<ChainLogo chainID={outpost.chainId} className='w-6' />
<Text size='sm'>
{outpost.name} <ExternalLink className='w-4 ml-1 mb-0.5 inline' />
</Text>
</li>
))}
</ul>
</>
)}
{!!chains[chain.chainId] && (
<ChainOption
chainConfig={chains[chain.chainId]}
onSelect={() => selectChain(chains[chain.chainId])}
active={chainConfig.name === chain.name && !isV1}
/>
)}
<ChainOption
chainConfig={chains[chain.chainId]}
outpost={v1Outposts.find((outpost) => outpost.chainId === chain.chainId)}
active={chainConfig.name === chain.name && isV1}
/>
</React.Fragment>
))}
</Overlay>
</div>
)
+4 -3
View File
@@ -16,7 +16,7 @@ import useStore from 'store'
import { WalletID } from 'types/enums/wallet'
import { getGovernanceUrl } from 'utils/helpers'
export const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTreeEntry[] => [
const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTreeEntry[] => [
{
pages: ['trade', 'trade-advanced'],
label: 'Trade',
@@ -36,7 +36,8 @@ export const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTree
],
},
...(chainConfig.perps ? [{ pages: ['perps'] as Page[], label: 'Perps' }] : []),
{ pages: chainConfig.farm ? ['lend', 'farm', 'borrow'] : ['lend'], label: 'Lend & Borrow' },
{ pages: chainConfig.farm ? ['lend', 'farm'] : ['lend'], label: 'Earn' },
{ pages: ['borrow'], label: 'Borrow' },
...(chainConfig.hls ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []),
{ pages: ['portfolio'], label: 'Portfolio' },
{ pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) },
@@ -72,7 +73,7 @@ export default function DesktopHeader() {
focusComponent ? 'relative isolate' : 'border-b border-white/20',
)}
>
<DesktopNavigation />
<DesktopNavigation menuTree={menuTree} />
{focusComponent ? (
<div className='flex justify-between w-full'>
+81
View File
@@ -0,0 +1,81 @@
import classNames from 'classnames'
import { useMemo } from 'react'
import { isDesktop } from 'react-device-detect'
import Wallet from 'components/Wallet'
import EscButton from 'components/common/Button/EscButton'
import Settings from 'components/common/Settings'
import ChainSelect from 'components/header/ChainSelect'
import OracleResyncButton from 'components/header/OracleResyncButton'
import RewardsCenter from 'components/header/RewardsCenter'
import DesktopNavigation from 'components/header/navigation/DesktopNavigation'
import useAccountId from 'hooks/useAccountId'
import useStore from 'store'
import { WalletID } from 'types/enums/wallet'
import { getGovernanceUrl } from 'utils/helpers'
const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTreeEntry[] => [
{
pages: ['v1'],
label: 'Red Bank',
},
{ pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) },
]
export default function DesktopHeader() {
const address = useStore((s) => s.address)
const focusComponent = useStore((s) => s.focusComponent)
const isOracleStale = useStore((s) => s.isOracleStale)
const accountId = useAccountId()
function handleCloseFocusMode() {
if (focusComponent && focusComponent.onClose) focusComponent.onClose()
useStore.setState({ focusComponent: null })
}
const showStaleOracle = useMemo(() => isOracleStale && address, [isOracleStale, address])
if (!isDesktop) return null
return (
<header
className={classNames(
'fixed left-0 top-0 z-50 w-full',
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:h-full before:w-full before:rounded-sm before:backdrop-blur-sticky',
)}
>
<div
className={classNames(
'flex items-center justify-between px-4 py-4',
focusComponent ? 'relative isolate' : 'border-b border-white/20',
)}
>
<DesktopNavigation menuTree={menuTree} />
{focusComponent ? (
<div className='flex justify-between w-full'>
<div className='flex h-5 w-13' />
{address && (
<div className='flex gap-4'>
<Wallet />
<ChainSelect />
</div>
)}
<div className='flex gap-4'>
{!address && <ChainSelect />}
<EscButton onClick={handleCloseFocusMode} />
</div>
</div>
) : (
<div className='flex gap-4'>
{showStaleOracle && <OracleResyncButton />}
{accountId && <RewardsCenter />}
<Wallet />
<ChainSelect />
<Settings />
</div>
)}
</div>
</header>
)
}
@@ -4,7 +4,6 @@ import { useMemo } from 'react'
import Button from 'components/common/Button'
import { ChevronDown, Logo } from 'components/common/Icons'
import { menuTree } from 'components/header/DesktopHeader'
import { NavLink } from 'components/header/navigation/NavLink'
import { NavMenu } from 'components/header/navigation/NavMenu'
import useChainConfig from 'hooks/useChainConfig'
@@ -12,19 +11,24 @@ import useToggle from 'hooks/useToggle'
import useStore from 'store'
import { WalletID } from 'types/enums/wallet'
interface Props {
menuTree: (walletId: WalletID, chainConfig: ChainConfig) => MenuTreeEntry[]
}
export function getIsActive(pages: string[]) {
const segments = location.pathname.split('/')
return pages.some((page) => segments.includes(page))
}
export default function DesktopNavigation() {
export default function DesktopNavigation(props: Props) {
const { menuTree } = props
const [showMenu, setShowMenu] = useToggle()
const { recentWallet } = useShuttle()
const chainConfig = useChainConfig()
const walletId = (recentWallet?.providerId as WalletID) ?? WalletID.Keplr
const focusComponent = useStore((s) => s.focusComponent)
const menu = useMemo(() => menuTree(walletId, chainConfig), [walletId, chainConfig])
const menu = useMemo(() => menuTree(walletId, chainConfig), [walletId, chainConfig, menuTree])
return (
<div
+5 -4
View File
@@ -12,12 +12,11 @@ import PerpsPage from 'pages/PerpsPage'
import PortfolioAccountPage from 'pages/PortfolioAccountPage'
import PortfolioPage from 'pages/PortfolioPage'
import TradePage from 'pages/TradePage'
import V1Page from 'pages/V1Page'
import Layout from 'pages/_layout'
import useStore from 'store'
export default function Routes() {
const chainConfig = useChainConfig()
const isV1 = useStore((s) => s.isV1)
return (
<RoutesWrapper>
<Route
@@ -30,10 +29,11 @@ export default function Routes() {
<Route path='/trade' element={<TradePage />} />
<Route path='/trade-advanced' element={<TradePage />} />
{chainConfig.perps && <Route path='/perps' element={<PerpsPage />} />}
{chainConfig.farm && !isV1 && <Route path='/farm' element={<FarmPage />} />}
{chainConfig.farm && <Route path='/farm' element={<FarmPage />} />}
<Route path='/lend' element={<LendPage />} />
<Route path='/borrow' element={<BorrowPage />} />
<Route path='/portfolio' element={<PortfolioPage />} />
<Route path='/v1' element={<V1Page />} />
<Route path='/mobile' element={<MobilePage />} />
{chainConfig.hls && <Route path='/hls-staking' element={<HLSStakingPage />} />}
{chainConfig.hls && <Route path='/hls-farm' element={<HLSFarmPage />} />}
@@ -43,12 +43,13 @@ export default function Routes() {
<Route path='trade' element={<TradePage />} />
<Route path='trade-advanced' element={<TradePage />} />
{chainConfig.perps && <Route path='perps' element={<PerpsPage />} />}
{chainConfig.farm && !isV1 && <Route path='farm' element={<FarmPage />} />}
{chainConfig.farm && <Route path='farm' element={<FarmPage />} />}
<Route path='lend' element={<LendPage />} />
<Route path='borrow' element={<BorrowPage />} />
<Route path='portfolio' element={<PortfolioPage />} />
{chainConfig.hls && <Route path='hls-staking' element={<HLSStakingPage />} />}
{chainConfig.hls && <Route path='hls-farm' element={<HLSFarmPage />} />}
<Route path='v1' element={<V1Page />} />
<Route path='portfolio/:accountId'>
<Route path='' element={<PortfolioAccountPage />} />
</Route>
@@ -1,10 +1,10 @@
import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import React, { useMemo } from 'react'
import DepositCap, { DEPOSIT_CAP_META } from 'components/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
import DepositCap, { DEPOSIT_CAP_META } from 'components/earn/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
import Apy, { APY_META } from 'components/hls/Farm/Table/Columns/APY'
import Deposit, { DEPOSIT_META } from 'components/hls/Farm/Table/Columns/Deposit'
import MaxLeverage, { MAX_LEV_META } from 'components/hls/Farm/Table/Columns/MaxLeverage'
@@ -5,7 +5,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
import Card from 'components/common/Card'
import TableSkeleton from 'components/common/Table/TableSkeleton'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount'
interface Props {
+5 -17
View File
@@ -3,7 +3,7 @@ import { Suspense, useMemo } from 'react'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
@@ -46,25 +46,15 @@ function Content(props: Props) {
return [
{
title: (
<DisplayCurrency
className='text-xl'
coin={positionValue}
options={{ abbreviated: false }}
/>
),
title: <DisplayCurrency className='text-xl' coin={positionValue} />,
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
},
{
title: (
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
),
title: <DisplayCurrency className='text-xl' coin={debts} />,
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
},
{
title: (
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
),
title: <DisplayCurrency className='text-xl' coin={netWorth} />,
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
},
{
@@ -94,14 +84,12 @@ function Content(props: Props) {
]
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, props.v1])
if (props.v1 && account?.lends.length == 0) return null
return (
<Skeleton
stats={stats}
health={health}
healthFactor={healthFactor}
title={props.v1 ? 'Wallet Mode Portfolio' : `Credit Account ${props.accountId}`}
title={props.v1 ? 'V1 Portfolio' : `Credit Account ${props.accountId}`}
accountId={props.accountId}
/>
)
+1 -1
View File
@@ -5,7 +5,7 @@ import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/Card/Skeleton'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
+5 -19
View File
@@ -4,10 +4,9 @@ import { useParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import SummarySkeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
import useAccounts from 'hooks/accounts/useAccounts'
import useAllAssets from 'hooks/assets/useAllAssets'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
@@ -28,11 +27,8 @@ export default function PortfolioSummary() {
const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const assets = useAllAssets()
const { data: v1Account } = useAccount(urlAddress)
const stats = useMemo(() => {
if (!accounts?.length) return
if (v1Account && !accounts.find((account) => account.id === urlAddress))
accounts.push(v1Account)
const combinedAccount = accounts.reduce(
(combinedAccount, account) => {
combinedAccount.debts = combinedAccount.debts.concat(account.debts)
@@ -64,25 +60,15 @@ export default function PortfolioSummary() {
return [
{
title: (
<DisplayCurrency
className='text-xl'
coin={positionValue}
options={{ abbreviated: false }}
/>
),
title: <DisplayCurrency className='text-xl' coin={positionValue} />,
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
},
{
title: (
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
),
title: <DisplayCurrency className='text-xl' coin={debts} />,
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
},
{
title: (
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
),
title: <DisplayCurrency className='text-xl' coin={netWorth} />,
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
},
{
@@ -110,7 +96,7 @@ export default function PortfolioSummary() {
sub: 'Combined leverage',
},
]
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, v1Account])
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
if (!walletAddress && !urlAddress) return null
+1 -1
View File
@@ -2,7 +2,7 @@ import { useMemo } from 'react'
import AccountBalancesTable from 'components/account/AccountBalancesTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
export default function AccountDetailsCard() {
+1 -1
View File
@@ -1,4 +1,4 @@
import DepositsTable from 'components/lend/Table/DepositedLendsTable'
import DepositsTable from 'components/earn/lend/Table/DepositedLendsTable'
import useV1DepositsTableData from 'components/v1/Table/useV1DepositsTableData'
import { BN_ZERO } from 'constants/math'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
@@ -43,6 +43,7 @@ export default function BorrowButton(props: Props) {
e.stopPropagation()
}}
text='Borrow'
short
/>
</ConditionalWrapper>
</div>
@@ -43,6 +43,7 @@ export default function DepositButton(props: Props) {
e.stopPropagation()
}}
text='Deposit'
short
/>
</ConditionalWrapper>
</div>
+6 -3
View File
@@ -8,9 +8,12 @@ export default function V1Intro() {
<Intro
text={
<>
The <span className='text-white'>Wallet Mode</span> provides simple lending and borrowing
without the use of Credit Accounts. Deposits{' '}
<span className='text-white'>can&lsquo;t be used</span> in the Trade or Farm interface.
<span className='text-white'>Welcome to the Red Bank!</span>
<br />
This is the first version (v1) of the Red Bank. It provides simple lending and borrowing,
without the use of Credit Accounts.
<br />
Deposited funds can&lsquo;t be used on v2 as collateral.
</>
}
bg='v1'
+16
View File
@@ -0,0 +1,16 @@
const stkATOM: AssetMetaData = {
symbol: 'stkATOM',
name: 'Persistence Staked Atom',
id: 'stkATOM',
color: '#c73238',
logo: '/images/tokens/stkatom.svg',
decimals: 6,
hasOraclePrice: true,
isEnabled: true,
isMarket: true,
isDisplayCurrency: true,
isAutoLendEnabled: false,
isStaking: true,
}
export default stkATOM
+18
View File
@@ -0,0 +1,18 @@
const wstETH: AssetMetaData = {
symbol: 'wstETH',
id: 'wstETH',
name: 'Lido Wrapped Staked Ethereum',
color: '#00a3ff',
logo: '/images/tokens/wsteth.svg',
decimals: 18,
hasOraclePrice: true,
isEnabled: true,
isMarket: true,
isDisplayCurrency: true,
isAutoLendEnabled: true,
isBorrowEnabled: true,
pythPriceFeedId: '0x6df640f3b8963d8f8358f791f352b8364513f6ab1cca5ed3f1f7b5448980e784',
pythFeedName: 'WSTETHUSD',
}
export default wstETH
+86
View File
@@ -0,0 +1,86 @@
import { Bech32Address } from '@keplr-wallet/cosmos'
import ATOM from 'configs/assets/ATOM'
import DYDX from 'configs/assets/DYDX'
import NTRN from 'configs/assets/NTRN'
import USDCaxl from 'configs/assets/USDC.axl'
import USDollar from 'configs/assets/USDollar'
import WETHaxl from 'configs/assets/WETH.axl'
import stATOM from 'configs/assets/stATOM'
import stkATOM from 'configs/assets/stkATOM'
import wstETH from 'configs/assets/wstETH'
import { NETWORK } from 'types/enums/network'
import { ChainInfoID } from 'types/enums/wallet'
const Neutron1: ChainConfig = {
assets: [
{ ...NTRN, denom: 'untrn' },
{ ...USDCaxl, denom: 'ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349' },
{
...ATOM,
denom: 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9',
},
{
...stATOM,
denom: 'ibc/B7864B03E1B9FD4F049243E92ABD691586F682137037A9F3FCA5222815620B3C',
},
{
...stkATOM,
denom: 'ibc/3649CE0C8A2C79048D8C6F31FF18FA69C9BC7EB193512E0BD03B733011290445',
},
{ ...WETHaxl, denom: 'ibc/A585C2D15DCD3B010849B453A2CFCB5E213208A5AB665691792684C26274304D' },
{
...wstETH,
denom: 'factory/neutron1ug740qrkquxzrk2hh29qrlx3sktkfml3je7juusc2te7xmvsscns0n2wry/wstETH',
},
{ ...DYDX, denom: 'ibc/2CB87BCE0937B1D1DFCEE79BE4501AAF3C265E923509AEAC410AD85D27F35130' },
USDollar,
],
id: ChainInfoID.Neutron1,
name: 'Neutron',
contracts: {
redBank: 'neutron1n97wnm7q6d2hrcna3rqlnyqw2we6k0l8uqvmyqq6gsml92epdu7quugyph',
incentives: 'neutron1aszpdh35zsaz0yj80mz7f5dtl9zq5jfl8hgm094y0j0vsychfekqxhzd39',
oracle: 'neutron1dwp6m7pdrz6rnhdyrx5ha0acsduydqcpzkylvfgspsz60pj2agxqaqrr7g',
swapper: 'neutron1udr9fc3kd743dezrj38v2ac74pxxr6qsx4xt4nfpcfczgw52rvyqyjp5au',
params: 'neutron16kqg3hr2qc36gz2wqvdzsctatkmzd3ss5gc07tnj6u3n5ajw89asrx8hfp',
creditManager: 'neutron1kj50g96c86nu7jmy5y7uy5cyjanntgru0eekmwz2qcmyyvx6383s8dgvm6',
accountNft: 'neutron17wvpxdc3k37054ume0ga4r0r6ra2rpfe622m0ecgd9s7xd5s0qusspc4ct',
perps: 'neutron14v9g7regs90qvful7djcajsvrfep5pg9qau7qm6wya6c2lzcpnms692dlt',
pyth: 'neutron1m2emc93m9gpwgsrsf2vylv9xvgqh654630v7dfrhrkmr5slly53spg85wv',
},
endpoints: {
routes: 'https://app.astroport.fi/api/routes',
rpc: process.env.NEXT_PUBLIC_NEUTRON_RPC ?? 'https://rpc-kralum.neutron-1.neutron.org',
rest: process.env.NEXT_PUBLIC_NEUTRON_REST ?? 'https://rest-kralum.neutron-1.neutron.org',
swap: 'https://neutron.astroport.fi/swap',
pools: '', //TODO: ⛓️ Implement this
explorer: 'https://mintscan.io/neutron',
aprs: {
vaults: 'https://api.marsprotocol.io/v1/vaults/neutron',
stride: 'https://edge.stride.zone/api/stake-stats',
},
},
network: NETWORK.MAINNET,
vaults: [],
explorerName: 'Mintscan',
bech32Config: Bech32Address.defaultBech32Config('neutron'),
defaultCurrency: {
coinDenom: 'NTRN',
coinMinimalDenom: 'untrn',
coinDecimals: 6,
coinGeckoId: 'neutron',
gasPriceStep: {
low: 0,
average: 0.025,
high: 0.04,
},
},
features: ['ibc-transfer', 'ibc-go'],
gasPrice: '0.025untrn',
hls: false,
perps: false,
farm: false,
}
export default Neutron1
+1 -1
View File
@@ -13,7 +13,7 @@ import USDCaxl from 'configs/assets/USDC.axl'
import USDT from 'configs/assets/USDT'
import USDollar from 'configs/assets/USDollar'
import WBTCaxl from 'configs/assets/WBTC.axl'
import WETHaxl from 'configs/assets/WETH.xal'
import WETHaxl from 'configs/assets/WETH.axl'
import OSMO_ATOM from 'configs/assets/lp/OSMO-ATOM'
import OSMO_USDC from 'configs/assets/lp/OSMO_USDC'
import OSMO_WBTC from 'configs/assets/lp/OSMO_WBTC'
+5
View File
@@ -47,6 +47,11 @@ const PAGE_METADATA = {
'Stake MARS token to ascend to the Martian Council and help govern key changes to the protocol.',
keywords: 'martian council, mars governance, cosmos governance, mars voting, mars staking',
},
v1: {
title: 'Mars Protocol V1',
description: "Lend, borrow and earn on the galaxy's most powerful credit protocol.",
keywords: 'martian council, mars governance, cosmos governance, mars voting, mars staking',
},
}
export default PAGE_METADATA
+1 -2
View File
@@ -1,6 +1,5 @@
export const LEND_AND_BORROW_TABS: Tab[] = [
export const EARN_TABS: Tab[] = [
{ page: 'lend', name: 'Lend' },
{ page: 'borrow', name: 'Borrow' },
{ page: 'farm', name: 'Farm' },
]
+1 -1
View File
@@ -15,7 +15,7 @@ export const WALLETS: WalletInfos = {
walletConnect: 'Cosmostation WalletConnect',
imageURL: '/images/wallets/cosmostation.png',
mobileImageURL: '/images/wallets/cosmostation-wc.png',
supportedChains: [ChainInfoID.Osmosis1, ChainInfoID.OsmosisDevnet],
supportedChains: [ChainInfoID.Osmosis1, ChainInfoID.OsmosisDevnet, ChainInfoID.Pion1],
},
[WalletID.Keplr]: {
name: 'Keplr Wallet',
-1
View File
@@ -20,7 +20,6 @@ export default function useClients() {
`chains/${chainConfig.id}/clients`,
async () => {
const client = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
return {
creditManager: new MarsCreditManagerQueryClient(
client,
+3 -11
View File
@@ -1,19 +1,11 @@
import BorrowIntro from 'components/borrow/BorrowIntro'
import Borrowings from 'components/borrow/Borrowings'
import Tab from 'components/common/Tab'
import V1Borrowings from 'components/v1/Borrowings'
import V1Intro from 'components/v1/V1Intro'
import { LEND_AND_BORROW_TABS } from 'constants/pages'
import useStore from 'store'
import BorrowIntro from 'components/borrow/BorrowIntro'
export default function BorrowPage() {
const isV1 = useStore((s) => s.isV1)
return (
<div className='flex flex-wrap w-full gap-6'>
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={1} showV1Toggle />
{isV1 ? <V1Intro /> : <BorrowIntro />}
{isV1 ? <V1Borrowings /> : <Borrowings />}
<BorrowIntro />
<Borrowings />
</div>
)
}
+5 -5
View File
@@ -1,12 +1,12 @@
import Tab from 'components/common/Tab'
import FarmIntro from 'components/farm/FarmIntro'
import Vaults from 'components/farm/Vaults'
import { LEND_AND_BORROW_TABS } from 'constants/pages'
import Tab from 'components/earn/Tab'
import FarmIntro from 'components/earn/farm/FarmIntro'
import Vaults from 'components/earn/farm/Vaults'
import { EARN_TABS } from 'constants/pages'
export default function FarmPage() {
return (
<div className='flex flex-wrap w-full gap-6'>
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={2} showV1Toggle />
<Tab tabs={EARN_TABS} activeTabIdx={1} />
<FarmIntro />
<Vaults />
</div>
+1 -1
View File
@@ -1,4 +1,4 @@
import Tab from 'components/common/Tab'
import Tab from 'components/earn/Tab'
import AvailableHLSVaults from 'components/hls/Farm/AvailableHLSVaults'
import HlsFarmIntro from 'components/hls/Farm/HLSFarmIntro'
import { HLS_TABS } from 'constants/pages'
+1 -1
View File
@@ -1,4 +1,4 @@
import Tab from 'components/common/Tab'
import Tab from 'components/earn/Tab'
import ActiveStakingAccounts from 'components/hls/Staking/ActiveStakingAccounts'
import AvailableHlsStakingAssets from 'components/hls/Staking/AvailableHLSStakingAssets'
import HLSStakingIntro from 'components/hls/Staking/HLSStakingIntro'
+9 -11
View File
@@ -1,19 +1,17 @@
import Tab from 'components/common/Tab'
import LendIntro from 'components/lend/LendIntro'
import Lends from 'components/lend/Lends'
import Deposits from 'components/v1/Deposits'
import V1Intro from 'components/v1/V1Intro'
import { LEND_AND_BORROW_TABS } from 'constants/pages'
import useStore from 'store'
import Tab from 'components/earn/Tab'
import LendIntro from 'components/earn/lend/LendIntro'
import Lends from 'components/earn/lend/Lends'
import { EARN_TABS } from 'constants/pages'
import useChainConfig from 'hooks/useChainConfig'
export default function LendPage() {
const isV1 = useStore((s) => s.isV1)
const chainConfig = useChainConfig()
return (
<div className='flex flex-wrap w-full gap-6'>
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={0} showV1Toggle />
{isV1 ? <V1Intro /> : <LendIntro />}
{isV1 ? <Deposits /> : <Lends />}
{chainConfig.farm && <Tab tabs={EARN_TABS} activeTabIdx={0} />}
<LendIntro />
<Lends />
</div>
)
}
-5
View File
@@ -1,18 +1,13 @@
import { useParams } from 'react-router-dom'
import ShareBar from 'components/common/ShareBar'
import Summary from 'components/portfolio/Account/Summary'
import AccountOverview from 'components/portfolio/Overview'
import PortfolioSummary from 'components/portfolio/Overview/Summary'
import PortfolioIntro from 'components/portfolio/PortfolioIntro'
export default function PortfolioPage() {
const { address } = useParams()
return (
<div className='flex flex-wrap w-full gap-6'>
<PortfolioIntro />
<PortfolioSummary />
{address && <Summary accountId={address} v1 />}
<AccountOverview />
<ShareBar text='Have a look at this @mars_protocol portfolio!' />
</div>
+19
View File
@@ -0,0 +1,19 @@
import Summary from 'components/portfolio/Account/Summary'
import Borrowings from 'components/v1/Borrowings'
import Deposits from 'components/v1/Deposits'
import V1Intro from 'components/v1/V1Intro'
import useStore from 'store'
export default function V1Page() {
const address = useStore((s) => s.address)
return (
<div className='flex flex-wrap w-full gap-6'>
<V1Intro />
{address && <Summary accountId={address} v1 />}
<div className='grid w-full grid-cols-1 gap-6 lg:grid-cols-2'>
<Deposits />
<Borrowings />
</div>
</div>
)
}
+8 -3
View File
@@ -4,13 +4,14 @@ import { isMobile } from 'react-device-detect'
import { useLocation } from 'react-router-dom'
import { SWRConfig } from 'swr'
import ModalsContainer from 'components/Modals/ModalsContainer'
import AccountDetails from 'components/account/AccountDetails'
import Background from 'components/common/Background'
import Footer from 'components/common/Footer'
import PageMetadata from 'components/common/PageMetadata'
import Toaster from 'components/common/Toaster'
import DesktopHeader from 'components/header/DesktopHeader'
import ModalsContainer from 'components/Modals/ModalsContainer'
import V1DesktopHeader from 'components/header/V1DesktopHeader'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
@@ -25,6 +26,8 @@ interface Props {
}
function PageContainer(props: Props) {
const isV1 = useStore((s) => s.isV1)
if (isMobile) return props.children
if (!props.focusComponent)
@@ -32,7 +35,8 @@ function PageContainer(props: Props) {
<div
className={classNames(
'mx-auto flex items-start w-full',
!props.fullWidth && 'max-w-content',
!props.fullWidth && !isV1 && 'max-w-content',
isV1 && 'max-w-v1',
)}
>
{props.children}
@@ -50,6 +54,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
const location = useLocation()
const focusComponent = useStore((s) => s.focusComponent)
const address = useStore((s) => s.address)
const isV1 = useStore((s) => s.isV1)
const [reduceMotion] = useLocalStorage<boolean>(
LocalStorageKeys.REDUCE_MOTION,
@@ -67,7 +72,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
<SWRConfig value={{ use: [debugSWR] }}>
<PageMetadata />
<Background />
<DesktopHeader />
{isV1 ? <V1DesktopHeader /> : <DesktopHeader />}
<main
className={classNames(
'lg:min-h-[calc(100dvh-81px)]',
+8
View File
@@ -23,6 +23,10 @@ export const getCurrentChainId = () => {
if (currentNetwork === NETWORK.TESTNET) chainId = ChainInfoID.OsmosisDevnet
break
case 'neutron':
if (currentNetwork === NETWORK.MAINNET) chainId = ChainInfoID.Neutron1
break
case 'testnet-neutron':
if (currentNetwork === NETWORK.TESTNET) chainId = ChainInfoID.Pion1
break
@@ -42,6 +46,10 @@ export const getCurrentChainId = () => {
if (currentNetwork === NETWORK.TESTNET) chainId = ChainInfoID.OsmosisDevnet
break
case ChainInfoID.Neutron1:
if (currentNetwork === NETWORK.MAINNET) chainId = ChainInfoID.Neutron1
break
case ChainInfoID.Pion1:
if (currentNetwork === NETWORK.TESTNET) chainId = ChainInfoID.Pion1
break
+8 -1
View File
@@ -240,6 +240,7 @@ module.exports = {
},
maxWidth: {
content: '1024px',
v1: '1248px',
modal: '895px',
'modal-md': '556px',
'modal-sm': '526px',
@@ -259,7 +260,7 @@ module.exports = {
screens: {
sm: '480px',
md: '720px',
lg: '1024px',
lg: '1280px',
xl: '1280px',
'2xl': '1920px',
},
@@ -504,6 +505,12 @@ module.exports = {
textTransform: 'uppercase',
letterSpacing: '9px',
},
'.bg-v1': {
backgroundImage: 'url(/images/bg-v1.svg)',
backgroundRepeat: 'no-repeat',
backgroundSize: '100% auto',
backgroundPosition: 'top',
},
})
}),
plugin(({ matchUtilities, theme }) => {