Compare commits
29 Commits
main
...
v1-impleme
Author | SHA1 | Date | |
---|---|---|---|
|
4ebcc44ded | ||
|
b4647ff440 | ||
|
103246261f | ||
|
860079b071 | ||
|
51e02eec8c | ||
|
071cceacec | ||
|
89e9942b7e | ||
|
1a45d64bac | ||
|
89d41fa5cf | ||
|
df7ef30a43 | ||
|
fc9fcf13fc | ||
|
5846e893d1 | ||
|
21bedd7905 | ||
|
37be3240eb | ||
|
f609540809 | ||
|
106de661a8 | ||
|
40593ae987 | ||
|
e3b5e330ee | ||
|
7eac8e7a35 | ||
|
af478c56d5 | ||
|
a6f4c24f15 | ||
|
6946ceddfc | ||
|
0154065ffb | ||
|
4f64234a75 | ||
|
26f1ef4a2c | ||
|
34db8aea1a | ||
|
75edb21c02 | ||
|
442b7a3a8c | ||
|
3f28ccd09c |
@ -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
public/images/bg-v1.svg
Normal file
63
public/images/bg-v1.svg
Normal 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
public/images/tokens/stkatom.svg
Normal file
42
public/images/tokens/stkatom.svg
Normal 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
public/images/tokens/wsteth.svg
Normal file
26
public/images/tokens/wsteth.svg
Normal 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 |
@ -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
|
||||
})
|
@ -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
|
@ -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
|
||||
})
|
@ -10,7 +10,12 @@ import {
|
||||
TotalDepositResponse,
|
||||
VaultConfigBaseForAddr,
|
||||
} from 'types/generated/mars-params/MarsParams.types'
|
||||
import { ArrayOfMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
import {
|
||||
ArrayOfMarket,
|
||||
ArrayOfUserCollateralResponse,
|
||||
ArrayOfUserDebtResponse,
|
||||
UserCollateralResponse,
|
||||
} from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
|
||||
interface Cache<T> extends Map<string, { data: T | null; timestamp: number }> {}
|
||||
|
||||
@ -62,3 +67,5 @@ export const underlyingDebtCache: Cache<string> = new Map()
|
||||
export const previewDepositCache: Cache<{ vaultAddress: string; amount: string }> = new Map()
|
||||
export const stakingAprCache: Cache<StakingApr[]> = new Map()
|
||||
export const assetParamsCache: Cache<AssetParamsBaseForAddr[]> = new Map()
|
||||
export const userCollateralCache: Cache<ArrayOfUserCollateralResponse> = new Map()
|
||||
export const userDebtCache: Cache<ArrayOfUserDebtResponse> = new Map()
|
||||
|
@ -6,7 +6,9 @@ import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMo
|
||||
import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client'
|
||||
import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client'
|
||||
import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client'
|
||||
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
|
||||
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
|
||||
import { getUrl } from 'utils/url'
|
||||
|
||||
let _cosmWasmClient: Map<string, CosmWasmClient> = new Map()
|
||||
let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map()
|
||||
@ -15,6 +17,7 @@ let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map()
|
||||
let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map()
|
||||
let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map()
|
||||
let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map()
|
||||
let _redBankQueryClient: Map<string, MarsRedBankQueryClient> = new Map()
|
||||
|
||||
const getClient = async (rpc: string) => {
|
||||
try {
|
||||
@ -32,7 +35,7 @@ const getClient = async (rpc: string) => {
|
||||
const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.creditManager
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_creditManagerQueryClient.get(key)) {
|
||||
@ -49,7 +52,7 @@ const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getParamsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.params
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_paramsQueryClient.get(key)) {
|
||||
@ -66,7 +69,7 @@ const getParamsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getOracleQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.oracle
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_oracleQueryClient.get(key)) {
|
||||
@ -82,7 +85,7 @@ const getOracleQueryClient = async (chainConfig: ChainConfig) => {
|
||||
|
||||
const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => {
|
||||
try {
|
||||
const client = await getClient(chainConfig.endpoints.rpc)
|
||||
const client = await getClient(getUrl(chainConfig.endpoints.rpc))
|
||||
return new MarsMockVaultQueryClient(client, address)
|
||||
} catch (error) {
|
||||
throw error
|
||||
@ -92,7 +95,7 @@ const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) =>
|
||||
const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.incentives
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
if (!_incentivesQueryClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@ -108,7 +111,7 @@ const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.swapper
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
if (!_swapperOsmosisClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@ -124,7 +127,7 @@ const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.perps
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
if (!_perpsClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@ -137,13 +140,31 @@ const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getRedBankQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.redBank
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_redBankQueryClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
_redBankQueryClient.set(key, new MarsRedBankQueryClient(client, contract))
|
||||
}
|
||||
|
||||
return _redBankQueryClient.get(key)!
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getClient,
|
||||
getCreditManagerQueryClient,
|
||||
getIncentivesQueryClient,
|
||||
getOracleQueryClient,
|
||||
getParamsQueryClient,
|
||||
getPerpsQueryClient,
|
||||
getRedBankQueryClient,
|
||||
getSwapperQueryClient,
|
||||
getVaultQueryClient,
|
||||
getPerpsQueryClient,
|
||||
}
|
||||
|
41
src/api/v1/getV1Positions.ts
Normal file
41
src/api/v1/getV1Positions.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { cacheFn, userCollateralCache, userDebtCache } from 'api/cache'
|
||||
import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import {
|
||||
ArrayOfUserCollateralResponse,
|
||||
ArrayOfUserDebtResponse,
|
||||
} from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
|
||||
export default async function getV1Positions(
|
||||
chainConfig: ChainConfig,
|
||||
user?: string,
|
||||
): Promise<Account> {
|
||||
if (!user) return new Promise((_, reject) => reject('No account Wallet ID found'))
|
||||
|
||||
const redBankQueryClient = await getRedBankQueryClient(chainConfig)
|
||||
|
||||
const userCollateral: ArrayOfUserCollateralResponse = await cacheFn(
|
||||
() => redBankQueryClient.userCollaterals({ user: user, limit: 100 }),
|
||||
userCollateralCache,
|
||||
`${chainConfig.id}/v1/deposits/${user}`,
|
||||
)
|
||||
const userDebt: ArrayOfUserDebtResponse = await cacheFn(
|
||||
() => redBankQueryClient.userDebts({ user: user, limit: 100 }),
|
||||
userDebtCache,
|
||||
`${chainConfig.id}/v1/debts/${user}`,
|
||||
)
|
||||
|
||||
if (userCollateral && userDebt) {
|
||||
return {
|
||||
id: user,
|
||||
debts: userDebt.map((debt) => new BNCoin(debt)),
|
||||
lends: userCollateral.map((lend) => new BNCoin(lend)),
|
||||
deposits: [],
|
||||
vaults: [],
|
||||
perps: [],
|
||||
kind: 'default',
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No account found'))
|
||||
}
|
@ -10,12 +10,12 @@ import Text from 'components/common/Text'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
asset: Asset
|
||||
title: string
|
||||
coinBalances: BNCoin[]
|
||||
@ -29,6 +29,7 @@ interface Props {
|
||||
|
||||
export default function AssetAmountSelectActionModal(props: Props) {
|
||||
const {
|
||||
account,
|
||||
asset,
|
||||
title,
|
||||
coinBalances,
|
||||
@ -41,7 +42,6 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
} = props
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
||||
const account = useCurrentAccount()
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setAmount(value)
|
||||
@ -54,7 +54,6 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
onAction(amount, amount.isEqualTo(maxAmount))
|
||||
}, [amount, maxAmount, onAction])
|
||||
|
||||
if (!account) return
|
||||
return (
|
||||
<Modal
|
||||
onClose={onClose}
|
||||
|
@ -35,18 +35,9 @@ interface Props {
|
||||
modal: BorrowModal
|
||||
}
|
||||
|
||||
function getDebtAmount(modal: BorrowModal) {
|
||||
return BN((modal.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
|
||||
}
|
||||
|
||||
function getAssetLogo(modal: BorrowModal) {
|
||||
if (!modal.asset) return null
|
||||
return <AssetImage asset={modal.asset} size={24} />
|
||||
}
|
||||
|
||||
function RepayNotAvailable(props: { asset: Asset; repayFromWallet: boolean }) {
|
||||
return (
|
||||
<Card className='mt-6'>
|
||||
<Card className='w-full'>
|
||||
<div className='flex items-start p-4'>
|
||||
<InfoCircle className='w-6 mr-2 flex-0' />
|
||||
<div className='flex flex-col flex-1 gap-1'>
|
||||
@ -90,7 +81,6 @@ function BorrowModal(props: Props) {
|
||||
const apy = modal.marketData.apy.borrow
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const totalDebt = BN(getDebtAmount(modal))
|
||||
const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO
|
||||
const markets = useMarkets()
|
||||
|
||||
@ -237,7 +227,7 @@ function BorrowModal(props: Props) {
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
{getAssetLogo(modal)}
|
||||
<AssetImage asset={asset} size={24} />
|
||||
<Text>
|
||||
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
|
||||
</Text>
|
||||
@ -251,14 +241,14 @@ function BorrowModal(props: Props) {
|
||||
title={formatPercent(modal.marketData.apy.borrow)}
|
||||
sub={'Borrow Rate APY'}
|
||||
/>
|
||||
{totalDebt.isGreaterThan(0) && (
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
<>
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={totalDebt.toNumber()}
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
@ -267,7 +257,7 @@ function BorrowModal(props: Props) {
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
@ -303,59 +293,57 @@ function BorrowModal(props: Props) {
|
||||
<div className='flex items-start flex-1 gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-1 p-4 bg-white/5'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<div className='flex flex-wrap w-full'>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Repay from Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Repay your debt directly from your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Receive funds to Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Your borrowed funds will directly go to your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
|
@ -23,6 +23,7 @@ interface Props {
|
||||
}
|
||||
|
||||
function LendAndReclaimModal({ currentAccount, config }: Props) {
|
||||
const account = useCurrentAccount()
|
||||
const lend = useStore((s) => s.lend)
|
||||
const reclaim = useStore((s) => s.reclaim)
|
||||
const { close } = useLendAndReclaimModal()
|
||||
@ -65,8 +66,11 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
|
||||
},
|
||||
[asset.denom, close, currentAccount.id, isLendAction, lend, reclaim],
|
||||
)
|
||||
if (!account) return null
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={data} />}
|
||||
coinBalances={coinBalances}
|
||||
|
@ -10,6 +10,8 @@ import {
|
||||
LendAndReclaimModalController,
|
||||
SettingsModal,
|
||||
UnlockModal,
|
||||
V1BorrowAndRepay,
|
||||
V1DepositAndWithdraw,
|
||||
VaultModal,
|
||||
WalletAssets,
|
||||
WithdrawFromVaultsModal,
|
||||
@ -32,6 +34,8 @@ export default function ModalsContainer() {
|
||||
<AlertDialogController />
|
||||
<HlsModal />
|
||||
<HlsManageModal />
|
||||
<V1DepositAndWithdraw />
|
||||
<V1BorrowAndRepay />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ export { default as AlertDialogController } from 'components/Modals/AlertDialog'
|
||||
export { default as BorrowModal } from 'components/Modals/BorrowModal'
|
||||
export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw'
|
||||
export { default as GetStartedModal } from 'components/Modals/GetStartedModal'
|
||||
export { default as HlsModal } from 'components/Modals/HLS'
|
||||
export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
|
||||
export { default as LendAndReclaimModalController } from 'components/Modals/LendAndReclaim'
|
||||
export { default as SettingsModal } from 'components/Modals/Settings'
|
||||
export { default as UnlockModal } from 'components/Modals/Unlock'
|
||||
export { default as VaultModal } from 'components/Modals/Vault'
|
||||
export { default as WalletAssets } from 'components/Modals/WalletAssets'
|
||||
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
|
||||
export { default as HlsModal } from 'components/Modals/HLS'
|
||||
export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
|
||||
export { default as V1BorrowAndRepay } from 'components/Modals/v1/V1BorrowAndRepay'
|
||||
export { default as V1DepositAndWithdraw } from 'components/Modals/v1/V1DepositAndWithdraw'
|
||||
|
179
src/components/Modals/v1/Borrow.tsx
Normal file
179
src/components/Modals/v1/Borrow.tsx
Normal file
@ -0,0 +1,179 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Modal from 'components/Modals/Modal'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Button from 'components/common/Button'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import Divider from 'components/common/Divider'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Borrow(props: Props) {
|
||||
const { account } = props
|
||||
const modal = useStore((s) => s.v1BorrowAndRepayModal)
|
||||
const baseAsset = useBaseAsset()
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [max, setMax] = useState(BN_ZERO)
|
||||
const { simulateBorrow } = useUpdatedAccount(account)
|
||||
const apy = modal?.data.apy.borrow ?? 0
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
|
||||
|
||||
const accountDebtWithInterest = useMemo(
|
||||
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||
[accountDebt, apy],
|
||||
)
|
||||
|
||||
const close = useCallback(() => {
|
||||
setAmount(BN_ZERO)
|
||||
useStore.setState({ v1BorrowAndRepayModal: null })
|
||||
}, [setAmount])
|
||||
|
||||
const onConfirmClick = useCallback(() => {
|
||||
v1Action('borrow', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
|
||||
close()
|
||||
}, [v1Action, asset, amount, close])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newAmount: BigNumber) => {
|
||||
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||
},
|
||||
[amount, setAmount],
|
||||
)
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
const borrowCoin = BNCoin.fromDenomAndBigNumber(
|
||||
asset.denom,
|
||||
amount.isGreaterThan(max) ? max : amount,
|
||||
)
|
||||
simulateBorrow('wallet', borrowCoin)
|
||||
}, [amount, max, asset, simulateBorrow])
|
||||
|
||||
const maxBorrow = useMemo(() => {
|
||||
const maxBorrowAmount = computeMaxBorrowAmount(asset.denom, 'wallet')
|
||||
|
||||
return BigNumber.min(maxBorrowAmount, modal?.data.liquidity || 0)
|
||||
}, [asset.denom, computeMaxBorrowAmount, modal?.data.liquidity])
|
||||
|
||||
useEffect(() => {
|
||||
if (maxBorrow.isEqualTo(max)) return
|
||||
setMax(maxBorrow)
|
||||
}, [account, maxBorrow, max])
|
||||
|
||||
useEffect(() => {
|
||||
if (amount.isLessThanOrEqualTo(max)) return
|
||||
handleChange(max)
|
||||
setAmount(max)
|
||||
}, [amount, max, handleChange])
|
||||
|
||||
if (!modal) return null
|
||||
return (
|
||||
<Modal
|
||||
onClose={close}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<AssetImage asset={modal.data.asset} size={24} />
|
||||
<Text>{`Borrow ${asset.symbol} from the Red Bank`}</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
<>
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
suffix: ` ${asset.symbol}`,
|
||||
}}
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Total Borrowed
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={modal.data.liquidity.toNumber() ?? 0}
|
||||
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
|
||||
animate
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data.liquidity ?? BN_ZERO)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Liquidity available
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-start flex-1 gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-1 p-4 bg-white/5'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
<Divider />
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
disabled={amount.isZero()}
|
||||
text={`Borrow ${asset.symbol}`}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
82
src/components/Modals/v1/Deposit.tsx
Normal file
82
src/components/Modals/v1/Deposit.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { BN } from 'utils/helpers'
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Deposit(props: Props) {
|
||||
const { account } = props
|
||||
const baseAsset = useBaseAsset()
|
||||
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
|
||||
const address = useStore((s) => s.address)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [fundingAsset, setFundingAsset] = useState<BNCoin>(
|
||||
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
|
||||
)
|
||||
const { data: walletBalances } = useWalletBalances(address)
|
||||
const { simulateDeposits } = useUpdatedAccount(account)
|
||||
const balance = useCurrentWalletBalance(asset.denom)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
|
||||
const baseBalance = useMemo(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
[walletBalances, baseAsset],
|
||||
)
|
||||
|
||||
const close = useCallback(() => {
|
||||
useStore.setState({ v1DepositAndWithdrawModal: null })
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
v1Action('deposit', fundingAsset)
|
||||
close()
|
||||
}, [v1Action, fundingAsset, close])
|
||||
|
||||
useEffect(() => {
|
||||
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
|
||||
useStore.setState({ focusComponent: { component: <WalletBridges /> } })
|
||||
}
|
||||
}, [baseBalance])
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
simulateDeposits('lend', [fundingAsset])
|
||||
}, [fundingAsset, simulateDeposits])
|
||||
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setFundingAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
|
||||
},
|
||||
[asset.denom],
|
||||
)
|
||||
|
||||
if (!modal) return
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={modal.data} />}
|
||||
coinBalances={balance ? [BNCoin.fromCoin(balance)] : []}
|
||||
actionButtonText={`Deposit ${asset.symbol}`}
|
||||
title={`Deposit ${asset.symbol} into the Red Bank`}
|
||||
onClose={close}
|
||||
onAction={handleClick}
|
||||
onChange={handleAmountChange}
|
||||
onDebounce={onDebounce}
|
||||
/>
|
||||
)
|
||||
}
|
208
src/components/Modals/v1/Repay.tsx
Normal file
208
src/components/Modals/v1/Repay.tsx
Normal file
@ -0,0 +1,208 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Modal from 'components/Modals/Modal'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Button from 'components/common/Button'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import Divider from 'components/common/Divider'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight, InfoCircle } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
function RepayNotAvailable(props: { asset: Asset }) {
|
||||
return (
|
||||
<Card className='w-full'>
|
||||
<div className='flex items-start p-4'>
|
||||
<InfoCircle className='w-6 mr-2 flex-0' />
|
||||
<div className='flex flex-col flex-1 gap-1'>
|
||||
<Text size='sm'>No funds for repay</Text>
|
||||
<Text
|
||||
size='xs'
|
||||
className='text-white/40'
|
||||
>{`Unfortunately you don't have any ${props.asset.symbol} in your Wallet to repay the debt.`}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Repay(props: Props) {
|
||||
const { account } = props
|
||||
const modal = useStore((s) => s.v1BorrowAndRepayModal)
|
||||
const baseAsset = useBaseAsset()
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const balance = useCurrentWalletBalance(asset.denom)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
const [max, setMax] = useState(BN_ZERO)
|
||||
const { simulateRepay } = useUpdatedAccount(account)
|
||||
const apy = modal?.data.apy.borrow ?? 0
|
||||
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
|
||||
const markets = useMarkets()
|
||||
|
||||
const accountDebtWithInterest = useMemo(
|
||||
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||
[accountDebt, apy],
|
||||
)
|
||||
|
||||
const overpayExeedsCap = useMemo(() => {
|
||||
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
|
||||
if (!marketAsset) return
|
||||
const overpayAmount = accountDebtWithInterest.minus(accountDebt)
|
||||
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
|
||||
|
||||
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
|
||||
}, [markets, asset.denom, accountDebt, accountDebtWithInterest])
|
||||
|
||||
const maxRepayAmount = useMemo(() => {
|
||||
const maxBalance = BN(balance?.amount ?? 0)
|
||||
return BigNumber.min(maxBalance, overpayExeedsCap ? accountDebt : accountDebtWithInterest)
|
||||
}, [accountDebtWithInterest, overpayExeedsCap, accountDebt, balance?.amount])
|
||||
|
||||
const close = useCallback(() => {
|
||||
setAmount(BN_ZERO)
|
||||
useStore.setState({ v1BorrowAndRepayModal: null })
|
||||
}, [setAmount])
|
||||
|
||||
const onConfirmClick = useCallback(() => {
|
||||
v1Action('repay', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
|
||||
close()
|
||||
}, [v1Action, asset, amount, close])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newAmount: BigNumber) => {
|
||||
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||
},
|
||||
[amount, setAmount],
|
||||
)
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
const repayCoin = BNCoin.fromDenomAndBigNumber(
|
||||
asset.denom,
|
||||
amount.isGreaterThan(accountDebt) ? accountDebt : amount,
|
||||
)
|
||||
simulateRepay(repayCoin, true)
|
||||
}, [amount, accountDebt, asset, simulateRepay])
|
||||
|
||||
useEffect(() => {
|
||||
if (maxRepayAmount.isEqualTo(max)) return
|
||||
setMax(maxRepayAmount)
|
||||
}, [max, maxRepayAmount])
|
||||
|
||||
useEffect(() => {
|
||||
if (amount.isLessThanOrEqualTo(max)) return
|
||||
handleChange(max)
|
||||
setAmount(max)
|
||||
}, [amount, max, handleChange])
|
||||
|
||||
if (!modal) return null
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onClose={close}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<AssetImage asset={modal.data.asset} size={24} />
|
||||
<Text>
|
||||
{'Repay'} {asset.symbol}
|
||||
</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
|
||||
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
suffix: ` ${asset.symbol}`,
|
||||
}}
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Total Borrowed
|
||||
</Text>
|
||||
</div>
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={modal.data?.liquidity.toNumber() ?? 0}
|
||||
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
|
||||
animate
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data?.liquidity ?? BN_ZERO)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Liquidity available
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-start flex-1 gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-1 p-4 bg-white/5'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
<Divider />
|
||||
{maxRepayAmount.isZero() && <RepayNotAvailable asset={asset} />}
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
disabled={amount.isZero()}
|
||||
text={`Repay ${asset.symbol}`}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
import Borrow from 'components/Modals/v1/Borrow'
|
||||
import Repay from 'components/Modals/v1/Repay'
|
||||
|
||||
export default function V1BorrowAndRepayModal() {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
const modal = useStore<V1BorrowAndRepayModal | null>((s) => s.v1BorrowAndRepayModal)
|
||||
const isBorrow = modal?.type === 'borrow'
|
||||
|
||||
if (!modal || !account) return null
|
||||
if (isBorrow) return <Borrow account={account} />
|
||||
return <Repay account={account} />
|
||||
}
|
15
src/components/Modals/v1/V1DepositAndWithdraw.tsx
Normal file
15
src/components/Modals/v1/V1DepositAndWithdraw.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
import Deposit from 'components/Modals/v1/Deposit'
|
||||
import Withdraw from 'components/Modals/v1/Withdraw'
|
||||
|
||||
export default function V1DepositAndWithdraw() {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
const modal = useStore<V1DepositAndWithdrawModal | null>((s) => s.v1DepositAndWithdrawModal)
|
||||
const isDeposit = modal?.type === 'deposit'
|
||||
|
||||
if (!modal || !account) return null
|
||||
if (isDeposit) return <Deposit account={account} />
|
||||
return <Withdraw account={account} />
|
||||
}
|
66
src/components/Modals/v1/Withdraw.tsx
Normal file
66
src/components/Modals/v1/Withdraw.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Withdraw(props: Props) {
|
||||
const { account } = props
|
||||
const baseAsset = useBaseAsset()
|
||||
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [withdrawAsset, setWithdrawAsset] = useState<BNCoin>(
|
||||
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
|
||||
)
|
||||
const { computeMaxWithdrawAmount } = useHealthComputer(account)
|
||||
const maxWithdrawAmount = computeMaxWithdrawAmount(asset.denom)
|
||||
const { simulateWithdraw } = useUpdatedAccount(account)
|
||||
const balance = BNCoin.fromDenomAndBigNumber(asset.denom, maxWithdrawAmount)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
|
||||
const close = useCallback(() => {
|
||||
useStore.setState({ v1DepositAndWithdrawModal: null })
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
v1Action('withdraw', withdrawAsset)
|
||||
close()
|
||||
}, [v1Action, withdrawAsset, close])
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
simulateWithdraw(false, withdrawAsset)
|
||||
}, [withdrawAsset, simulateWithdraw])
|
||||
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setWithdrawAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
|
||||
},
|
||||
[asset.denom],
|
||||
)
|
||||
|
||||
if (!modal) return
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={modal.data} />}
|
||||
coinBalances={[balance]}
|
||||
actionButtonText={`Withdraw ${asset.symbol}`}
|
||||
title={`Withdraw ${asset.symbol} from the Red Bank`}
|
||||
onClose={close}
|
||||
onAction={handleClick}
|
||||
onChange={handleAmountChange}
|
||||
onDebounce={onDebounce}
|
||||
/>
|
||||
)
|
||||
}
|
@ -7,8 +7,8 @@ import Text from 'components/common/Text'
|
||||
import { TextLink } from 'components/common/TextLink'
|
||||
import { generateToastContent } from 'components/common/Toaster'
|
||||
import useTransactions from 'hooks/localStorage/useTransactions'
|
||||
import useStore from 'store'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function RecentTransactions() {
|
||||
const address = useStore((s) => s.address)
|
||||
@ -47,7 +47,9 @@ export default function RecentTransactions() {
|
||||
key={hash}
|
||||
>
|
||||
<div className='flex items-start justify-between w-full pb-2'>
|
||||
<Text className='flex font-bold'>Credit Account {accountId}</Text>
|
||||
<Text className='flex font-bold'>
|
||||
{accountId === address ? 'Red Bank' : `Credit Account ${accountId}`}
|
||||
</Text>
|
||||
<Text size='sm' className='text-white/70'>
|
||||
{moment.unix(timestamp).format('lll')}
|
||||
</Text>
|
||||
|
@ -15,6 +15,7 @@ interface Props {
|
||||
color?: ButtonProps['color']
|
||||
variant?: ButtonProps['variant']
|
||||
size?: ButtonProps['size']
|
||||
short?: boolean
|
||||
}
|
||||
|
||||
export default function WalletConnectButton(props: Props) {
|
||||
|
@ -10,6 +10,7 @@ import useChainConfig from 'hooks/useChainConfig'
|
||||
import useCurrentWallet from 'hooks/useCurrentWallet'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getUrl } from 'utils/url'
|
||||
|
||||
interface Props {
|
||||
providerId?: string
|
||||
@ -53,7 +54,7 @@ export default function WalletConnecting(props: Props) {
|
||||
setIsConnecting(true)
|
||||
try {
|
||||
const response = await connect({ extensionProviderId, chainId: chainConfig.id })
|
||||
const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
|
||||
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||
const walletClient: WalletClient = {
|
||||
broadcast,
|
||||
cosmWasmClient: cosmClient,
|
||||
@ -137,7 +138,7 @@ export default function WalletConnecting(props: Props) {
|
||||
setIsConnecting(true)
|
||||
try {
|
||||
await mobileConnect({ mobileProviderId, chainId: chainConfig.id })
|
||||
const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
|
||||
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||
const walletClient: WalletClient = {
|
||||
broadcast,
|
||||
cosmWasmClient: cosmClient,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
},
|
||||
})
|
||||
}}
|
||||
short
|
||||
/>
|
||||
</div>
|
||||
</ConditionalWrapper>
|
||||
|
@ -37,6 +37,7 @@ import {
|
||||
export default function AccountDetailsController() {
|
||||
const address = useStore((s) => s.address)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const isV1 = useStore((s) => s.isV1)
|
||||
const { data: _, isLoading } = useAccounts('default', address)
|
||||
const { data: accountIds } = useAccountIds(address, false, true)
|
||||
|
||||
@ -45,10 +46,11 @@ export default function AccountDetailsController() {
|
||||
const account = useCurrentAccount()
|
||||
const focusComponent = useStore((s) => s.focusComponent)
|
||||
const isOwnAccount = accountId && accountIds?.includes(accountId)
|
||||
const hideAccountDetails = !address || focusComponent || !isOwnAccount || isHLS || isV1
|
||||
const isLoadingAccountDetails = (isLoading && accountId && !focusComponent) || !account
|
||||
|
||||
if (!address || focusComponent || !isOwnAccount || isHLS) return null
|
||||
|
||||
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
||||
if (hideAccountDetails) return null
|
||||
if (isLoadingAccountDetails) return <Skeleton />
|
||||
|
||||
return <AccountDetails account={account} />
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
import ActiveBorrowingsTable from 'components/borrow/Table/ActiveBorrowingsTable'
|
||||
import AvailableBorrowingsTable from 'components/borrow/Table/AvailableBorrowingsTable'
|
||||
import DepositedBorrowingsTable from 'components/borrow/Table/DepositedBorrowingsTable'
|
||||
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
|
||||
|
||||
export default function Borrowings() {
|
||||
const data = useBorrowMarketAssetsTableData()
|
||||
const { accountBorrowedAssets, availableAssets, allAssets } = useBorrowMarketAssetsTableData()
|
||||
|
||||
if (!data?.allAssets?.length) {
|
||||
if (!allAssets?.length) {
|
||||
return <Fallback />
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<DepositedBorrowingsTable data={data.accountBorrowedAssets} isLoading={false} />
|
||||
<AvailableBorrowingsTable data={data.availableAssets} isLoading={false} />
|
||||
<ActiveBorrowingsTable data={accountBorrowedAssets} isLoading={false} />
|
||||
<AvailableBorrowingsTable data={availableAssets} isLoading={false} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { DEBT_VALUE_META } from 'components/borrow/Table/Columns/DebtValue'
|
||||
import { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns'
|
||||
import useBorrowingsColumns from 'components/borrow/Table/Columns/useActiveColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
|
||||
type Props = {
|
||||
data: BorrowMarketTableData[]
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function DepositedBorrowingsTable(props: Props) {
|
||||
const columns = useDepositedColumns()
|
||||
export default function ActiveBorrowingsTable(props: Props) {
|
||||
const columns = useBorrowingsColumns({ v1: props.v1 })
|
||||
|
||||
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
|
||||
return <MarketDetails row={row} type='borrow' />
|
||||
@ -22,10 +24,17 @@ export default function DepositedBorrowingsTable(props: Props) {
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Borrowed Assets'
|
||||
title={props.v1 ? 'Borrowings' : 'Borrowed Assets'}
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
||||
initialSorting={
|
||||
props.v1
|
||||
? [
|
||||
{ id: DEBT_VALUE_META.id, desc: true },
|
||||
{ id: NAME_META.id, desc: false },
|
||||
]
|
||||
: [{ id: NAME_META.id, desc: false }]
|
||||
}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
@ -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>
|
||||
|
@ -1,36 +0,0 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
|
||||
import AmountAndValue from 'components/common/AmountAndValue'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export const DEBT_META = {
|
||||
accessorKey: 'debt',
|
||||
header: 'Debt',
|
||||
}
|
||||
|
||||
export const debtSortingFn = (
|
||||
a: Row<BorrowMarketTableData>,
|
||||
b: Row<BorrowMarketTableData>,
|
||||
): number => {
|
||||
const assetA = a.original.asset
|
||||
const assetB = b.original.asset
|
||||
if (!a.original.accountDebt || !b.original.accountDebt) return 0
|
||||
const debtA = a.original.accountDebt.shiftedBy(-assetA.decimals)
|
||||
const debtB = b.original.accountDebt.shiftedBy(-assetB.decimals)
|
||||
return debtA.minus(debtB).toNumber()
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function Debt(props: Props) {
|
||||
const marketAssets = useMarketEnabledAssets()
|
||||
const asset = marketAssets.find(byDenom(props.data.asset.denom))
|
||||
|
||||
if (!asset) return null
|
||||
|
||||
return <AmountAndValue asset={asset} amount={props.data?.accountDebt ?? BN_ZERO} />
|
||||
}
|
30
src/components/borrow/Table/Columns/DebtValue.tsx
Normal file
30
src/components/borrow/Table/Columns/DebtValue.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
|
||||
import AmountAndValue from 'components/common/AmountAndValue'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const DEBT_VALUE_META = {
|
||||
id: 'accountDebtValue',
|
||||
accessorKey: 'accountDebtValue',
|
||||
header: 'Debt',
|
||||
}
|
||||
|
||||
export const debtSortingFn = (
|
||||
a: Row<BorrowMarketTableData>,
|
||||
b: Row<BorrowMarketTableData>,
|
||||
): number => {
|
||||
const debtValueA = BN(a.original?.accountDebtValue ?? 0)
|
||||
const debtValueB = BN(b.original?.accountDebtValue ?? 0)
|
||||
return debtValueA.minus(debtValueB).toNumber()
|
||||
}
|
||||
|
||||
interface Props {
|
||||
asset: Asset
|
||||
debtAmount?: BigNumber
|
||||
}
|
||||
export default function DebtValue(props: Props) {
|
||||
return (
|
||||
<AmountAndValue asset={props.asset} amount={props.debtAmount ? props.debtAmount : BN_ZERO} />
|
||||
)
|
||||
}
|
@ -48,7 +48,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>
|
||||
)
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -3,24 +3,34 @@ import { useMemo } from 'react'
|
||||
|
||||
import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate'
|
||||
import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
|
||||
import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt'
|
||||
import DebtValue, {
|
||||
DEBT_VALUE_META,
|
||||
debtSortingFn,
|
||||
} from 'components/borrow/Table/Columns/DebtValue'
|
||||
import Liquidity, {
|
||||
LIQUIDITY_META,
|
||||
liquiditySortingFn,
|
||||
} from 'components/borrow/Table/Columns/Liquidity'
|
||||
import Manage, { MANAGE_META } from 'components/borrow/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import Action from 'components/v1/Table/borrowings/Columns/Action'
|
||||
|
||||
export default function useDepositedColumns() {
|
||||
interface Props {
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function useActiveColumns(props: Props) {
|
||||
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
||||
return [
|
||||
{
|
||||
...NAME_META,
|
||||
cell: ({ row }) => <Name data={row.original} />,
|
||||
cell: ({ row }) => <Name data={row.original} v1={props.v1} />,
|
||||
},
|
||||
{
|
||||
...DEBT_META,
|
||||
cell: ({ row }) => <Debt data={row.original} />,
|
||||
...DEBT_VALUE_META,
|
||||
cell: ({ row }) => (
|
||||
<DebtValue asset={row.original.asset} debtAmount={row.original.accountDebtAmount} />
|
||||
),
|
||||
sortingFn: debtSortingFn,
|
||||
},
|
||||
{
|
||||
@ -34,12 +44,13 @@ export default function useDepositedColumns() {
|
||||
},
|
||||
{
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) => <Manage data={row.original} />,
|
||||
cell: ({ row }) =>
|
||||
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
}, [props.v1])
|
||||
}
|
@ -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])
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||
|
||||
export default function useBorrowMarketAssetsTableData() {
|
||||
const account = useCurrentAccount()
|
||||
const markets = useMarkets()
|
||||
const { convertAmount } = useDisplayCurrencyPrice()
|
||||
|
||||
return useMemo((): {
|
||||
accountBorrowedAssets: BorrowMarketTableData[]
|
||||
@ -18,15 +21,21 @@ export default function useBorrowMarketAssetsTableData() {
|
||||
markets
|
||||
.filter((market) => market.borrowEnabled)
|
||||
.forEach((market) => {
|
||||
const debt = account?.debts?.find((debt) => debt.denom === market.asset.denom)
|
||||
const amount =
|
||||
account?.debts?.find((debt) => debt.denom === market.asset.denom)?.amount ?? BN_ZERO
|
||||
const value = amount ? convertAmount(market.asset, amount) : undefined
|
||||
|
||||
const borrowMarketAsset: BorrowMarketTableData = {
|
||||
...market,
|
||||
accountDebt: debt?.amount,
|
||||
accountDebtAmount: amount,
|
||||
accountDebtValue: value,
|
||||
}
|
||||
|
||||
if (borrowMarketAsset.accountDebtAmount?.isZero()) {
|
||||
availableAssets.push(borrowMarketAsset)
|
||||
} else {
|
||||
accountBorrowedAssets.push(borrowMarketAsset)
|
||||
}
|
||||
;(borrowMarketAsset.accountDebt ? accountBorrowedAssets : availableAssets).push(
|
||||
borrowMarketAsset,
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
@ -34,5 +43,5 @@ export default function useBorrowMarketAssetsTableData() {
|
||||
availableAssets,
|
||||
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
||||
}
|
||||
}, [account?.debts, markets])
|
||||
}, [account?.debts, markets, convertAmount])
|
||||
}
|
||||
|
@ -15,19 +15,31 @@ 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])
|
||||
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, isV1])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'fixed inset-0',
|
||||
'w-full h-full',
|
||||
'overflow-hidden pointer-events-none background ',
|
||||
isHLS ? 'bg-body-hls' : 'bg-body',
|
||||
'overflow-hidden pointer-events-none background',
|
||||
bodyClassName,
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
)}
|
||||
>
|
||||
@ -39,7 +51,7 @@ export default function Background() {
|
||||
'max-h-[500px] max-w-[500px]',
|
||||
'left-[-10vw] top-[-10vw]',
|
||||
'blur-orb-primary',
|
||||
isHLS ? ' bg-orb-primary-hls' : 'bg-orb-primary',
|
||||
primaryOrbClassName,
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
!reduceMotion && 'animate-[float_120s_ease-in-out_infinite_2s]',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
@ -53,7 +65,7 @@ export default function Background() {
|
||||
'max-h-[1000px] max-w-[1000px]',
|
||||
'bottom-[-20vw] right-[-10vw]',
|
||||
'blur-orb-secondary',
|
||||
isHLS ? ' bg-orb-secondary-hls' : 'bg-orb-secondary',
|
||||
secondaryOrbClassName,
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-30',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
)}
|
||||
@ -66,7 +78,7 @@ export default function Background() {
|
||||
'max-h-[600px] max-w-[600px]',
|
||||
'right-[-4vw] top-[-10vw]',
|
||||
'blur-orb-tertiary ',
|
||||
isHLS ? ' bg-orb-tertiary-hls' : 'bg-orb-tertiary',
|
||||
tertiaryOrbClassName,
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
!reduceMotion && 'animate-[float_180s_ease-in_infinite]',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
|
@ -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'
|
||||
|
@ -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'>
|
||||
|
@ -17,7 +17,7 @@ import useStore from 'store'
|
||||
interface Props {
|
||||
text: string | ReactNode
|
||||
children?: ReactNode
|
||||
bg: 'borrow' | 'lend' | 'farm' | 'portfolio' | 'hls-farm' | 'hls-staking'
|
||||
bg: Page
|
||||
}
|
||||
|
||||
function IntroBackground(props: { bg: Props['bg'] }) {
|
||||
|
@ -23,7 +23,7 @@ export default function MarketDetails({ row, type }: Props) {
|
||||
symbol: displayCurrencySymbol,
|
||||
} = useDisplayCurrencyPrice()
|
||||
|
||||
const { asset, ltv, cap, liquidity, deposits, debt } = row.original
|
||||
const { asset, ltv, deposits, debt } = row.original
|
||||
|
||||
const details: Detail[] = useMemo(() => {
|
||||
const isDollar = displayCurrencySymbol === '$'
|
||||
@ -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'
|
||||
|
@ -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())}
|
||||
|
@ -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,
|
||||
)}
|
||||
>
|
||||
|
@ -11,11 +11,11 @@ import { TextLink } from 'components/common/TextLink'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useTransactionStore from 'hooks/useTransactionStore'
|
||||
import useStore from 'store'
|
||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
|
||||
const toastBodyClasses = classNames(
|
||||
'flex flex-wrap w-full group/transaction',
|
||||
@ -99,6 +99,13 @@ export default function Toaster() {
|
||||
if (!isError && toast.accountId) addTransaction(toast)
|
||||
const generalMessage = isError ? 'Transaction failed!' : 'Transaction completed successfully!'
|
||||
const showDetailElement = !!(!details && toast.hash)
|
||||
const address = useStore.getState().address
|
||||
|
||||
let target: string
|
||||
if (!isError) {
|
||||
target = toast.accountId === address ? 'Red Bank' : `Credit Account ${toast.accountId}`
|
||||
}
|
||||
|
||||
const Msg = () => (
|
||||
<div className='relative flex flex-wrap w-full m-0 isolate'>
|
||||
<div className='flex w-full gap-2 mb-2'>
|
||||
@ -141,7 +148,7 @@ export default function Toaster() {
|
||||
)}
|
||||
>
|
||||
{!isError && toast.accountId && (
|
||||
<Text className='mb-1 font-bold text-white'>{`Credit Account ${toast.accountId}`}</Text>
|
||||
<Text className='mb-1 font-bold text-white'>{target}</Text>
|
||||
)}
|
||||
{showDetailElement && toast.message && (
|
||||
<Text size='sm' className='w-full mb-1 text-white'>
|
||||
|
@ -34,6 +34,7 @@ export const Deposit = (props: Props) => {
|
||||
color='tertiary'
|
||||
text='Deposit'
|
||||
leftIcon={<Plus />}
|
||||
short
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,17 +1,16 @@
|
||||
import moment from 'moment/moment'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons'
|
||||
import Loading from 'components/common/Loading'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useStore from 'store'
|
||||
import { VaultStatus } from 'types/enums/vault'
|
||||
|
||||
import { DEFAULT_SETTINGS } from '../../../../../constants/defaultSettings'
|
||||
import { LocalStorageKeys } from '../../../../../constants/localStorageKeys'
|
||||
import useLocalStorage from '../../../../../hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from '../../../../../hooks/useAccountId'
|
||||
import useStore from '../../../../../store'
|
||||
import DropDownButton from '../../../../common/Button/DropDownButton'
|
||||
|
||||
export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' }
|
||||
|
||||
interface Props {
|
||||
@ -104,7 +103,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'
|
||||
|
@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
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,
|
||||
@ -10,8 +11,6 @@ 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 { Deposit, DEPOSIT_META } from './Deposit'
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
}
|
||||
|
@ -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 = (
|
||||
|
@ -5,6 +5,7 @@ import { BN_ZERO } from 'constants/math'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const DEPOSIT_VALUE_META = {
|
||||
id: 'accountLentValue',
|
||||
accessorKey: 'accountLentValue',
|
||||
header: 'Deposited',
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ 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])
|
||||
}
|
||||
|
@ -13,9 +13,11 @@ import DepositValue, {
|
||||
} 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 {
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function useDepositedColumns(props: Props) {
|
||||
@ -23,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,
|
||||
@ -49,12 +51,13 @@ export default function useDepositedColumns(props: Props) {
|
||||
},
|
||||
{
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) => <Manage data={row.original} />,
|
||||
cell: ({ row }) =>
|
||||
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [props.isLoading])
|
||||
}, [props.isLoading, props.v1])
|
||||
}
|
||||
|
@ -3,16 +3,18 @@ import { useCallback } from 'react'
|
||||
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
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[]
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function DepositedLendsTable(props: Props) {
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading, v1: props.v1 })
|
||||
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
|
||||
@ -23,10 +25,17 @@ export default function DepositedLendsTable(props: Props) {
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Lent Assets'
|
||||
title={props.v1 ? 'Deposits' : 'Lent Assets'}
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
||||
initialSorting={
|
||||
props.v1
|
||||
? [
|
||||
{ id: DEPOSIT_VALUE_META.id, desc: true },
|
||||
{ id: NAME_META.id, desc: false },
|
||||
]
|
||||
: [{ id: NAME_META.id, desc: false }]
|
||||
}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -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',
|
||||
@ -49,6 +49,7 @@ export default function DesktopHeader() {
|
||||
const isOracleStale = useStore((s) => s.isOracleStale)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const accountId = useAccountId()
|
||||
const showAccountMenu = address && !isHLS
|
||||
|
||||
function handleCloseFocusMode() {
|
||||
if (focusComponent && focusComponent.onClose) focusComponent.onClose()
|
||||
@ -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'>
|
||||
@ -92,7 +93,7 @@ export default function DesktopHeader() {
|
||||
<div className='flex gap-4'>
|
||||
{showStaleOracle && <OracleResyncButton />}
|
||||
{accountId && <RewardsCenter />}
|
||||
{address && !isHLS && <AccountMenu />}
|
||||
{showAccountMenu && <AccountMenu />}
|
||||
<Wallet />
|
||||
<ChainSelect />
|
||||
<Settings />
|
||||
|
81
src/components/header/V1DesktopHeader.tsx
Normal file
81
src/components/header/V1DesktopHeader.tsx
Normal 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
|
||||
|
@ -12,6 +12,7 @@ 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'
|
||||
|
||||
export default function Routes() {
|
||||
@ -32,6 +33,7 @@ export default function Routes() {
|
||||
<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 />} />}
|
||||
@ -47,6 +49,7 @@ export default function Routes() {
|
||||
<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>
|
||||
|
@ -17,6 +17,7 @@ import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'
|
||||
|
||||
interface Props {
|
||||
accountId: string
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
function Content(props: Props) {
|
||||
@ -74,21 +75,21 @@ function Content(props: Props) {
|
||||
title: (
|
||||
<FormattedNumber
|
||||
className='text-xl'
|
||||
amount={leverage.toNumber()}
|
||||
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()}
|
||||
options={{ suffix: 'x' }}
|
||||
/>
|
||||
),
|
||||
sub: DEFAULT_PORTFOLIO_STATS[4].sub,
|
||||
sub: props.v1 ? 'Total Leverage' : DEFAULT_PORTFOLIO_STATS[4].sub,
|
||||
},
|
||||
]
|
||||
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
|
||||
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, props.v1])
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
stats={stats}
|
||||
health={health}
|
||||
healthFactor={healthFactor}
|
||||
title={`Credit Account ${props.accountId}`}
|
||||
title={props.v1 ? 'V1 Portfolio' : `Credit Account ${props.accountId}`}
|
||||
accountId={props.accountId}
|
||||
/>
|
||||
)
|
||||
|
@ -89,7 +89,7 @@ export default function PortfolioSummary() {
|
||||
title: (
|
||||
<FormattedNumber
|
||||
className='text-xl'
|
||||
amount={leverage.toNumber()}
|
||||
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()}
|
||||
options={{ suffix: 'x' }}
|
||||
/>
|
||||
),
|
||||
|
47
src/components/v1/Borrowings.tsx
Normal file
47
src/components/v1/Borrowings.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import BorrowingsTable from 'components/borrow/Table/ActiveBorrowingsTable'
|
||||
import useV1BorrowingsTableData from 'components/v1/Table/useV1BorrowingsTableData'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
|
||||
|
||||
export default function Borrowings() {
|
||||
const { debtAssets } = useV1BorrowingsTableData()
|
||||
|
||||
if (!debtAssets?.length) {
|
||||
return <Fallback />
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<BorrowingsTable data={debtAssets} isLoading={false} v1 />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Fallback() {
|
||||
const assets = useBorrowEnabledAssets()
|
||||
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
||||
asset,
|
||||
apy: {
|
||||
borrow: 0,
|
||||
deposit: 0,
|
||||
},
|
||||
ltv: {
|
||||
max: 0,
|
||||
liq: 0,
|
||||
},
|
||||
liquidity: BN_ZERO,
|
||||
marketLiquidityRate: 0,
|
||||
cap: {
|
||||
denom: asset.denom,
|
||||
max: BN_ZERO,
|
||||
used: BN_ZERO,
|
||||
},
|
||||
debt: BN_ZERO,
|
||||
borrowEnabled: true,
|
||||
depositEnabled: true,
|
||||
deposits: BN_ZERO,
|
||||
accountDebt: BN_ZERO,
|
||||
}))
|
||||
|
||||
return <BorrowingsTable data={data} isLoading v1 />
|
||||
}
|
46
src/components/v1/Deposits.tsx
Normal file
46
src/components/v1/Deposits.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
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'
|
||||
|
||||
export default function Deposits() {
|
||||
const { depositAssets } = useV1DepositsTableData()
|
||||
|
||||
if (!depositAssets?.length) {
|
||||
return <Fallback />
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DepositsTable data={depositAssets} isLoading={false} v1 />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Fallback() {
|
||||
const assets = useMarketEnabledAssets()
|
||||
|
||||
const data: LendingMarketTableData[] = assets.map((asset) => ({
|
||||
asset,
|
||||
borrowEnabled: true,
|
||||
depositEnabled: true,
|
||||
debt: BN_ZERO,
|
||||
deposits: BN_ZERO,
|
||||
liquidity: BN_ZERO,
|
||||
cap: {
|
||||
max: BN_ZERO,
|
||||
used: BN_ZERO,
|
||||
denom: asset.denom,
|
||||
},
|
||||
apy: {
|
||||
borrow: 0,
|
||||
deposit: 0,
|
||||
},
|
||||
ltv: {
|
||||
max: 0,
|
||||
liq: 0,
|
||||
},
|
||||
}))
|
||||
|
||||
return <DepositsTable data={data} isLoading v1 />
|
||||
}
|
20
src/components/v1/Table/borrowings/Columns/Action.tsx
Normal file
20
src/components/v1/Table/borrowings/Columns/Action.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import BorrowButton from 'components/v1/Table/borrowings/Columns/BorrowButton'
|
||||
import Manage from 'components/v1/Table/borrowings/Columns/Manage'
|
||||
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function Action(props: Props) {
|
||||
const hasDebt = !props.data.accountDebtAmount?.isZero() ?? false
|
||||
|
||||
if (hasDebt) return <Manage data={props.data} />
|
||||
|
||||
return <BorrowButton data={props.data} />
|
||||
}
|
51
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
51
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { Plus } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
export default function BorrowButton(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
|
||||
const hasCollateral = account?.lends?.length ?? 0 > 0
|
||||
|
||||
return (
|
||||
<div className='flex justify-end'>
|
||||
<ConditionalWrapper
|
||||
condition={!hasCollateral}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have assets deposited in the Red Bank. Please deposit assets before you borrow.`}</Text>
|
||||
}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<Plus />}
|
||||
disabled={!hasCollateral}
|
||||
color='tertiary'
|
||||
onClick={(e) => {
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
|
||||
})
|
||||
e.stopPropagation()
|
||||
}}
|
||||
text='Borrow'
|
||||
short
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { HandCoins, Plus } from 'components/common/Icons'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: balances } = useWalletBalances(address)
|
||||
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <Plus />,
|
||||
text: 'Borrow more',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
|
||||
}),
|
||||
},
|
||||
{
|
||||
icon: <HandCoins />,
|
||||
text: 'Repay',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1BorrowAndRepayModal: { type: 'repay', data: props.data },
|
||||
}),
|
||||
disabled: !hasBalance,
|
||||
disabledTooltip: `You don’t have any ${props.data.asset.symbol} in your Wallet.`,
|
||||
},
|
||||
],
|
||||
[hasBalance, props.data],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||
</div>
|
||||
)
|
||||
}
|
19
src/components/v1/Table/deposits/Columns/Action.tsx
Normal file
19
src/components/v1/Table/deposits/Columns/Action.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import DepositButton from 'components/v1/Table/deposits/Columns/DepositButton'
|
||||
import Manage from 'components/v1/Table/deposits/Columns/Manage'
|
||||
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
export default function Action(props: Props) {
|
||||
const hasDeposits = !props.data.accountLentAmount?.isZero() ?? false
|
||||
|
||||
if (hasDeposits) return <Manage data={props.data} />
|
||||
|
||||
return <DepositButton data={props.data} />
|
||||
}
|
51
src/components/v1/Table/deposits/Columns/DepositButton.tsx
Normal file
51
src/components/v1/Table/deposits/Columns/DepositButton.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { ArrowUpLine } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
export default function DepositButton(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: balances } = useWalletBalances(address)
|
||||
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
|
||||
|
||||
return (
|
||||
<div className='flex justify-end'>
|
||||
<ConditionalWrapper
|
||||
condition={!hasBalance}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have any ${props.data.asset.symbol} in your Wallet.`}</Text>
|
||||
}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<ArrowUpLine />}
|
||||
disabled={!hasBalance}
|
||||
color='tertiary'
|
||||
onClick={(e) => {
|
||||
useStore.setState({
|
||||
v1DepositAndWithdrawModal: { type: 'deposit', data: props.data },
|
||||
})
|
||||
e.stopPropagation()
|
||||
}}
|
||||
text='Deposit'
|
||||
short
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
48
src/components/v1/Table/deposits/Columns/Manage.tsx
Normal file
48
src/components/v1/Table/deposits/Columns/Manage.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { ArrowDownLine, ArrowUpLine } from 'components/common/Icons'
|
||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: balances } = useWalletBalances(address)
|
||||
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <ArrowUpLine />,
|
||||
text: 'Deposit more',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1DepositAndWithdrawModal: { type: 'deposit', data: props.data },
|
||||
}),
|
||||
disabled: !hasBalance,
|
||||
disabledTooltip: `You don’t have any ${props.data.asset.symbol} in your Wallet.`,
|
||||
},
|
||||
{
|
||||
icon: <ArrowDownLine />,
|
||||
text: 'Withdraw',
|
||||
onClick: () =>
|
||||
useStore.setState({
|
||||
v1DepositAndWithdrawModal: { type: 'withdraw', data: props.data },
|
||||
}),
|
||||
},
|
||||
],
|
||||
[hasBalance, props.data],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||
</div>
|
||||
)
|
||||
}
|
38
src/components/v1/Table/useV1BorrowingsTableData.ts
Normal file
38
src/components/v1/Table/useV1BorrowingsTableData.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function useV1BorrowingsTableData() {
|
||||
const address = useStore((s) => s.address)
|
||||
const markets = useMarkets()
|
||||
const { data: v1Positions } = useAccount(address)
|
||||
const { convertAmount } = useDisplayCurrencyPrice()
|
||||
|
||||
return useMemo((): {
|
||||
debtAssets: BorrowMarketTableData[]
|
||||
} => {
|
||||
const userDebts = v1Positions?.debts ?? []
|
||||
const debtAssets: BorrowMarketTableData[] = []
|
||||
|
||||
markets
|
||||
.filter((market) => market.borrowEnabled)
|
||||
.forEach((market) => {
|
||||
const amount =
|
||||
userDebts.find((debt) => debt.denom === market.asset.denom)?.amount ?? BN_ZERO
|
||||
const value = amount ? convertAmount(market.asset, amount) : undefined
|
||||
|
||||
const borrowMarketAsset: BorrowMarketTableData = {
|
||||
...market,
|
||||
accountDebtAmount: amount,
|
||||
accountDebtValue: value,
|
||||
}
|
||||
debtAssets.push(borrowMarketAsset)
|
||||
})
|
||||
|
||||
return { debtAssets }
|
||||
}, [v1Positions, markets, convertAmount])
|
||||
}
|
39
src/components/v1/Table/useV1DepositsTableData.ts
Normal file
39
src/components/v1/Table/useV1DepositsTableData.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export default function useV1DepositsTableData(): {
|
||||
depositAssets: LendingMarketTableData[]
|
||||
} {
|
||||
const address = useStore((s) => s.address)
|
||||
const markets = useMarkets()
|
||||
const { data: v1Positions } = useAccount(address)
|
||||
const { convertAmount } = useDisplayCurrencyPrice()
|
||||
|
||||
return useMemo(() => {
|
||||
const depositAssets: LendingMarketTableData[] = []
|
||||
const userCollateral = v1Positions?.lends ?? []
|
||||
|
||||
markets.forEach((market) => {
|
||||
const amount = userCollateral.find(byDenom(market.asset.denom))?.amount ?? BN_ZERO
|
||||
const value = amount ? convertAmount(market.asset, amount) : undefined
|
||||
|
||||
const lendingMarketAsset: LendingMarketTableData = {
|
||||
...market,
|
||||
accountLentValue: value,
|
||||
accountLentAmount: amount,
|
||||
}
|
||||
|
||||
depositAssets.push(lendingMarketAsset)
|
||||
})
|
||||
|
||||
return {
|
||||
depositAssets,
|
||||
}
|
||||
}, [markets, v1Positions, convertAmount])
|
||||
}
|
24
src/components/v1/V1Intro.tsx
Normal file
24
src/components/v1/V1Intro.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
|
||||
import Intro from 'components/common/Intro'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function V1Intro() {
|
||||
const address = useStore((state) => state.address)
|
||||
return (
|
||||
<Intro
|
||||
text={
|
||||
<>
|
||||
<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‘t be used on v2 as collateral.
|
||||
</>
|
||||
}
|
||||
bg='v1'
|
||||
>
|
||||
{!address && <WalletConnectButton className='mt-4' />}
|
||||
</Intro>
|
||||
)
|
||||
}
|
16
src/configs/assets/stkATOM.ts
Normal file
16
src/configs/assets/stkATOM.ts
Normal 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
src/configs/assets/wstETH.ts
Normal file
18
src/configs/assets/wstETH.ts
Normal 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
src/configs/chains/neutron/neutron-1.ts
Normal file
86
src/configs/chains/neutron/neutron-1.ts
Normal 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
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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,14 +1,22 @@
|
||||
import useSWR from 'swr'
|
||||
|
||||
import getAccount from 'api/accounts/getAccount'
|
||||
import getV1Positions from 'api/v1/getV1Positions'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function useAccount(accountId?: string, suspense?: boolean) {
|
||||
const chainConfig = useChainConfig()
|
||||
const address = useStore((s) => s.address)
|
||||
const isV1 = accountId === address
|
||||
|
||||
const cacheKey = isV1
|
||||
? `chains/${chainConfig.id}/v1/user/${accountId}`
|
||||
: `chains/${chainConfig.id}/accounts/${accountId}`
|
||||
|
||||
return useSWR(
|
||||
accountId && `chains/${chainConfig.id}/accounts/${accountId}`,
|
||||
() => getAccount(chainConfig, accountId),
|
||||
accountId && cacheKey,
|
||||
() => (isV1 ? getV1Positions(chainConfig, accountId) : getAccount(chainConfig, accountId)),
|
||||
{
|
||||
suspense: suspense,
|
||||
revalidateOnFocus: false,
|
||||
|
@ -11,6 +11,7 @@ import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.cl
|
||||
import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client'
|
||||
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
|
||||
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
|
||||
import { getUrl } from 'utils/url'
|
||||
|
||||
export default function useClients() {
|
||||
const chainConfig = useChainConfig()
|
||||
@ -18,8 +19,7 @@ export default function useClients() {
|
||||
const swr = useSWR(
|
||||
`chains/${chainConfig.id}/clients`,
|
||||
async () => {
|
||||
const client = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
|
||||
|
||||
const client = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||
return {
|
||||
creditManager: new MarsCreditManagerQueryClient(
|
||||
client,
|
||||
|
@ -1,11 +1,9 @@
|
||||
import Borrowings from 'components/borrow/Borrowings'
|
||||
import BorrowIntro from 'components/borrow/BorrowIntro'
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
|
||||
export default function BorrowPage() {
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-6'>
|
||||
<MigrationBanner />
|
||||
<BorrowIntro />
|
||||
<Borrowings />
|
||||
</div>
|
||||
|
@ -1,13 +1,11 @@
|
||||
import Tab from 'components/earn/Tab'
|
||||
import FarmIntro from 'components/earn/farm/FarmIntro'
|
||||
import Vaults from 'components/earn/farm/Vaults'
|
||||
import Tab from 'components/earn/Tab'
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
import { EARN_TABS } from 'constants/pages'
|
||||
|
||||
export default function FarmPage() {
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-6'>
|
||||
<MigrationBanner />
|
||||
<Tab tabs={EARN_TABS} activeTabIdx={1} />
|
||||
<FarmIntro />
|
||||
<Vaults />
|
||||
|
@ -1,13 +1,11 @@
|
||||
import Tab from 'components/earn/Tab'
|
||||
import AvailableHLSVaults from 'components/hls/Farm/AvailableHLSVaults'
|
||||
import HlsFarmIntro from 'components/hls/Farm/HLSFarmIntro'
|
||||
import MigrationBanner from 'components/common/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={1} />
|
||||
<HlsFarmIntro />
|
||||
<AvailableHLSVaults />
|
||||
|
@ -2,13 +2,11 @@ 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'
|
||||
import MigrationBanner from 'components/common/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={0} />
|
||||
<HLSStakingIntro />
|
||||
<AvailableHlsStakingAssets />
|
||||
|
@ -1,4 +1,3 @@
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
import Tab from 'components/earn/Tab'
|
||||
import LendIntro from 'components/earn/lend/LendIntro'
|
||||
import Lends from 'components/earn/lend/Lends'
|
||||
@ -10,7 +9,6 @@ export default function LendPage() {
|
||||
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-6'>
|
||||
<MigrationBanner />
|
||||
{chainConfig.farm && <Tab tabs={EARN_TABS} activeTabIdx={0} />}
|
||||
<LendIntro />
|
||||
<Lends />
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
import ShareBar from 'components/common/ShareBar'
|
||||
import Balances from 'components/portfolio/Account/Balances'
|
||||
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
||||
@ -25,7 +24,6 @@ export default function PortfolioAccountPage() {
|
||||
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-6'>
|
||||
<MigrationBanner />
|
||||
<BreadCrumbs accountId={accountId} />
|
||||
<Summary accountId={accountId} />
|
||||
<Balances accountId={accountId} />
|
||||
|
@ -1,13 +1,11 @@
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
import ShareBar from 'components/common/ShareBar'
|
||||
import AccountOverview from 'components/portfolio/Overview'
|
||||
import PortfolioSummary from 'components/portfolio/Overview/Summary'
|
||||
import PortfolioIntro from 'components/portfolio/PortfolioIntro'
|
||||
import ShareBar from 'components/common/ShareBar'
|
||||
|
||||
export default function PortfolioPage() {
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-6'>
|
||||
<MigrationBanner />
|
||||
<PortfolioIntro />
|
||||
<PortfolioSummary />
|
||||
<AccountOverview />
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import MigrationBanner from 'components/common/MigrationBanner'
|
||||
import AccountDetailsCard from 'components/trade/AccountDetailsCard'
|
||||
import TradeChart from 'components/trade/TradeChart'
|
||||
import TradeModule from 'components/trade/TradeModule'
|
||||
@ -47,7 +46,6 @@ export default function TradePage() {
|
||||
)
|
||||
return (
|
||||
<div className='flex flex-col w-full h-full gap-4'>
|
||||
<MigrationBanner />
|
||||
<div className='grid w-full grid-cols-[auto_346px] gap-4'>
|
||||
<TradeChart buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<TradeModule buyAsset={buyAsset} sellAsset={sellAsset} isAdvanced={isAdvanced} />
|
||||
|
19
src/pages/V1Page.tsx
Normal file
19
src/pages/V1Page.tsx
Normal 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>
|
||||
)
|
||||
}
|
@ -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)]',
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
ExecuteMsg as CreditManagerExecuteMsg,
|
||||
ExecuteMsg,
|
||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { ExecuteMsg as RedBankExecuteMsg } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
import { AccountKind } from 'types/generated/mars-rover-health-types/MarsRoverHealthTypes.types'
|
||||
import { byDenom, bySymbol } from 'utils/array'
|
||||
import { generateErrorMessage, getSingleValueFromBroadcastResult } from 'utils/broadcast'
|
||||
@ -30,7 +31,7 @@ import { getVaultDepositCoinsFromActions } from 'utils/vaults'
|
||||
function generateExecutionMessage(
|
||||
sender: string | undefined = '',
|
||||
contract: string,
|
||||
msg: CreditManagerExecuteMsg | AccountNftExecuteMsg | PythUpdateExecuteMsg,
|
||||
msg: CreditManagerExecuteMsg | AccountNftExecuteMsg | RedBankExecuteMsg | PythUpdateExecuteMsg,
|
||||
funds: Coin[],
|
||||
) {
|
||||
return new MsgExecuteContract({
|
||||
@ -1065,5 +1066,69 @@ export default function createBroadcastSlice(
|
||||
{ denom: get().chainConfig.assets[0].denom, amount: String(pythAssets.length) },
|
||||
])
|
||||
},
|
||||
v1Action: async (type: V1ActionType, coin: BNCoin) => {
|
||||
let msg: RedBankExecuteMsg
|
||||
let toastOptions: ToastObjectOptions = {
|
||||
action: type,
|
||||
accountId: get().address,
|
||||
changes: {},
|
||||
}
|
||||
let funds: Coin[] = []
|
||||
|
||||
switch (type) {
|
||||
case 'withdraw':
|
||||
msg = {
|
||||
withdraw: {
|
||||
amount: coin.amount.toString(),
|
||||
denom: coin.denom,
|
||||
},
|
||||
}
|
||||
toastOptions = {
|
||||
...toastOptions,
|
||||
changes: { deposits: [coin] },
|
||||
target: 'wallet',
|
||||
}
|
||||
break
|
||||
case 'repay':
|
||||
msg = {
|
||||
repay: {},
|
||||
}
|
||||
toastOptions.changes = { deposits: [coin] }
|
||||
funds = [coin.toCoin()]
|
||||
break
|
||||
case 'borrow':
|
||||
msg = {
|
||||
borrow: {
|
||||
amount: coin.amount.toString(),
|
||||
denom: coin.denom,
|
||||
},
|
||||
}
|
||||
toastOptions = {
|
||||
...toastOptions,
|
||||
changes: { debts: [coin] },
|
||||
target: 'wallet',
|
||||
}
|
||||
break
|
||||
default:
|
||||
msg = {
|
||||
deposit: {},
|
||||
}
|
||||
toastOptions.changes = { deposits: [coin] }
|
||||
funds = [coin.toCoin()]
|
||||
}
|
||||
|
||||
const redBankContract = get().chainConfig.contracts.redBank
|
||||
|
||||
const response = get().executeMsg({
|
||||
messages: [generateExecutionMessage(get().address, redBankContract, msg, funds)],
|
||||
})
|
||||
|
||||
get().setToast({
|
||||
response,
|
||||
options: toastOptions,
|
||||
})
|
||||
|
||||
return response.then((response) => !!response.result)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,6 @@ export default function createCommonSlice(set: SetState<CommonSlice>, get: GetSt
|
||||
useAutoRepay: true,
|
||||
isOracleStale: false,
|
||||
isHLS: false,
|
||||
isV1: false,
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,7 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
|
||||
vaultModal: null,
|
||||
walletAssetsModal: null,
|
||||
withdrawFromVaultsModal: null,
|
||||
v1DepositAndWithdrawModal: null,
|
||||
v1BorrowAndRepayModal: null,
|
||||
}
|
||||
}
|
||||
|
3
src/types/interfaces/market.d.ts
vendored
3
src/types/interfaces/market.d.ts
vendored
@ -17,7 +17,8 @@ interface Market {
|
||||
}
|
||||
|
||||
interface BorrowMarketTableData extends Market {
|
||||
accountDebt?: BigNumber
|
||||
accountDebtAmount?: BigNumber
|
||||
accountDebtValue?: BigNumber
|
||||
}
|
||||
|
||||
interface LendingMarketTableData extends Market {
|
||||
|
1
src/types/interfaces/route.d.ts
vendored
1
src/types/interfaces/route.d.ts
vendored
@ -11,6 +11,7 @@ type Page =
|
||||
| 'hls-staking'
|
||||
| 'governance'
|
||||
| 'execute'
|
||||
| 'v1'
|
||||
|
||||
type OsmosisRouteResponse = {
|
||||
amount_in: {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user