├── .gitignore ├── package.json ├── public ├── assets │ └── images │ │ ├── download.png │ │ ├── ethereum.png │ │ ├── logo.png │ │ ├── test-powerer-brand.png │ │ └── usdc.png ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.test.tsx ├── App.tsx ├── Routes.tsx ├── components │ ├── CardsField.tsx │ ├── LiquidateDialog.tsx │ ├── Loading.tsx │ ├── PageHeader.tsx │ ├── ProgressBar.tsx │ ├── Section.tsx │ ├── boards │ │ ├── CollapsibleBoard.tsx │ │ └── PrimaryBoard.tsx │ ├── buttons │ │ ├── FilledButton.tsx │ │ ├── OutlinedButton.tsx │ │ ├── TextButton.tsx │ │ └── TextIconButton.tsx │ ├── cards │ │ └── InfoCard.tsx │ ├── containers │ │ └── Container.tsx │ ├── dialogs │ │ └── CustomDialog.tsx │ ├── form │ │ ├── MainInput.tsx │ │ ├── MainSelect.tsx │ │ ├── SelectChain.tsx │ │ ├── SelectLP.tsx │ │ ├── SelectTokenWithDetail.tsx │ │ └── SelectTokenWithPrice.tsx │ └── tableComponents │ │ ├── Table.tsx │ │ ├── Td.tsx │ │ ├── Th.tsx │ │ └── Tr.tsx ├── contexts │ ├── AlertMessageContext.tsx │ ├── DialogSizeContext.tsx │ ├── LoadingContext.tsx │ └── MobileMenuContext.tsx ├── hooks │ ├── useAlertMessage.tsx │ ├── useDialogSize.tsx │ ├── useLoading.ts │ └── useMobileMenu.ts ├── index.css ├── index.tsx ├── layouts │ └── LandingLayout │ │ ├── Footer.tsx │ │ ├── Navbar.tsx │ │ └── index.tsx ├── pages │ ├── Blank.tsx │ ├── Bridge │ │ └── index.tsx │ ├── Dashboard │ │ ├── AccountStatusSection.tsx │ │ ├── DialogClaimPeko.tsx │ │ ├── FarmsSection.tsx │ │ ├── LPTokensSection.tsx │ │ ├── PekoSection │ │ │ ├── ClaimPekoDialog.tsx │ │ │ └── index.tsx │ │ ├── ProfitSection │ │ │ ├── ClaimProfitDialog.tsx │ │ │ ├── DPRow.tsx │ │ │ ├── MBRow.tsx │ │ │ └── index.tsx │ │ ├── TokensSection │ │ │ ├── DPRow.tsx │ │ │ ├── MBRow.tsx │ │ │ └── index.tsx │ │ ├── UserProfileSection │ │ │ ├── LiquidationsBoard │ │ │ │ ├── Row.tsx │ │ │ │ └── index.tsx │ │ │ ├── UserReservesBoard │ │ │ │ ├── Row.tsx │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ └── index.tsx │ ├── Lending │ │ ├── AssetDialog │ │ │ ├── BorrowTab.tsx │ │ │ ├── DepositTab.tsx │ │ │ ├── MoreInfo.tsx │ │ │ ├── RepayTab.tsx │ │ │ ├── WithdrawTab.tsx │ │ │ └── index.tsx │ │ ├── BorrowBoard │ │ │ ├── Position.tsx │ │ │ └── index.tsx │ │ ├── DPRow.tsx │ │ ├── DepositBoard │ │ │ ├── Position.tsx │ │ │ └── index.tsx │ │ ├── MBRow.tsx │ │ └── index.tsx │ ├── Liquidate │ │ ├── DPRow.tsx │ │ ├── MBRow.tsx │ │ └── index.tsx │ ├── Swap │ │ ├── BorrowPanel.tsx │ │ └── index.tsx │ └── Trading │ │ ├── BidCard.tsx │ │ ├── BuySellCard.tsx │ │ ├── MarketCard.tsx │ │ ├── OrdersCard.tsx │ │ └── index.tsx ├── react-app-env.d.ts ├── reportWebVitals.ts ├── service-worker.ts ├── serviceWorkerRegistration.ts ├── setupTests.ts └── utils │ ├── constants.ts │ ├── functions.ts │ ├── interfaces.ts │ └── types.ts ├── tailwind.config.js ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "peko-protocol-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-tailwind/react": "^2.0.1", 7 | "@testing-library/jest-dom": "^5.16.5", 8 | "@testing-library/react": "^13.4.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "@types/jest": "^27.5.2", 11 | "@types/node": "^17.0.45", 12 | "@types/react": "^18.2.6", 13 | "@types/react-dom": "^18.2.4", 14 | "@web3modal/ethereum": "^2.7.0", 15 | "@web3modal/react": "^2.7.0", 16 | "chart.js": "^4.3.0", 17 | "framer-motion": "^10.12.16", 18 | "rc-slider": "^10.2.0", 19 | "react": "^18.2.0", 20 | "react-chartjs-2": "^5.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-responsive": "^9.0.2", 23 | "react-router-dom": "^6.11.2", 24 | "react-scripts": "5.0.1", 25 | "react-toastify": "^9.1.3", 26 | "typescript": "^4.9.5", 27 | "usehooks-ts": "^2.9.1", 28 | "viem": "^1.3.0", 29 | "wagmi": "^1.3.9", 30 | "web-vitals": "^2.1.4", 31 | "workbox-background-sync": "^6.5.4", 32 | "workbox-broadcast-update": "^6.5.4", 33 | "workbox-cacheable-response": "^6.5.4", 34 | "workbox-core": "^6.5.4", 35 | "workbox-expiration": "^6.5.4", 36 | "workbox-google-analytics": "^6.5.4", 37 | "workbox-navigation-preload": "^6.5.4", 38 | "workbox-precaching": "^6.5.4", 39 | "workbox-range-requests": "^6.5.4", 40 | "workbox-routing": "^6.5.4", 41 | "workbox-strategies": "^6.5.4", 42 | "workbox-streams": "^6.5.4" 43 | }, 44 | "scripts": { 45 | "start": "react-scripts start", 46 | "build": "react-scripts build", 47 | "test": "react-scripts test", 48 | "eject": "react-scripts eject" 49 | }, 50 | "eslintConfig": { 51 | "extends": [ 52 | "react-app", 53 | "react-app/jest" 54 | ] 55 | }, 56 | "browserslist": { 57 | "production": [ 58 | "chrome >= 67", 59 | "edge >= 79", 60 | "firefox >= 68", 61 | "opera >= 54", 62 | "safari >= 14" 63 | ], 64 | "development": [ 65 | "last 1 chrome version", 66 | "last 1 firefox version", 67 | "last 1 safari version" 68 | ] 69 | }, 70 | "devDependencies": { 71 | "@iconify/react": "^4.1.0", 72 | "tailwindcss": "^3.3.2" 73 | } 74 | } -------------------------------------------------------------------------------- /public/assets/images/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/assets/images/download.png -------------------------------------------------------------------------------- /public/assets/images/ethereum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/assets/images/ethereum.png -------------------------------------------------------------------------------- /public/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/assets/images/logo.png -------------------------------------------------------------------------------- /public/assets/images/test-powerer-brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/assets/images/test-powerer-brand.png -------------------------------------------------------------------------------- /public/assets/images/usdc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/assets/images/usdc.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Peko Protocol 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybersage14/PekoProtocolFrontend-React/3296ef973ea6a0a7919accaa55f34ac9f217eba2/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import { BrowserRouter } from 'react-router-dom'; 3 | import { createConfig, WagmiConfig } from 'wagmi'; 4 | import { EthereumClient, w3mConnectors } from '@web3modal/ethereum'; 5 | import { Web3Modal } from '@web3modal/react'; 6 | import { lineaTestnet } from 'wagmi/chains'; 7 | import { ToastContainer } from 'react-toastify'; 8 | import { createPublicClient, http } from 'viem'; 9 | import Loading from './components/Loading'; 10 | import { LoadingProvider } from './contexts/LoadingContext'; 11 | import { MobileMenuProvider } from './contexts/MobileMenuContext'; 12 | import Routes from './Routes'; 13 | import { DialogSizeProvider } from './contexts/DialogSizeContext'; 14 | 15 | // ----------------------------------------------------------------------------------------------- 16 | 17 | const projectId = process.env.REACT_APP_CONNECT_PROJECT_ID || '' 18 | const chains = [lineaTestnet] 19 | const wagmiConfig = createConfig({ 20 | autoConnect: true, 21 | connectors: w3mConnectors({ projectId, chains }), 22 | publicClient: createPublicClient({ 23 | chain: lineaTestnet, 24 | transport: http() 25 | }) 26 | }) 27 | const ethereumClient = new EthereumClient(wagmiConfig, chains) 28 | 29 | // ----------------------------------------------------------------------------------------------- 30 | 31 | function App() { 32 | return ( 33 | 34 | }> 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ); 49 | } 50 | 51 | export default App; 52 | -------------------------------------------------------------------------------- /src/Routes.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from "react"; 2 | import { Navigate, useRoutes } from "react-router-dom"; 3 | import Blank from "./pages/Blank"; 4 | import { useAccount } from "wagmi"; 5 | 6 | // ---------------------------------------------------------------------------------- 7 | 8 | const LandingLayout = lazy(() => import('./layouts/LandingLayout')) 9 | const Lending = lazy(() => import('./pages/Lending')) 10 | const Liquidate = lazy(() => import('./pages/Liquidate')) 11 | const Swap = lazy(() => import('./pages/Swap')) 12 | const Dashboard = lazy(() => import('./pages/Dashboard')) 13 | // const Bridge = lazy(() => import('./pages/Bridge')) 14 | // const Trading = lazy(() => import('./pages/Trading')) 15 | 16 | // ---------------------------------------------------------------------------------- 17 | 18 | export default function Routes() { 19 | const { isConnected } = useAccount() 20 | return useRoutes([ 21 | { 22 | element: , 23 | path: '/', 24 | children: [ 25 | { 26 | path: 'lending', 27 | element: 28 | }, 29 | { 30 | path: 'liquidate', 31 | element: 32 | }, 33 | // { 34 | // path: 'swap', 35 | // element: 36 | // }, 37 | // { 38 | // path: 'bridge', 39 | // element: 40 | // }, 41 | { 42 | path: 'dashboard', 43 | element: isConnected ? : 44 | }, 45 | // { 46 | // path: 'trading', 47 | // element: 48 | // }, 49 | { 50 | path: '/', 51 | element: 52 | }, 53 | { 54 | path: '404', 55 | element: 56 | }, 57 | { 58 | path: '*', 59 | element: 60 | } 61 | ] 62 | } 63 | ]) 64 | } -------------------------------------------------------------------------------- /src/components/CardsField.tsx: -------------------------------------------------------------------------------- 1 | import { IPropsOfComponent } from "../utils/interfaces"; 2 | 3 | export default function CardsField({ children }: IPropsOfComponent) { 4 | return ( 5 |
6 |
7 | {children} 8 |
9 |
10 | ) 11 | } -------------------------------------------------------------------------------- /src/components/Loading.tsx: -------------------------------------------------------------------------------- 1 | export default function Loading() { 2 | return ( 3 |
4 |
5 | 9 |

Loading...

10 |
11 |
12 | ) 13 | } -------------------------------------------------------------------------------- /src/components/PageHeader.tsx: -------------------------------------------------------------------------------- 1 | import { IPropsOfComponent } from "../utils/interfaces"; 2 | import Container from "./containers/Container"; 3 | 4 | interface IProps extends IPropsOfComponent { 5 | title: string; 6 | description: string; 7 | } 8 | 9 | export default function PageHeader({ className = '', title, description }: IProps) { 10 | return ( 11 |
12 | 13 |

{title}

14 |

{description}

15 |
16 |
17 | ) 18 | } -------------------------------------------------------------------------------- /src/components/ProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { Progress } from '@material-tailwind/react' 3 | import { IPropsOfComponent } from "../utils/interfaces"; 4 | import { color } from '@material-tailwind/react/types/components/progress'; 5 | 6 | // ----------------------------------------------------------------------------------- 7 | 8 | interface IProps extends IPropsOfComponent { 9 | label: string; 10 | value: number; 11 | valueNode?: ReactNode; 12 | color?: color; 13 | } 14 | 15 | // ----------------------------------------------------------------------------------- 16 | 17 | export default function ProgressBar({ label, value, valueNode, children, color = 'blue', ...others }: IProps) { 18 | return ( 19 |
20 |
21 | {label} 22 | {valueNode || <>} 23 |
24 | 25 |
26 | ) 27 | } -------------------------------------------------------------------------------- /src/components/Section.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { IPropsOfComponent } from "../utils/interfaces"; 3 | 4 | interface IProps extends IPropsOfComponent { 5 | title: string; 6 | action?: ReactNode; 7 | } 8 | 9 | export default function Section({ className = '', children, title, action, ...others }: IProps) { 10 | return ( 11 |
12 |
13 |

{title}

14 | {action && <>{action}} 15 |
16 | {children} 17 |
18 | ) 19 | } -------------------------------------------------------------------------------- /src/components/boards/CollapsibleBoard.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { IPropsOfComponent } from "../../utils/interfaces"; 3 | import TextIconButton from '../buttons/TextIconButton'; 4 | import { Icon } from '@iconify/react'; 5 | 6 | // ---------------------------------------------------------------------------------------- 7 | 8 | interface IProps extends IPropsOfComponent { 9 | title: string; 10 | collapsible: boolean; 11 | } 12 | 13 | // ---------------------------------------------------------------------------------------- 14 | 15 | export default function CollapsibleBoard({ className = '', title = '', collapsible = false, children }: IProps) { 16 | const [collapsed, setCollapsed] = useState(false) 17 | 18 | return ( 19 |
20 |
21 |

{title}

22 | {collapsible && ( 23 | setCollapsed(!collapsed)}> 24 | {collapsed ? ( 25 | 26 | ) : ( 27 | 28 | )} 29 | 30 | )} 31 |
32 | 33 | {collapsed ? <> : ( 34 |
35 | {children} 36 |
37 | )} 38 |
39 | ) 40 | } -------------------------------------------------------------------------------- /src/components/boards/PrimaryBoard.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { IPropsOfComponent } from "../../utils/interfaces"; 3 | 4 | // ---------------------------------------------------------------------------------------- 5 | 6 | interface IProps extends IPropsOfComponent { 7 | title: string; 8 | action?: ReactNode; 9 | } 10 | 11 | // ---------------------------------------------------------------------------------------- 12 | 13 | export default function PrimaryBoard({ className = '', title = '', action, children }: IProps) { 14 | 15 | return ( 16 |
17 |
18 |

{title}

19 | {action || <>} 20 |
21 |
22 | {children} 23 |
24 |
25 | ) 26 | } -------------------------------------------------------------------------------- /src/components/buttons/FilledButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@material-tailwind/react'; 2 | import { IPropsOfComponent } from '../../utils/interfaces'; 3 | 4 | export default function FilledButton({ className = '', children, ...others }: IPropsOfComponent) { 5 | return ( 6 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/components/buttons/OutlinedButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@material-tailwind/react' 2 | import { IPropsOfComponent } from '../../utils/interfaces' 3 | 4 | export default function OutlinedButton({ className = '', children, ...others }: IPropsOfComponent) { 5 | return ( 6 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/components/buttons/TextButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@material-tailwind/react"; 2 | import { IPropsOfComponent } from "../../utils/interfaces"; 3 | 4 | export default function TextButton({ className = '', children, ...others }: IPropsOfComponent) { 5 | return ( 6 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/components/buttons/TextIconButton.tsx: -------------------------------------------------------------------------------- 1 | import { IconButton } from '@material-tailwind/react' 2 | import { IPropsOfComponent } from '../../utils/interfaces' 3 | 4 | export default function TextIconButton({ className = '', children, ...others }: IPropsOfComponent) { 5 | return ( 6 | 11 | {children} 12 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/components/cards/InfoCard.tsx: -------------------------------------------------------------------------------- 1 | interface IProps { 2 | label: string; 3 | value: string | number; 4 | unit?: string; 5 | className?: string; 6 | } 7 | 8 | export default function InfoCard({ label = '', value = '', unit = '', className = '' }: IProps) { 9 | return ( 10 |
11 | {label}: 12 | {unit}{value} 13 |
14 | ) 15 | } -------------------------------------------------------------------------------- /src/components/containers/Container.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | interface IProps { 4 | className?: string; 5 | children: ReactNode; 6 | } 7 | 8 | export default function Container({ className = '', children }: IProps) { 9 | return ( 10 |
11 | {children} 12 |
13 | ) 14 | } -------------------------------------------------------------------------------- /src/components/dialogs/CustomDialog.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { Dialog, DialogBody, DialogHeader } from "@material-tailwind/react"; 3 | import useDialogSize from "../../hooks/useDialogSize"; 4 | import { IPropsOfComponent } from "../../utils/interfaces"; 5 | import { Icon } from "@iconify/react"; 6 | import TextIconButton from "../buttons/TextIconButton"; 7 | 8 | interface IProps extends IPropsOfComponent { 9 | title: string | ReactNode; 10 | visible: boolean; 11 | setVisible: Function; 12 | } 13 | 14 | export default function CustomDialog({ title = '', visible, setVisible, children }: IProps) { 15 | const { dialogSize } = useDialogSize() 16 | 17 | const closeDialog = () => { 18 | setVisible(false) 19 | } 20 | 21 | const handleVisible = () => { 22 | setVisible(!visible) 23 | } 24 | 25 | return ( 26 | 27 | 28 |
{title}
29 | 30 | 31 | 32 |
33 | 34 | {children} 35 | 36 |
37 | ) 38 | } -------------------------------------------------------------------------------- /src/components/form/MainInput.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { IPropsOfComponent } from '../../utils/interfaces'; 3 | 4 | /* --------------------------------------------------------------------------- */ 5 | 6 | interface IProps extends IPropsOfComponent { 7 | classNameOfInput?: string; 8 | startAdornment?: ReactNode; 9 | endAdornment?: ReactNode; 10 | error?: boolean; 11 | } 12 | 13 | /* --------------------------------------------------------------------------- */ 14 | 15 | export default function MainInput({ className = '', classNameOfInput = '', startAdornment, endAdornment, error, ...others }: IProps) { 16 | return ( 17 |
20 | {startAdornment ? ( 21 |
{startAdornment}
22 | ) : (<>)} 23 | 27 | {endAdornment ? ( 28 |
{endAdornment}
29 | ) : (<>)} 30 |
31 | ); 32 | } -------------------------------------------------------------------------------- /src/components/form/MainSelect.tsx: -------------------------------------------------------------------------------- 1 | import { Icon } from "@iconify/react"; 2 | import { useOnClickOutside } from 'usehooks-ts'; 3 | import { IOption, IPropsOfComponent } from "../../utils/interfaces"; 4 | import { useRef, useState } from "react"; 5 | 6 | // -------------------------------------------------------------------------------- 7 | 8 | interface IProps extends IPropsOfComponent { 9 | options: Array; 10 | selectedOption: IOption; 11 | setSelectedOption: Function; 12 | } 13 | 14 | // -------------------------------------------------------------------------------- 15 | 16 | export default function MainSelect({ className = '', options, selectedOption, setSelectedOption, ...others }: IProps) { 17 | const ref = useRef(null) 18 | const [listVisible, setListVisible] = useState(false) 19 | 20 | useOnClickOutside(ref, () => setListVisible(false)) 21 | 22 | const handleSelectOption = (_option: IOption) => { 23 | setSelectedOption(_option) 24 | setListVisible(false) 25 | } 26 | 27 | return ( 28 |
29 |
setListVisible(!listVisible)} 32 | {...others} 33 | > 34 | {selectedOption.label} 35 | 39 |
40 | {listVisible && ( 41 |
42 | {options.map(optionItem => ( 43 |

handleSelectOption(optionItem)} 47 | > 48 | {optionItem.label} 49 |

50 | ))} 51 |
52 | )} 53 |
54 | 55 | ) 56 | } -------------------------------------------------------------------------------- /src/components/form/SelectChain.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import { Icon } from "@iconify/react"; 3 | import { useOnClickOutside } from 'usehooks-ts' 4 | import { IPropsOfComponent, IChain } from "../../utils/interfaces"; 5 | 6 | // ------------------------------------------------------------------------------------------------------- 7 | 8 | interface IProps extends IPropsOfComponent { 9 | chains: Array; 10 | selectedChain: IChain | null; 11 | setSelectedChain: Function; 12 | } 13 | 14 | // ------------------------------------------------------------------------------------------------------- 15 | 16 | export default function SelectChain({ className = '', chains, selectedChain, setSelectedChain, ...others }: IProps) { 17 | const ref = useRef(null) 18 | const [listVisible, setListVisible] = useState(false) 19 | 20 | useOnClickOutside(ref, () => setListVisible(false)) 21 | 22 | const handleSelectChain = (chain: IChain) => { 23 | setSelectedChain(chain) 24 | setListVisible(false) 25 | } 26 | 27 | return ( 28 |
29 |
setListVisible(!listVisible)} 33 | > 34 |
35 | {selectedChain && ( 36 | <> 37 | {selectedChain.name} 38 | {selectedChain.name} 39 | 40 | )} 41 | 42 |
43 | 47 |
48 | 49 | {listVisible && ( 50 |
51 | {chains.map(chainItem => ( 52 |
handleSelectChain(chainItem)} 56 | > 57 | {chainItem.name} 58 | {chainItem.name} 59 |
60 | ))} 61 |
62 | )} 63 |
64 | ) 65 | } -------------------------------------------------------------------------------- /src/components/form/SelectLP.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import { Icon } from "@iconify/react"; 3 | import { useOnClickOutside } from 'usehooks-ts' 4 | import { IPropsOfComponent, ILP } from "../../utils/interfaces"; 5 | 6 | // ------------------------------------------------------------------------------------------------------- 7 | 8 | interface IProps extends IPropsOfComponent { 9 | lps: Array; 10 | selectedLP: ILP | null; 11 | setSelectedLP: Function; 12 | } 13 | 14 | // ------------------------------------------------------------------------------------------------------- 15 | 16 | export default function SelectLP({ className = '', lps, selectedLP, setSelectedLP, ...others }: IProps) { 17 | const ref = useRef(null) 18 | const [listVisible, setListVisible] = useState(false) 19 | 20 | useOnClickOutside(ref, () => setListVisible(false)) 21 | 22 | const handleSelectChain = (lp: ILP) => { 23 | setSelectedLP(lp) 24 | setListVisible(false) 25 | } 26 | 27 | return ( 28 |
29 |
setListVisible(!listVisible)} 33 | > 34 | {selectedLP ? ( 35 | <> 36 |
37 |
38 | {selectedLP.token.symbol} 39 | {selectedLP.coin.symbol} 40 |
41 | {selectedLP.token.symbol}-{selectedLP.coin.symbol} 42 |
43 | 44 |
45 |
46 |
47 | 48 | POWERED BY 49 |
50 | 51 |
52 | 53 | 57 |
58 | 59 | ) : ( 60 | <> 61 |
62 | 66 | 67 | )} 68 | 69 |
70 | 71 | {listVisible && ( 72 |
73 | {lps.map(lpItem => ( 74 |
handleSelectChain(lpItem)} 78 | > 79 |
80 |
81 | {lpItem.token.symbol} 82 | {lpItem.coin.symbol} 83 |
84 | {lpItem.token.symbol}-{lpItem.coin.symbol} 85 |
86 | 87 |
88 |
89 |
90 | 91 | POWERED BY 92 |
93 | 94 |
95 |
96 |
97 | ))} 98 |
99 | )} 100 |
101 | ) 102 | } -------------------------------------------------------------------------------- /src/components/form/SelectTokenWithDetail.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import { Icon } from "@iconify/react"; 3 | import { useOnClickOutside, useCopyToClipboard } from 'usehooks-ts' 4 | import { IPropsOfComponent, IToken } from "../../utils/interfaces"; 5 | import { getVisibleWalletAddress } from "../../utils/functions"; 6 | 7 | // ------------------------------------------------------------------------------------------------------- 8 | 9 | interface IProps extends IPropsOfComponent { 10 | tokens: Array; 11 | selectedToken: IToken | null; 12 | setSelectedToken: Function; 13 | } 14 | 15 | // ------------------------------------------------------------------------------------------------------- 16 | 17 | export default function SelectTokenWithDetail({ className = '', tokens, selectedToken, setSelectedToken, ...others }: IProps) { 18 | const ref = useRef(null) 19 | 20 | const [listVisible, setListVisible] = useState(false) 21 | 22 | const [copiedValue, copy] = useCopyToClipboard() 23 | 24 | useOnClickOutside(ref, () => setListVisible(false)) 25 | 26 | const handleSelectChain = (token: IToken) => { 27 | setSelectedToken(token) 28 | setListVisible(false) 29 | } 30 | 31 | return ( 32 |
33 |
setListVisible(!listVisible)} 36 | {...others} 37 | > 38 |
39 | {selectedToken && ( 40 | <> 41 | {selectedToken.name} 42 |
43 |
44 | {selectedToken.symbol} 45 |
46 | {getVisibleWalletAddress(selectedToken.tokenAddress || '')} 47 | 48 | {copiedValue === selectedToken.tokenAddress ? ( 49 | 50 | ) : ( 51 | copy(selectedToken.tokenAddress || '')} 55 | /> 56 | )} 57 |
58 |
59 | {selectedToken.name} 60 |
61 | 62 | )} 63 |
64 | 68 |
69 | 70 | {listVisible && ( 71 |
72 | {tokens.map(tokenItem => ( 73 |
handleSelectChain(tokenItem)} 77 | > 78 | {tokenItem.name} 79 |
80 |
81 | {tokenItem.symbol} 82 | {getVisibleWalletAddress(tokenItem.tokenAddress || '')} 83 |
84 | {tokenItem.name} 85 |
86 |
87 | ))} 88 |
89 | )} 90 |
91 | ) 92 | } -------------------------------------------------------------------------------- /src/components/form/SelectTokenWithPrice.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, ReactNode, useEffect, useRef, useState } from "react"; 2 | import { Icon } from "@iconify/react"; 3 | import { useDebounce, useOnClickOutside } from "usehooks-ts"; 4 | import { IAsset, IPropsOfComponent } from "../../utils/interfaces"; 5 | import MainInput from "./MainInput"; 6 | import TextIconButton from "../buttons/TextIconButton"; 7 | import Table from "../tableComponents/Table"; 8 | import Th from "../tableComponents/Th"; 9 | import Tr from "../tableComponents/Tr"; 10 | import Td from "../tableComponents/Td"; 11 | import { REGEX_NUMBER_VALID } from "../../utils/constants"; 12 | 13 | /* --------------------------------------------------------------------------- */ 14 | 15 | interface IProps extends IPropsOfComponent { 16 | classNameOfInput?: string; 17 | startAdornment?: ReactNode; 18 | tokens: Array; 19 | selectedToken: IAsset; 20 | setSelectedToken: Function; 21 | error?: boolean; 22 | tokenAmount: string; 23 | setTokenAmount: Function; 24 | } 25 | 26 | /* --------------------------------------------------------------------------- */ 27 | 28 | export default function SelectTokenWithPrice({ 29 | className = '', 30 | classNameOfInput = '', 31 | startAdornment, 32 | error, 33 | tokens = [], 34 | selectedToken, 35 | setSelectedToken, 36 | tokenAmount, 37 | setTokenAmount, 38 | ...others 39 | }: IProps) { 40 | const ref = useRef(null) 41 | 42 | const [listVisible, setListVisible] = useState(false) 43 | const [filteredTokens, setFilteredTokens] = useState>(tokens) 44 | const [searchKeyword, setSearchKeyword] = useState('') 45 | const debouncedSearchKeyword = useDebounce(searchKeyword, 500) 46 | 47 | useOnClickOutside(ref, () => setListVisible(false)) 48 | 49 | useEffect(() => { 50 | const _filteredTokens = tokens.filter(tokenItem => tokenItem.name.includes(debouncedSearchKeyword) || tokenItem.symbol.includes(debouncedSearchKeyword)) 51 | setFilteredTokens(_filteredTokens) 52 | }, [debouncedSearchKeyword]) 53 | 54 | const handleTokenAmount = (e: ChangeEvent) => { 55 | const { value } = e.target 56 | if (value.match(REGEX_NUMBER_VALID)) { 57 | setTokenAmount(value); 58 | } 59 | } 60 | 61 | return ( 62 |
63 |
67 | {startAdornment ? ( 68 |
{startAdornment}
69 | ) : (<>)} 70 | 76 |
77 | {selectedToken && ( 78 |
79 | {selectedToken.symbol} 80 | {selectedToken.symbol} 81 |
82 | )} 83 | 84 | setListVisible(!listVisible)}> 85 | 89 | 90 |
91 |
92 | 93 | {listVisible && ( 94 |
95 | } 97 | placeholder="Search by symbol or name" 98 | value={searchKeyword} 99 | onChange={(e: ChangeEvent) => setSearchKeyword(e.target.value)} 100 | /> 101 | 102 | 103 | 104 | 105 | 108 | 109 | 110 | {filteredTokens.map(tokenItem => ( 111 | setSelectedToken(tokenItem)}> 112 | 121 | 122 | 123 | ))} 124 | 125 |
106 | 107 |
113 |
114 | {tokenItem.symbol} 115 |
116 | {tokenItem.symbol} 117 | {tokenItem.name} 118 |
119 |
120 |
0
126 |
127 | )} 128 |
129 | ) 130 | } -------------------------------------------------------------------------------- /src/components/tableComponents/Table.tsx: -------------------------------------------------------------------------------- 1 | import { IPropsOfComponent } from "../../utils/interfaces"; 2 | 3 | export default function Table({ className = '', children, ...others }: IPropsOfComponent) { 4 | return ( 5 | 6 | {children} 7 |
8 | ) 9 | } -------------------------------------------------------------------------------- /src/components/tableComponents/Td.tsx: -------------------------------------------------------------------------------- 1 | import { IPropsOfComponent } from "../../utils/interfaces"; 2 | 3 | export default function Td({ className = '', children, ...others }: IPropsOfComponent) { 4 | return ( 5 | 6 | {children} 7 | 8 | ) 9 | } -------------------------------------------------------------------------------- /src/components/tableComponents/Th.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Icon } from '@iconify/react'; 3 | import { IPropsOfComponent } from "../../utils/interfaces"; 4 | 5 | // ------------------------------------------------------------------------------- 6 | 7 | interface IProps extends IPropsOfComponent { 8 | label: string; 9 | sortable?: boolean; 10 | sortAsc?: Function; 11 | sortDesc?: Function; 12 | } 13 | 14 | // ------------------------------------------------------------------------------- 15 | 16 | export default function Th({ className = '', label, sortable = false, sortAsc, sortDesc, ...others }: IProps) { 17 | const [sortedAsc, setSortedAsc] = useState(true) 18 | 19 | const handleSort = (_isAsc: boolean) => { 20 | setSortedAsc(_isAsc) 21 | if (_isAsc) { 22 | sortAsc?.() 23 | } else { 24 | sortDesc?.() 25 | } 26 | } 27 | 28 | return ( 29 | handleSort(!sortedAsc)} {...others} 32 | > 33 | {sortable ? ( 34 |
35 | {label} 36 |
37 | 41 | 45 |
46 |
47 | ) : ( 48 |

{label}

49 | )} 50 | 51 | ) 52 | } -------------------------------------------------------------------------------- /src/components/tableComponents/Tr.tsx: -------------------------------------------------------------------------------- 1 | import { IPropsOfComponent } from "../../utils/interfaces"; 2 | 3 | export default function Tr({ className = '', children, ...others }: IPropsOfComponent) { 4 | return ( 5 | 6 | {children} 7 | 8 | ) 9 | } -------------------------------------------------------------------------------- /src/contexts/AlertMessageContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useReducer } from 'react'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | type TColor = 'blue' | 'red' | 'green' | 'amber' 6 | 7 | interface IInitialState { 8 | isOpened: boolean, 9 | color: TColor, 10 | message: string 11 | } 12 | 13 | interface IAction { 14 | type: string, 15 | payload: any 16 | } 17 | 18 | interface IProps { 19 | children: any 20 | } 21 | 22 | interface IParamsOfOpenAlert { 23 | color: TColor, 24 | message: string 25 | } 26 | 27 | interface IHandlers { 28 | [key: string]: Function, 29 | } 30 | 31 | // ---------------------------------------------------------------------- 32 | 33 | const initialState: IInitialState = { 34 | isOpened: false, 35 | color: 'blue', 36 | message: '' 37 | }; 38 | 39 | const handlers: IHandlers = { 40 | INITIALIZE: (state: object, action: IAction) => { 41 | return { 42 | ...state, 43 | ...action.payload 44 | }; 45 | }, 46 | SET_IS_OPENED: (state: object, action: IAction) => { 47 | return { 48 | ...state, 49 | isOpened: action.payload 50 | }; 51 | }, 52 | SET_COLOR: (state: object, action: IAction) => { 53 | return { 54 | ...state, 55 | color: action.payload 56 | }; 57 | }, 58 | SET_MESSAGE: (state: object, action: IAction) => { 59 | return { 60 | ...state, 61 | message: action.payload 62 | }; 63 | } 64 | }; 65 | 66 | const reducer = (state: object, action: IAction) => 67 | handlers[action.type] ? handlers[action.type](state, action) : state; 68 | 69 | // Context 70 | const AlertMessageContext = createContext({ 71 | ...initialState, 72 | openAlert: (alertContent: IParamsOfOpenAlert) => Promise.resolve(), 73 | closeAlert: () => Promise.resolve() 74 | }); 75 | 76 | // Provider 77 | function AlertMessageProvider({ children }: IProps) { 78 | const [state, dispatch] = useReducer(reducer, initialState); 79 | 80 | /** 81 | * Visible the alert message 82 | * @param {object} param0 83 | */ 84 | const openAlert = ({ color, message }: IParamsOfOpenAlert) => { 85 | dispatch({ 86 | type: 'SET_IS_OPENED', 87 | payload: true 88 | }); 89 | dispatch({ 90 | type: 'SET_COLOR', 91 | payload: color 92 | }); 93 | dispatch({ 94 | type: 'SET_MESSAGE', 95 | payload: message 96 | }); 97 | }; 98 | 99 | /** 100 | * Unvisible the alert message 101 | */ 102 | const closeAlert = () => { 103 | dispatch({ 104 | type: 'INITIALIZE', 105 | payload: { 106 | isOpened: false, 107 | color: 'blue', 108 | message: '' 109 | } 110 | }); 111 | }; 112 | 113 | return ( 114 | 121 | {children} 122 | 123 | ); 124 | } 125 | 126 | export { AlertMessageContext, AlertMessageProvider }; -------------------------------------------------------------------------------- /src/contexts/DialogSizeContext.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, createContext, useReducer } from "react"; 2 | import { size } from "@material-tailwind/react/types/components/avatar"; 3 | 4 | // ------------------------------------------------------------------------------------------- 5 | 6 | interface IInitalState { 7 | dialogSize: size; 8 | } 9 | 10 | interface IAction { 11 | type: string; 12 | payload: string | number | object | null; 13 | } 14 | 15 | interface IProps { 16 | children: ReactNode; 17 | } 18 | 19 | interface IHandlers { 20 | [key: string]: Function, 21 | } 22 | 23 | // ------------------------------------------------------------------------------------------- 24 | 25 | const initialState: IInitalState = { 26 | dialogSize: 'xxl' 27 | } 28 | 29 | const handlers: IHandlers = { 30 | SET_DIALOG_SIZE: (state: object, action: IAction) => { 31 | return { 32 | ...state, 33 | dialogSize: action.payload 34 | } 35 | } 36 | } 37 | 38 | const reducer = (state: object, action: IAction) => handlers[action.type] ? handlers[action.type](state, action) : state; 39 | 40 | // ------------------------------------------------------------------------------------------- 41 | 42 | const DialogSizeContext = createContext({ 43 | ...initialState, 44 | setDialogSizeAct: (_dialogSize: size) => Promise.resolve(), 45 | }); 46 | 47 | const DialogSizeProvider = ({ children }: IProps) => { 48 | const [state, dispatch] = useReducer(reducer, initialState); 49 | 50 | const setDialogSizeAct = (_dialogSize: size) => { 51 | dispatch({ 52 | type: 'SET_DIALOG_SIZE', 53 | payload: _dialogSize 54 | }) 55 | } 56 | 57 | return ( 58 | 59 | {children} 60 | 61 | ) 62 | } 63 | 64 | export { DialogSizeContext, DialogSizeProvider } -------------------------------------------------------------------------------- /src/contexts/LoadingContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useReducer } from 'react'; 2 | 3 | /* --------------------------------------------------------------- */ 4 | 5 | interface IInitialState { 6 | isLoading: boolean 7 | } 8 | 9 | interface IAction { 10 | type: string, 11 | payload: any 12 | } 13 | 14 | interface IProps { 15 | children: any 16 | } 17 | 18 | interface IHandlers { 19 | [key: string]: Function, 20 | } 21 | 22 | /* --------------------------------------------------------------- */ 23 | 24 | const initialState: IInitialState = { 25 | isLoading: false, 26 | }; 27 | 28 | const handlers: IHandlers = { 29 | SET_IS_LOADING: (state: object, action: IAction) => { 30 | return { 31 | ...state, 32 | isLoading: action.payload 33 | }; 34 | } 35 | }; 36 | 37 | const reducer = (state: object, action: IAction) => 38 | handlers[action.type] ? handlers[action.type](state, action) : state; 39 | 40 | // Context 41 | const LoadingContext = createContext({ 42 | ...initialState, 43 | openLoading: () => Promise.resolve(), 44 | closeLoading: () => Promise.resolve() 45 | }); 46 | 47 | // Provider 48 | function LoadingProvider({ children }: IProps) { 49 | const [state, dispatch] = useReducer(reducer, initialState); 50 | 51 | const openLoading = () => { 52 | dispatch({ 53 | type: 'SET_IS_LOADING', 54 | payload: true 55 | }); 56 | }; 57 | 58 | const closeLoading = () => { 59 | dispatch({ 60 | type: 'SET_IS_LOADING', 61 | payload: false 62 | }); 63 | }; 64 | 65 | return ( 66 | 73 | {children} 74 | 75 | ); 76 | } 77 | 78 | export { LoadingContext, LoadingProvider }; -------------------------------------------------------------------------------- /src/contexts/MobileMenuContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useReducer } from 'react'; 2 | 3 | /* --------------------------------------------------------------- */ 4 | 5 | interface IInitialState { 6 | opened: boolean 7 | } 8 | 9 | interface IAction { 10 | type: string, 11 | payload: any 12 | } 13 | 14 | interface IProps { 15 | children: any 16 | } 17 | 18 | interface IHandlers { 19 | [key: string]: Function, 20 | } 21 | 22 | /* --------------------------------------------------------------- */ 23 | 24 | const initialState: IInitialState = { 25 | opened: false, 26 | }; 27 | 28 | const handlers: IHandlers = { 29 | SET_OPENED: (state: object, action: IAction) => { 30 | return { 31 | ...state, 32 | opened: action.payload 33 | }; 34 | } 35 | }; 36 | 37 | const reducer = (state: object, action: IAction) => 38 | handlers[action.type] ? handlers[action.type](state, action) : state; 39 | 40 | // Context 41 | const MobileMenuContext = createContext({ 42 | ...initialState, 43 | openMenu: () => Promise.resolve(), 44 | closeMenu: () => Promise.resolve() 45 | }); 46 | 47 | // Provider 48 | function MobileMenuProvider({ children }: IProps) { 49 | const [state, dispatch] = useReducer(reducer, initialState); 50 | 51 | const openMenu = () => { 52 | dispatch({ 53 | type: 'SET_OPENED', 54 | payload: true 55 | }); 56 | }; 57 | 58 | const closeMenu = () => { 59 | dispatch({ 60 | type: 'SET_OPENED', 61 | payload: false 62 | }); 63 | }; 64 | 65 | return ( 66 | 73 | {children} 74 | 75 | ); 76 | } 77 | 78 | export { MobileMenuContext, MobileMenuProvider }; -------------------------------------------------------------------------------- /src/hooks/useAlertMessage.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AlertMessageContext } from '../contexts/AlertMessageContext'; 3 | 4 | const useAlertMessage = () => useContext(AlertMessageContext); 5 | 6 | export default useAlertMessage; -------------------------------------------------------------------------------- /src/hooks/useDialogSize.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { DialogSizeContext } from '../contexts/DialogSizeContext'; 3 | 4 | const useDialogSize = () => useContext(DialogSizeContext); 5 | 6 | export default useDialogSize; -------------------------------------------------------------------------------- /src/hooks/useLoading.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { LoadingContext } from "../contexts/LoadingContext"; 3 | 4 | const useLoading = () => useContext(LoadingContext); 5 | 6 | export default useLoading; 7 | -------------------------------------------------------------------------------- /src/hooks/useMobileMenu.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { MobileMenuContext } from "../contexts/MobileMenuContext"; 3 | 4 | const useMobileMenu = () => useContext(MobileMenuContext); 5 | 6 | export default useMobileMenu; 7 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* ------ Custom Scroll bar -------- */ 6 | 7 | /* width */ 8 | ::-webkit-scrollbar { 9 | width: 12px; 10 | } 11 | 12 | /* Track */ 13 | ::-webkit-scrollbar-track { 14 | background: #292524; 15 | } 16 | 17 | /* Handle */ 18 | ::-webkit-scrollbar-thumb { 19 | background: #57534e; 20 | border-radius: 9999px; 21 | } 22 | 23 | /* Handle on hover */ 24 | ::-webkit-scrollbar-thumb:hover { 25 | background: #57534e; 26 | } 27 | 28 | /* --------------------------------- */ 29 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import 'rc-slider/assets/index.css'; 4 | import 'react-toastify/dist/ReactToastify.css'; 5 | import './index.css'; 6 | import App from './App'; 7 | import * as serviceWorkerRegistration from './serviceWorkerRegistration'; 8 | import reportWebVitals from './reportWebVitals'; 9 | 10 | const root = ReactDOM.createRoot( 11 | document.getElementById('root') as HTMLElement 12 | ); 13 | root.render( 14 | 15 | 16 | 17 | ); 18 | 19 | // If you want your app to work offline and load faster, you can change 20 | // unregister() to register() below. Note this comes with some pitfalls. 21 | // Learn more about service workers: https://cra.link/PWA 22 | serviceWorkerRegistration.unregister(); 23 | 24 | // If you want to start measuring performance in your app, pass a function 25 | // to log results (for example: reportWebVitals(console.log)) 26 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 27 | reportWebVitals(); 28 | -------------------------------------------------------------------------------- /src/layouts/LandingLayout/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { Icon } from "@iconify/react"; 2 | import Container from "../../components/containers/Container"; 3 | import TextIconButton from "../../components/buttons/TextIconButton"; 4 | 5 | export default function Footer() { 6 | return ( 7 |
8 | 9 |
10 | Audited by: 11 |
12 | 13 | 14 | Copyrights © {new Date().getFullYear()} Peko 15 | 16 | 17 | 25 |
26 | 27 | 28 |

29 | Copyrights © {new Date().getFullYear()} Peko 30 |

31 |
32 |
33 | Audited by: 34 |
35 | 43 |
44 |
45 |
46 | ) 47 | } -------------------------------------------------------------------------------- /src/layouts/LandingLayout/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Link, useLocation, useNavigate } from "react-router-dom"; 3 | import { Icon } from '@iconify/react'; 4 | import { useWeb3Modal } from "@web3modal/react" 5 | import { useAccount, useDisconnect, useSwitchNetwork, useNetwork } from "wagmi" 6 | import { Drawer, List, ListItem } from "@material-tailwind/react"; 7 | import Container from "../../components/containers/Container"; 8 | import TextButton from "../../components/buttons/TextButton"; 9 | import TextIconButton from "../../components/buttons/TextIconButton"; 10 | import FilledButton from "../../components/buttons/FilledButton"; 11 | 12 | // ----------------------------------------------------------------------------------------- 13 | 14 | interface INavLink { 15 | id: number; 16 | label: string; 17 | iconName: string; 18 | to: string; 19 | } 20 | 21 | // ----------------------------------------------------------------------------------------- 22 | 23 | const NAV_LINKS: Array = [ 24 | { 25 | id: 4, 26 | label: 'Dashboard', 27 | iconName: 'material-symbols:dashboard', 28 | to: '/dashboard' 29 | }, 30 | { 31 | id: 1, 32 | label: 'Lending', 33 | iconName: 'cryptocurrency:lend', 34 | to: '/lending' 35 | }, 36 | // { 37 | // id: 2, 38 | // label: 'Swap', 39 | // iconName: 'ph:swap-bold', 40 | // to: '/swap' 41 | // }, 42 | // { 43 | // id: 3, 44 | // label: 'Bridge', 45 | // iconName: 'mdi:bridge', 46 | // to: '/bridge' 47 | // }, 48 | 49 | // { 50 | // id: 5, 51 | // label: 'Trading', 52 | // iconName: 'ep:histogram', 53 | // to: '/trading' 54 | // }, 55 | ] 56 | 57 | const chainId = process.env.REACT_APP_CHAIN_ID 58 | 59 | // ----------------------------------------------------------------------------------------- 60 | 61 | export default function Navbar() { 62 | const { pathname } = useLocation() 63 | const { open } = useWeb3Modal() 64 | const { isConnected } = useAccount() 65 | const { disconnect } = useDisconnect() 66 | const { switchNetwork } = useSwitchNetwork() 67 | const { chain } = useNetwork() 68 | const navigate = useNavigate() 69 | 70 | const [visibleDrawer, setVisibleDrawer] = useState(false) 71 | 72 | const closeDrawer = () => { 73 | setVisibleDrawer(false) 74 | } 75 | 76 | const navigateToPage = (to: string) => { 77 | navigate(to) 78 | closeDrawer() 79 | } 80 | 81 | return ( 82 | 177 | ) 178 | } -------------------------------------------------------------------------------- /src/layouts/LandingLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useEffect } from "react"; 2 | import { useMediaQuery } from "react-responsive"; 3 | import { Outlet } from "react-router-dom"; 4 | import useDialogSize from "../../hooks/useDialogSize"; 5 | import useLoading from "../../hooks/useLoading"; 6 | import Loading from "../../components/Loading"; 7 | 8 | // --------------------------------------------------------------------------------------- 9 | 10 | const Navbar = lazy(() => import('./Navbar')) 11 | const Footer = lazy(() => import('./Footer')) 12 | 13 | // --------------------------------------------------------------------------------------- 14 | 15 | export default function LandingLayout() { 16 | const isMobile = useMediaQuery({ maxWidth: 480 }); 17 | const isTablet = useMediaQuery({ minWidth: 480, maxWidth: 768 }); 18 | const isLaptop = useMediaQuery({ minWidth: 768, maxWidth: 1024 }); 19 | const isDesktop = useMediaQuery({ minWidth: 1024, maxWidth: 1280 }); 20 | const { isLoading } = useLoading() 21 | const { setDialogSizeAct } = useDialogSize() 22 | 23 | useEffect(() => { 24 | if (isMobile) { 25 | setDialogSizeAct('xxl') 26 | } else if (isTablet) { 27 | setDialogSizeAct('xl') 28 | } else if (isLaptop) { 29 | setDialogSizeAct('lg') 30 | } else if (isDesktop) { 31 | setDialogSizeAct('md') 32 | } else { 33 | setDialogSizeAct('sm') 34 | } 35 | }, [isMobile, isTablet, isLaptop, isDesktop]) 36 | 37 | return ( 38 | <> 39 |
40 | 41 |
42 | 43 |
44 |
45 |
46 | {isLoading && } 47 | 48 | ) 49 | } -------------------------------------------------------------------------------- /src/pages/Blank.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import Container from "../components/containers/Container"; 3 | 4 | export default function Blank() { 5 | return ( 6 |
7 | 8 |

4 0 4

9 | Go to Homepage 10 |
11 |
12 | ) 13 | } -------------------------------------------------------------------------------- /src/pages/Bridge/index.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, lazy, useState } from "react"; 2 | import { useCopyToClipboard } from 'usehooks-ts'; 3 | import { Icon } from "@iconify/react"; 4 | import PageHeader from "../../components/PageHeader"; 5 | import { IChain, IToken } from "../../utils/interfaces"; 6 | import { REGEX_NUMBER_VALID, TEMP_CHAINS } from "../../utils/constants"; 7 | import MainInput from "../../components/form/MainInput"; 8 | import { getVisibleWalletAddress } from "../../utils/functions"; 9 | import OutlinedButton from "../../components/buttons/OutlinedButton"; 10 | import FilledButton from "../../components/buttons/FilledButton"; 11 | 12 | // --------------------------------------------------------------------------------------------- 13 | 14 | const SelectChain = lazy(() => import('../../components/form/SelectChain')) 15 | const SelectTokenWithDetail = lazy(() => import('../../components/form/SelectTokenWithDetail')) 16 | 17 | // --------------------------------------------------------------------------------------------- 18 | 19 | const TOKENS: Array = [ 20 | { 21 | id: 1, 22 | name: "USDC(Wormhole)", 23 | symbol: "USDC", 24 | imgSrc: "https://cryptologos.cc/logos/usd-coin-usdc-logo.svg?v=025", 25 | depositedAmount: 0, 26 | tokenAddress: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d' 27 | }, 28 | { 29 | id: 2, 30 | name: "Wormhole Solana USDC", 31 | symbol: "USDC", 32 | imgSrc: "https://cryptologos.cc/logos/usd-coin-usdc-logo.svg?v=025", 33 | depositedAmount: 0, 34 | tokenAddress: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d' 35 | }, 36 | ] 37 | 38 | // --------------------------------------------------------------------------------------------- 39 | 40 | export default function Bridge() { 41 | const [sourceChain, setSourceChain] = useState(null) 42 | const [targetChain, setTargetChain] = useState(null) 43 | const [token, setToken] = useState(null) 44 | const [amount, setAmount] = useState('0') 45 | 46 | const [copiedValue, copy] = useCopyToClipboard() 47 | 48 | const handleAmount = (e: ChangeEvent) => { 49 | const { value } = e.target 50 | if (value.match(REGEX_NUMBER_VALID)) { 51 | setAmount(value); 52 | } 53 | } 54 | 55 | return ( 56 |
57 | 58 | 59 |
60 |

Bridge

61 | 62 |
63 |
64 | {/* Source chain */} 65 |
66 | 67 | 73 |
74 | 75 | 76 | 77 | {/* Target chain */} 78 |
79 | 80 | 86 |
87 |
88 | 89 | {/* Token */} 90 |
91 | 92 | {token ? ( 93 |
94 |
95 | 101 |
102 | 103 | 104 | 105 |
106 | {token.name} 107 |
108 |
109 | {token.symbol} 110 |
111 | {getVisibleWalletAddress(token.tokenAddress || '')} 112 | 113 | {copiedValue === token.tokenAddress ? ( 114 | 115 | ) : ( 116 | copy(token.tokenAddress || '')} 120 | /> 121 | )} 122 |
123 |
124 | {token.name} 125 |
126 |
127 | 128 |
129 | ) : ( 130 | 136 | )} 137 |
138 | 139 | {/* Amount */} 140 |
141 | 142 | {token?.symbol}} 145 | value={amount} 146 | onChange={handleAmount} 147 | /> 148 |
149 | 150 |
151 |
152 | {sourceChain?.name} Balance: 0 {token?.symbol} 153 | {targetChain?.name} Balance: 0 {token?.symbol} 154 |
155 |
156 | half 157 | max 158 |
159 |
160 |
161 | 162 |

163 | * You will get wormhole wrapped token on Fantom, you can swap them to native token manually. 164 |

165 | 166 | Connect Wallet 167 |
168 |
169 | ) 170 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/AccountStatusSection.tsx: -------------------------------------------------------------------------------- 1 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; 2 | import { Doughnut } from 'react-chartjs-2'; 3 | import Section from "../../components/Section"; 4 | 5 | ChartJS.register(ArcElement, Tooltip, Legend); 6 | 7 | export const data = { 8 | labels: ['Wallet', 'LP token', 'Farms', 'Main Account'], 9 | datasets: [ 10 | { 11 | label: '# of Votes', 12 | data: [12, 19, 3, 5], 13 | backgroundColor: [ 14 | 'rgba(255, 99, 132, 0.2)', 15 | 'rgba(54, 162, 235, 0.2)', 16 | 'rgba(255, 206, 86, 0.2)', 17 | 'rgba(75, 192, 192, 0.2)', 18 | ], 19 | borderColor: [ 20 | 'rgba(255, 99, 132, 1)', 21 | 'rgba(54, 162, 235, 1)', 22 | 'rgba(255, 206, 86, 1)', 23 | 'rgba(75, 192, 192, 1)', 24 | ], 25 | borderWidth: 1, 26 | }, 27 | ], 28 | }; 29 | 30 | export default function AccountStatusSection() { 31 | return ( 32 |
33 |
34 |
35 | History 36 |
37 |
38 |
Composition
39 | 40 |
41 |
42 |
43 | ) 44 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/DialogClaimPeko.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, useEffect, useMemo, useState } from "react"; 2 | import { useContractWrite, usePrepareContractWrite, useWaitForTransaction } from "wagmi"; 3 | import { parseUnits } from "viem"; 4 | import { toast } from "react-toastify"; 5 | import CustomDialog from "../../components/dialogs/CustomDialog"; 6 | import MainInput from "../../components/form/MainInput"; 7 | import { IN_PROGRESS, PEKO_DECIMAL, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, REGEX_NUMBER_VALID } from "../../utils/constants"; 8 | import { IUserInfo } from "../../utils/interfaces"; 9 | import OutlinedButton from "../../components/buttons/OutlinedButton"; 10 | import FilledButton from "../../components/buttons/FilledButton"; 11 | 12 | // --------------------------------------------------------------------------------------- 13 | 14 | interface IProps { 15 | visible: boolean; 16 | setVisible: Function; 17 | userInfo: IUserInfo 18 | } 19 | 20 | // --------------------------------------------------------------------------------------- 21 | 22 | export default function DialogClaimPeko({ userInfo, visible, setVisible }: IProps) { 23 | const [amount, setAmount] = useState('0') 24 | 25 | // ------------------------------------------------------------------------ 26 | 27 | // Claim Peko 28 | const { config: depositConfig } = usePrepareContractWrite({ 29 | address: POOL_CONTRACT_ADDRESS, 30 | abi: POOL_CONTRACT_ABI, 31 | functionName: 'claimPeko', 32 | args: [parseUnits(amount, PEKO_DECIMAL)], 33 | }) 34 | 35 | const { write: claimPeko, data: claimPekoData } = useContractWrite(depositConfig); 36 | 37 | const { isLoading: claimPekoIsLoading, isSuccess: claimPekoIsSuccess, isError: claimPekoIsError } = useWaitForTransaction({ 38 | hash: claimPekoData?.hash, 39 | }) 40 | 41 | // ------------------------------------------------------------------------ 42 | 43 | const handleAmount = (e: ChangeEvent) => { 44 | const { value } = e.target; 45 | 46 | if (value.match(REGEX_NUMBER_VALID)) { 47 | setAmount(value); 48 | } 49 | } 50 | 51 | const handleHalf = () => { 52 | setAmount(`${maxAmount / 2}`) 53 | } 54 | 55 | const handleMax = () => { 56 | setAmount(`${maxAmount}`) 57 | } 58 | 59 | // ------------------------------------------------------------------------ 60 | 61 | const maxAmount = useMemo(() => { 62 | return Number(userInfo.pekoRewardAmount) 63 | }, [userInfo]) 64 | 65 | const amountIsValid = useMemo(() => { 66 | if (Number(amount) > 0 && Number(amount) <= maxAmount) { 67 | return true 68 | } 69 | return false 70 | }, [maxAmount, amount]) 71 | 72 | // ------------------------------------------------------------------------ 73 | 74 | useEffect(() => { 75 | if (claimPekoIsSuccess) { 76 | toast.success('Claimed.') 77 | } 78 | }, [claimPekoIsSuccess]) 79 | 80 | useEffect(() => { 81 | if (claimPekoIsError) { 82 | toast.error('Claiming token has an error.') 83 | } 84 | }, [claimPekoIsError]) 85 | 86 | // ------------------------------------------------------------------------ 87 | 88 | return ( 89 | 90 |
91 |
} 93 | onChange={handleAmount} 94 | value={amount} 95 | disabled={!amountIsValid} 96 | /> 97 |
98 |

Max: {maxAmount.toFixed(4)} PEKO

99 |
100 | half 104 | max 108 |
109 |
110 | 111 | claimPeko?.()} 115 | > 116 | {claimPekoIsLoading ? IN_PROGRESS : "Claim"} 117 | 118 |
119 | 120 | ) 121 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/FarmsSection.tsx: -------------------------------------------------------------------------------- 1 | import Table from "../../components/tableComponents/Table"; 2 | import Th from "../../components/tableComponents/Th"; 3 | import Section from "../../components/Section"; 4 | 5 | export default function FarmsSection() { 6 | return ( 7 |
$0.00}> 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 |
12 | 13 | 14 | 15 | 16 | 17 |
23 |

You have no Farms Record yet.

24 |
28 |
29 | ) 30 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/LPTokensSection.tsx: -------------------------------------------------------------------------------- 1 | import Table from "../../components/tableComponents/Table"; 2 | import Th from "../../components/tableComponents/Th"; 3 | import Section from "../../components/Section"; 4 | 5 | export default function LPTokensSection() { 6 | return ( 7 |
$0.00}> 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 |
12 | 13 | 14 | 15 |
21 |

You have no LP token in your wallet.

22 |
26 |
27 | ) 28 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/PekoSection/ClaimPekoDialog.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, useMemo, useState } from "react"; 2 | import { toast } from "react-toastify"; 3 | import { useContractWrite, usePrepareContractWrite, useWaitForTransaction } from "wagmi"; 4 | import CustomDialog from "../../../components/dialogs/CustomDialog"; 5 | import MainInput from "../../../components/form/MainInput"; 6 | import { IPropsOfCustomDialog, IUserInfo } from "../../../utils/interfaces"; 7 | import { IN_PROGRESS, PEKO_DECIMAL, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, REGEX_NUMBER_VALID } from "../../../utils/constants"; 8 | import OutlinedButton from "../../../components/buttons/OutlinedButton"; 9 | import Slider from "rc-slider"; 10 | import FilledButton from "../../../components/buttons/FilledButton"; 11 | import { formatUnits } from "viem"; 12 | 13 | // --------------------------------------------------------------------------------------------- 14 | 15 | interface IProps extends IPropsOfCustomDialog { 16 | userInfo: IUserInfo; 17 | } 18 | 19 | // --------------------------------------------------------------------------------------------- 20 | 21 | export default function ClaimPekoDialog({ visible, setVisible, userInfo }: IProps) { 22 | const [amount, setAmount] = useState('0') 23 | 24 | // ---------------------------------------------------------------------- 25 | 26 | // Claim Peko 27 | const { config: configOfClaimPeko } = usePrepareContractWrite({ 28 | address: POOL_CONTRACT_ADDRESS, 29 | abi: POOL_CONTRACT_ABI, 30 | functionName: 'claimPeko', 31 | }) 32 | const { write: claimPeko, data: claimPekoData } = useContractWrite(configOfClaimPeko); 33 | const { isLoading: claimPekoIsLoading } = useWaitForTransaction({ 34 | hash: claimPekoData?.hash, 35 | onSuccess: () => { 36 | toast.success('Peko Claimed.') 37 | setVisible(false) 38 | }, 39 | onError: () => { 40 | toast.error('Claim occured error.') 41 | } 42 | }) 43 | 44 | // ---------------------------------------------------------------------- 45 | 46 | const amountInNumberType = useMemo(() => { 47 | if (amount[0] === '0') { 48 | if (amount[1] !== '.') 49 | return `${Number(amount)}` 50 | } 51 | return amount 52 | }, [amount]) 53 | 54 | const maxAmount = useMemo(() => { 55 | return Number(formatUnits(userInfo.pekoRewardAmount, PEKO_DECIMAL)) 56 | }, [userInfo]) 57 | 58 | const amountIsValid = useMemo(() => { 59 | if (Number(amount) > maxAmount) { 60 | return false 61 | } 62 | if (Number(amount) <= 0) { 63 | return false 64 | } 65 | return true 66 | }, [amount, maxAmount]) 67 | 68 | // ---------------------------------------------------------------------- 69 | 70 | const handleAmount = (e: ChangeEvent) => { 71 | const { value } = e.target; 72 | 73 | if (value.match(REGEX_NUMBER_VALID)) { 74 | setAmount(value); 75 | } 76 | } 77 | 78 | const handleMaxAmount = () => { 79 | setAmount(Number(maxAmount).toFixed(4)) 80 | } 81 | 82 | const handleHalfAmount = () => { 83 | setAmount(`${(Number(maxAmount) / 2).toFixed(4)}`) 84 | } 85 | 86 | const handleSlider = (value: any) => { 87 | setAmount(`${Number(value * Number(maxAmount) / 100).toFixed(4)}`) 88 | } 89 | 90 | // ---------------------------------------------------------------------- 91 | 92 | return ( 93 | 94 |
95 |
96 | PEKO} 98 | onChange={handleAmount} 99 | value={amountInNumberType} 100 | /> 101 | 102 |
103 |

Max: {maxAmount.toFixed(PEKO_DECIMAL)}PEKO

104 |
105 | half 106 | max 107 |
108 |
109 | 110 |
111 | 125 |
126 |
127 | 128 | claimPeko?.()} 132 | > 133 | {claimPekoIsLoading ? IN_PROGRESS : "Claim $Peko"} 134 | 135 |
136 |
137 | ) 138 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/PekoSection/index.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { useAccount, useBalance } from "wagmi"; 3 | import { useMediaQuery } from "react-responsive"; 4 | import { formatUnits } from "viem"; 5 | import Table from "../../../components/tableComponents/Table"; 6 | import Th from "../../../components/tableComponents/Th"; 7 | import Section from "../../../components/Section"; 8 | import Td from "../../../components/tableComponents/Td"; 9 | import { IUserInfo } from "../../../utils/interfaces"; 10 | import { PEKO_CONTRACT_ADDRESS, PEKO_DECIMAL } from "../../../utils/constants"; 11 | import FilledButton from "../../../components/buttons/FilledButton"; 12 | import ClaimPekoDialog from "./ClaimPekoDialog"; 13 | 14 | // ------------------------------------------------------------------------------------------------------ 15 | 16 | interface IProps { 17 | userInfo: IUserInfo; 18 | } 19 | 20 | // ------------------------------------------------------------------------------------------------------ 21 | 22 | export default function PekoSection({ userInfo }: IProps) { 23 | const isMobile = useMediaQuery({ maxWidth: 640 }) 24 | const { address } = useAccount() 25 | 26 | const [dialogVisible, setDialogVisible] = useState(false) 27 | 28 | // -------------------------------------------------------------------- 29 | 30 | const { data: pekoBalanceDataOfWallet } = useBalance({ 31 | address, 32 | token: PEKO_CONTRACT_ADDRESS, 33 | watch: true 34 | }) 35 | 36 | // -------------------------------------------------------------------- 37 | 38 | return ( 39 |
40 | {isMobile ? ( 41 |
42 |
43 | {/* Symbol */} 44 |
45 | Symbol: 46 |
47 | 48 | PEKO 49 |
50 |
51 | 52 | {/* Unclaimed Peko */} 53 |
54 | Unclaimed Peko: 55 | {formatUnits(userInfo.pekoRewardAmount, PEKO_DECIMAL)} PEKO 56 |
57 | 58 | {/* Wallet Balance */} 59 |
60 | Wallet Balance: 61 | {Number(pekoBalanceDataOfWallet?.formatted).toFixed(2)} PEKO 62 |
63 | 64 | {/* Operation */} 65 |
66 | Oepration: 67 | setDialogVisible(true)} 69 | > 70 | Claim 71 | 72 |
73 |
74 |
75 | ) : ( 76 | 77 | 78 | 79 | 84 | 85 | 86 | 87 | 88 | 94 | 97 | 100 | 105 | 106 | 107 |
80 | 81 | 82 | 83 |
89 |
90 | 91 | PEKO 92 |
93 |
95 | {formatUnits(userInfo.pekoRewardAmount, PEKO_DECIMAL)} PEKO 96 | 98 | {pekoBalanceDataOfWallet?.formatted} PEKO 99 | 101 | setDialogVisible(true)}> 102 | Claim 103 | 104 |
108 | )} 109 | 110 |
111 | ) 112 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/ProfitSection/ClaimProfitDialog.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, useMemo, useState } from "react"; 2 | import Slider from "rc-slider"; 3 | import { useContractRead, useContractWrite, usePrepareContractWrite, useWaitForTransaction } from "wagmi"; 4 | import { toast } from "react-toastify"; 5 | import { formatUnits, parseUnits } from "viem"; 6 | import OutlinedButton from "../../../components/buttons/OutlinedButton"; 7 | import CustomDialog from "../../../components/dialogs/CustomDialog"; 8 | import MainInput from "../../../components/form/MainInput"; 9 | import { IAsset, IPropsOfCustomDialog, IReturnValueOfAllowance } from "../../../utils/interfaces"; 10 | import FilledButton from "../../../components/buttons/FilledButton"; 11 | import { IN_PROGRESS, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, REGEX_NUMBER_VALID } from "../../../utils/constants"; 12 | 13 | // ------------------------------------------------------------------------------------------- 14 | 15 | interface IProps extends IPropsOfCustomDialog { 16 | visible: boolean; 17 | setVisible: Function; 18 | asset: IAsset; 19 | } 20 | 21 | // ------------------------------------------------------------------------------------------- 22 | 23 | export default function ClaimProfitDialog({ visible, setVisible, asset }: IProps) { 24 | const [amount, setAmount] = useState('0') 25 | 26 | // ---------------------------------------------------------------------- 27 | // Get Profit 28 | const { data: profitInBigint }: IReturnValueOfAllowance = useContractRead({ 29 | address: POOL_CONTRACT_ADDRESS, 30 | abi: POOL_CONTRACT_ABI, 31 | functionName: 'getProfit', 32 | args: [asset.contractAddress, parseUnits(amount, asset.decimals)], 33 | watch: true 34 | }) 35 | 36 | // Claim Profit 37 | const { config: configOfClaimProfit } = usePrepareContractWrite({ 38 | address: POOL_CONTRACT_ADDRESS, 39 | abi: POOL_CONTRACT_ABI, 40 | functionName: 'claimProfit', 41 | }) 42 | const { write: claimProfit, data: claimProfitData } = useContractWrite(configOfClaimProfit); 43 | const { isLoading: claimProfitIsLoading } = useWaitForTransaction({ 44 | hash: claimProfitData?.hash, 45 | onSuccess: () => { 46 | toast.success('Peko Claimed.') 47 | setVisible(false) 48 | }, 49 | onError: () => { 50 | toast.error('Claim occured error.') 51 | } 52 | }) 53 | 54 | // ---------------------------------------------------------------------- 55 | 56 | const amountInNumberType = useMemo(() => { 57 | if (amount[0] === '0') { 58 | if (amount[1] !== '.') 59 | return `${Number(amount)}` 60 | } 61 | return amount 62 | }, [amount]) 63 | 64 | const maxAmount = useMemo(() => { 65 | if (profitInBigint) { 66 | return Number(formatUnits(profitInBigint, asset.decimals)) 67 | } 68 | return 0 69 | }, [profitInBigint]) 70 | 71 | const amountIsValid = useMemo(() => { 72 | if (Number(amount) > maxAmount) { 73 | return false 74 | } 75 | if (Number(amount) <= 0) { 76 | return false 77 | } 78 | return true 79 | }, [amount, maxAmount]) 80 | 81 | // ---------------------------------------------------------------------- 82 | 83 | const handleAmount = (e: ChangeEvent) => { 84 | const { value } = e.target; 85 | 86 | if (value.match(REGEX_NUMBER_VALID)) { 87 | setAmount(value); 88 | } 89 | } 90 | 91 | const handleMaxAmount = () => { 92 | setAmount(maxAmount.toFixed(4)) 93 | } 94 | 95 | const handleHalfAmount = () => { 96 | setAmount(`${(maxAmount / 2).toFixed(4)}`) 97 | } 98 | 99 | const handleSlider = (value: any) => { 100 | setAmount(`${Number(value * maxAmount / 100).toFixed(4)}`) 101 | } 102 | 103 | // ---------------------------------------------------------------------- 104 | 105 | return ( 106 | 107 |
108 |
109 | {asset.symbol}} 111 | onChange={handleAmount} 112 | value={amountInNumberType} 113 | /> 114 | 115 |
116 |

Max: {maxAmount.toFixed(asset.decimals)}{asset.symbol}

117 |
118 | half 119 | max 120 |
121 |
122 | 123 |
124 | 138 |
139 |
140 | 141 | claimProfit?.()} 145 | > 146 | {claimProfitIsLoading ? IN_PROGRESS : 'Claim'} 147 | 148 |
149 |
150 | ) 151 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/ProfitSection/DPRow.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | import { useContractRead } from "wagmi"; 3 | import { formatUnits } from "viem"; 4 | import Td from "../../../components/tableComponents/Td"; 5 | import { IAsset, IReturnValueOfAllowance } from "../../../utils/interfaces" 6 | import { POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS } from "../../../utils/constants"; 7 | import FilledButton from "../../../components/buttons/FilledButton"; 8 | 9 | // --------------------------------------------------------------------------------------------- 10 | 11 | interface IProps { 12 | asset: IAsset; 13 | ethPriceInUsd: number; 14 | usdcPriceInUsd: number; 15 | openDialog: Function; 16 | } 17 | 18 | // --------------------------------------------------------------------------------------------- 19 | 20 | export default function DPRow({ asset, ethPriceInUsd, usdcPriceInUsd, openDialog }: IProps) { 21 | const { data: profitInBigint }: IReturnValueOfAllowance = useContractRead({ 22 | address: POOL_CONTRACT_ADDRESS, 23 | abi: POOL_CONTRACT_ABI, 24 | functionName: 'getProfit', 25 | args: [asset.contractAddress], 26 | watch: true 27 | }) 28 | 29 | // ---------------------------------------------------------------------- 30 | 31 | const profit = useMemo(() => { 32 | if (profitInBigint) { 33 | return Number(formatUnits(profitInBigint, asset.decimals)) 34 | } 35 | return 0 36 | }, [profitInBigint]) 37 | 38 | const profitInUsd = useMemo(() => { 39 | if (asset.symbol === 'eth') { 40 | return profit * ethPriceInUsd 41 | } 42 | return profit * usdcPriceInUsd 43 | }, [profit]) 44 | 45 | // ---------------------------------------------------------------------- 46 | 47 | return ( 48 | 49 | {/* Token */} 50 | 51 |
52 | {asset.name} 53 | {asset.symbol} 54 |
55 | 56 | 57 | {/* Profit */} 58 | {profit} {asset.symbol} 59 | 60 | {/* Profit in USD */} 61 | ${profitInUsd.toFixed(2)} 62 | 63 | 64 | openDialog(asset)}> 65 | Claim 66 | 67 | 68 | 69 | ) 70 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/ProfitSection/MBRow.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | import { useContractRead } from "wagmi"; 3 | import { formatUnits } from "viem"; 4 | import { IAsset, IReturnValueOfAllowance } from "../../../utils/interfaces"; 5 | import { POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS } from "../../../utils/constants"; 6 | import FilledButton from "../../../components/buttons/FilledButton"; 7 | 8 | // ------------------------------------------------------------------------------------------------------- 9 | 10 | interface IProps { 11 | asset: IAsset; 12 | ethPriceInUsd: number; 13 | usdcPriceInUsd: number; 14 | openDialog: Function; 15 | } 16 | 17 | // ------------------------------------------------------------------------------------------------------- 18 | 19 | export default function MBRow({ asset, ethPriceInUsd, usdcPriceInUsd, openDialog }: IProps) { 20 | const { data: profitInBigint }: IReturnValueOfAllowance = useContractRead({ 21 | address: POOL_CONTRACT_ADDRESS, 22 | abi: POOL_CONTRACT_ABI, 23 | functionName: 'getProfit', 24 | args: [asset.contractAddress], 25 | watch: true 26 | }) 27 | 28 | // ---------------------------------------------------------------------- 29 | 30 | const profit = useMemo(() => { 31 | if (profitInBigint) { 32 | return Number(formatUnits(profitInBigint, asset.decimals)) 33 | } 34 | return 0 35 | }, [profitInBigint]) 36 | 37 | const profitInUsd = useMemo(() => { 38 | if (asset.symbol === 'eth') { 39 | return profit * ethPriceInUsd 40 | } 41 | return profit * usdcPriceInUsd 42 | }, [profit]) 43 | 44 | // ---------------------------------------------------------------------- 45 | 46 | return ( 47 |
48 | {/* Token */} 49 |
50 | Token: 51 |
52 | 53 | {asset.symbol} 54 |
55 |
56 | 57 | {/* Profit */} 58 |
59 | Profit: 60 | {profit} {asset.symbol} 61 |
62 | 63 | {/* Profit in USD */} 64 |
65 | Profit in USD: 66 | ${profitInUsd.toFixed(2)} 67 |
68 | 69 |
70 | Profit in USD: 71 | openDialog(asset)}> 72 | Claim 73 | 74 |
75 |
76 | ) 77 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/ProfitSection/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import { useMediaQuery } from "react-responsive"; 3 | import Section from "../../../components/Section"; 4 | import Table from "../../../components/tableComponents/Table"; 5 | import Th from "../../../components/tableComponents/Th"; 6 | import { ASSETS } from "../../../utils/constants"; 7 | import { IAsset } from "../../../utils/interfaces"; 8 | 9 | // --------------------------------------------------------------------------------------------- 10 | 11 | const DPRow = lazy(() => import('./DPRow')) 12 | const ClaimProfitDialog = lazy(() => import('./ClaimProfitDialog')) 13 | 14 | // --------------------------------------------------------------------------------------------- 15 | 16 | interface IProps { 17 | ethPriceInUsd: number; 18 | usdcPriceInUsd: number; 19 | } 20 | 21 | // --------------------------------------------------------------------------------------------- 22 | 23 | export default function ProfitSection({ ethPriceInUsd, usdcPriceInUsd }: IProps) { 24 | const isMobile = useMediaQuery({ maxWidth: 640 }) 25 | 26 | const [dialogVisible, setDialogVisible] = useState(false) 27 | const [assetToBeClaimed, setAssetToBeClaimed] = useState(ASSETS[0]) 28 | 29 | const openDialog = (asset: IAsset) => { 30 | setAssetToBeClaimed(asset) 31 | setDialogVisible(true) 32 | } 33 | 34 | return ( 35 |
36 | {isMobile ? ( 37 |
38 | 39 |
40 | ) : ( 41 | 42 | 43 | 44 | 49 | 50 | 51 | {ASSETS.map(asset => ( 52 | 59 | ))} 60 | 61 |
45 | 46 | 47 | 48 |
62 | )} 63 | 68 |
69 | ) 70 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/TokensSection/DPRow.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | import { useAccount, useBalance } from "wagmi"; 3 | import Td from "../../../components/tableComponents/Td"; 4 | import { IAsset, IReturnValueOfBalance } from "../../../utils/interfaces"; 5 | import { USDC_CONTRACT_ADDRESS } from "../../../utils/constants"; 6 | 7 | // ------------------------------------------------------------------------------------------------ 8 | 9 | interface IProps { 10 | asset: IAsset; 11 | ethPriceInUsd: number; 12 | usdcPriceInUsd: number; 13 | } 14 | 15 | // ------------------------------------------------------------------------------------------------ 16 | 17 | export default function DPRow({ asset, ethPriceInUsd, usdcPriceInUsd }: IProps) { 18 | const { address } = useAccount() 19 | 20 | // Balance data 21 | const { data: balanceData }: IReturnValueOfBalance = useBalance({ 22 | address, 23 | token: asset.symbol === 'usdc' ? USDC_CONTRACT_ADDRESS : undefined 24 | }) 25 | 26 | const balanceInUsd = useMemo(() => { 27 | if (balanceData) { 28 | return Number(balanceData.formatted) * (asset.symbol === 'eth' ? ethPriceInUsd : usdcPriceInUsd); 29 | } 30 | return 0 31 | }, [balanceData]) 32 | 33 | return ( 34 | 35 | 36 |
37 | 38 | {asset.symbol} 39 |
40 | 41 | 42 | {Number(balanceData?.formatted).toFixed(4)} {asset.symbol} 43 | 44 | 45 | $ {asset.symbol === 'eth' ? ethPriceInUsd.toFixed(2) : usdcPriceInUsd.toFixed(2)} 46 | 47 | ${balanceInUsd.toFixed(2)} 48 | 49 | ) 50 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/TokensSection/MBRow.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | import { useAccount, useBalance } from "wagmi"; 3 | import { ListItem } from "@material-tailwind/react"; 4 | import { IAsset, IReturnValueOfBalance } from "../../../utils/interfaces"; 5 | import { USDC_CONTRACT_ADDRESS } from "../../../utils/constants"; 6 | 7 | // ---------------------------------------------------------------------------------- 8 | 9 | interface IProps { 10 | asset: IAsset; 11 | ethPriceInUsd: number; 12 | usdcPriceInUsd: number; 13 | } 14 | 15 | // ---------------------------------------------------------------------------------- 16 | 17 | export default function MBRow({ asset, ethPriceInUsd, usdcPriceInUsd }: IProps) { 18 | const { address } = useAccount() 19 | 20 | // Balance data 21 | const { data: balanceData }: IReturnValueOfBalance = useBalance({ 22 | address, 23 | token: asset.symbol === 'usdc' ? USDC_CONTRACT_ADDRESS : undefined 24 | }) 25 | 26 | const balanceInUsd = useMemo(() => { 27 | if (balanceData) { 28 | return Number(balanceData.formatted) * (asset.symbol === 'eth' ? ethPriceInUsd : usdcPriceInUsd); 29 | } 30 | return 0 31 | }, [balanceData]) 32 | 33 | // ------------------------------------------------------------------------------------------ 34 | 35 | return ( 36 |
39 | {/* Symbol */} 40 |
41 | Symbol: 42 |
43 | 44 | {asset.symbol} 45 |
46 |
47 | 48 | {/* Balance */} 49 |
50 | Balance: 51 | {Number(balanceData?.formatted).toFixed(4)} {asset.symbol} 52 |
53 | 54 | {/* Price */} 55 |
56 | Price: 57 | ${asset.symbol === 'eth' ? ethPriceInUsd.toFixed(2) : usdcPriceInUsd.toFixed(2)} 58 |
59 | 60 | {/* Value */} 61 |
62 | Value: 63 | ${balanceInUsd.toFixed(2)} 64 |
65 |
66 | ) 67 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/TokensSection/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from "react"; 2 | import Table from "../../../components/tableComponents/Table"; 3 | import Th from "../../../components/tableComponents/Th"; 4 | import Section from "../../../components/Section"; 5 | import { ASSETS } from "../../../utils/constants"; 6 | import { useMediaQuery } from "react-responsive"; 7 | 8 | // ------------------------------------------------------------------------------------------------------ 9 | 10 | const DPRow = lazy(() => import('./DPRow')) 11 | const MBRow = lazy(() => import('./MBRow')) 12 | 13 | // ------------------------------------------------------------------------------------------------------ 14 | 15 | interface IProps { 16 | ethPriceInUsd: number; 17 | usdcPriceInUsd: number; 18 | } 19 | 20 | // ------------------------------------------------------------------------------------------------------ 21 | 22 | export default function TokensSection({ ethPriceInUsd, usdcPriceInUsd }: IProps) { 23 | const isMobile = useMediaQuery({ maxWidth: 640 }); 24 | 25 | return ( 26 |
27 | {isMobile ? ( 28 |
29 | {ASSETS.map(asset => ( 30 | 31 | ))} 32 |
33 | ) : ( 34 | 35 | 36 | 37 | 42 | 43 | 44 | 45 | {ASSETS.map(asset => ( 46 | 47 | ))} 48 | 49 |
38 | 39 | 40 | 41 |
50 | )} 51 | 52 |
53 | ) 54 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/UserProfileSection/LiquidationsBoard/Row.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import Tr from "../../../../components/tableComponents/Tr"; 4 | import { ILiquidation } from "../../../../utils/interfaces"; 5 | import { USDC_DECIMAL } from "../../../../utils/constants"; 6 | import Td from "../../../../components/tableComponents/Td"; 7 | import FilledButton from "../../../../components/buttons/FilledButton"; 8 | 9 | // ----------------------------------------------------------------------------------------- 10 | 11 | interface IProps { 12 | liquidation: ILiquidation; 13 | ethPriceInUsd: number; 14 | usdcPriceInUsd: number; 15 | openLiquidateDialog: Function; 16 | } 17 | 18 | // ----------------------------------------------------------------------------------------- 19 | 20 | export default function Row({ liquidation, ethPriceInUsd, usdcPriceInUsd, openLiquidateDialog }: IProps) { 21 | const [borrowedValueInUsd, setBorrowedValueInUsd] = useState(0) 22 | const [depositedValueInUsd, setDepositedValueInUsd] = useState(0) 23 | 24 | // ---------------------------------------------------------------------------------------- 25 | 26 | useEffect(() => { 27 | const _borrowedValueInUsd = Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)) * ethPriceInUsd + 28 | Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)) * usdcPriceInUsd 29 | const _depositedValueInUsd = Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)) * ethPriceInUsd + 30 | Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)) * usdcPriceInUsd 31 | 32 | setBorrowedValueInUsd(_borrowedValueInUsd) 33 | setDepositedValueInUsd(_depositedValueInUsd) 34 | }, [liquidation]) 35 | 36 | // ---------------------------------------------------------------------------------------- 37 | return ( 38 | 39 | {/* Borrowed Value */} 40 | 41 | {liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 42 |
43 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 44 | 45 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 46 | 47 |
48 | ) : !liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 49 | 50 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 51 | 52 | ) : ( 53 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 54 | )} 55 | 56 | 57 | {/* Deposited Value */} 58 | 59 | {liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 60 |
61 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 62 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 63 |
64 | ) : !liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 65 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 66 | ) : ( 67 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 68 | )} 69 | 70 | 71 | {/* Risk Factor */} 72 | 73 | {liquidation.riskFactor.toFixed(4)} % 74 | 75 | 76 | 77 | openLiquidateDialog(liquidation)}> 78 | Liquidate 79 | 80 | 81 | 82 | ) 83 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/UserProfileSection/LiquidationsBoard/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useEffect, useMemo, useState } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import { useAccount, useContractRead } from "wagmi"; 4 | import PrimaryBoard from "../../../../components/boards/PrimaryBoard"; 5 | import Table from "../../../../components/tableComponents/Table"; 6 | import Th from "../../../../components/tableComponents/Th"; 7 | import { ILiquidation, IReturnValueOfAllowance, IReturnValueOfListOfUsers, IUserInfo } from "../../../../utils/interfaces"; 8 | import { POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, USDC_DECIMAL } from "../../../../utils/constants"; 9 | 10 | const Row = lazy(() => import('./Row')) 11 | const LiquidateDialog = lazy(() => import('../../../../components/LiquidateDialog')) 12 | 13 | // ----------------------------------------------------------------------------------------- 14 | 15 | interface IProps { 16 | userInfo: IUserInfo; 17 | ethPriceInUsd: number; 18 | usdcPriceInUsd: number; 19 | } 20 | 21 | // ----------------------------------------------------------------------------------------- 22 | 23 | export default function LiquidationsBoard({ userInfo, ethPriceInUsd, usdcPriceInUsd }: IProps) { 24 | const [selectedLiquidation, setSelectedLiquidation] = useState(null) 25 | const [liquidateDialogOpened, setLiquidateDialogOpened] = useState(false) 26 | const [currentPage, setCurrentPage] = useState(0) 27 | const [liquidations, setLiquidations] = useState>([]) 28 | 29 | // ------------------------------------------------------------------------------- 30 | 31 | const { address } = useAccount() 32 | 33 | // Get listOfUsers 34 | const { data: listOfUsers }: IReturnValueOfListOfUsers = useContractRead({ 35 | address: POOL_CONTRACT_ADDRESS, 36 | abi: POOL_CONTRACT_ABI, 37 | functionName: 'listUserInfo', 38 | args: [currentPage], 39 | watch: true, 40 | onSuccess: () => { 41 | if (numberOfPages > currentPage) { 42 | setCurrentPage(currentPage + 1) 43 | } 44 | } 45 | }) 46 | 47 | const { data: liquidatationThresholdInBigInt } = useContractRead({ 48 | address: POOL_CONTRACT_ADDRESS, 49 | abi: POOL_CONTRACT_ABI, 50 | functionName: 'getLiquidationThreshhold', 51 | watch: true 52 | }) 53 | 54 | const { data: numberOfUsersInBigint }: IReturnValueOfAllowance = useContractRead({ 55 | address: POOL_CONTRACT_ADDRESS, 56 | abi: POOL_CONTRACT_ABI, 57 | functionName: 'getMemberNumber', 58 | watch: true 59 | }) 60 | 61 | // ------------------------------------------------------------------------------- 62 | 63 | const openLiquidateDialog = (liquidation: ILiquidation) => { 64 | setSelectedLiquidation(liquidation) 65 | setLiquidateDialogOpened(true) 66 | } 67 | 68 | const closeLiquidateDialog = () => { 69 | setSelectedLiquidation(null) 70 | setLiquidateDialogOpened(false) 71 | } 72 | 73 | // ------------------------------------------------------------------------------- 74 | 75 | // const liquidations = useMemo>(() => { 76 | // if (listOfUsers) { 77 | // let _liquidations = []; 78 | 79 | // for (let i = 0; i < listOfUsers.length; i += 1) { 80 | // if (address === listOfUsers[i].accountAddress) { 81 | // if (listOfUsers[i].ethBorrowAmount || listOfUsers[i].usdtBorrowAmount) { 82 | // let depositedValueInUsd = Number(formatEther(listOfUsers[i].ethDepositAmount + listOfUsers[i].ethRewardAmount)) * ethPriceInUsd + Number(formatUnits(listOfUsers[i].usdtDepositAmount + listOfUsers[i].usdtDepositAmount, USDC_DECIMAL)) * usdcPriceInUsd 83 | // let borrowedValueInUsd = Number(formatEther(listOfUsers[i].ethBorrowAmount + listOfUsers[i].ethInterestAmount)) * ethPriceInUsd + Number(formatUnits(listOfUsers[i].usdtBorrowAmount + listOfUsers[i].usdtInterestAmount, USDC_DECIMAL)) * usdcPriceInUsd 84 | 85 | // if (depositedValueInUsd > 0) { 86 | // let riskFactor = borrowedValueInUsd / (depositedValueInUsd * 0.9) * 100 87 | // if (riskFactor > Number(liquidatationThresholdInBigInt)) { 88 | // _liquidations.push({ ...listOfUsers[i], riskFactor }) 89 | // } 90 | // } 91 | // } 92 | // } 93 | // } 94 | 95 | // return _liquidations 96 | // } 97 | // return [] 98 | // }, [listOfUsers]) 99 | 100 | // The threshold of liquidation 101 | const liquidationThreshold = useMemo(() => { 102 | if (liquidatationThresholdInBigInt) { 103 | return Number(liquidatationThresholdInBigInt) 104 | } 105 | return 0 106 | }, [liquidatationThresholdInBigInt]) 107 | 108 | // The number of users 109 | const numberOfUsers = useMemo(() => { 110 | if (numberOfUsersInBigint) { 111 | return Number(numberOfUsersInBigint) 112 | } 113 | return 0 114 | }, [numberOfUsersInBigint]) 115 | 116 | const numberOfPages = useMemo(() => { 117 | return Math.ceil(numberOfUsers / 100) 118 | }, [numberOfUsers]) 119 | 120 | // ------------------------------------------------------------------------------- 121 | 122 | useEffect(() => { 123 | console.log('>>>>>>>>>> listOfUsers => ', listOfUsers) 124 | if (listOfUsers) { 125 | const _liquidations = []; 126 | for (let i = 0; i < listOfUsers.length; i += 1) { 127 | if (address === listOfUsers[i].accountAddress) { 128 | if (listOfUsers[i].ethBorrowAmount || listOfUsers[i].usdtBorrowAmount) { 129 | let depositedValueInUsd = Number(formatEther(listOfUsers[i].ethDepositAmount + listOfUsers[i].ethRewardAmount)) * ethPriceInUsd + Number(formatUnits(listOfUsers[i].usdtDepositAmount + listOfUsers[i].usdtDepositAmount, USDC_DECIMAL)) * usdcPriceInUsd 130 | let borrowedValueInUsd = Number(formatEther(listOfUsers[i].ethBorrowAmount + listOfUsers[i].ethInterestAmount)) * ethPriceInUsd + Number(formatUnits(listOfUsers[i].usdtBorrowAmount + listOfUsers[i].usdtInterestAmount, USDC_DECIMAL)) * usdcPriceInUsd 131 | 132 | if (depositedValueInUsd > 0) { 133 | let riskFactor = borrowedValueInUsd / depositedValueInUsd * 100 134 | if (riskFactor > liquidationThreshold) { 135 | _liquidations.push({ ...listOfUsers[i], riskFactor }) 136 | } 137 | } 138 | } 139 | } 140 | } 141 | if (currentPage === 0) { 142 | setLiquidations(_liquidations) 143 | } else { 144 | setLiquidations([...liquidations, ..._liquidations]) 145 | } 146 | } 147 | }, [listOfUsers, currentPage]) 148 | 149 | // ------------------------------------------------------------------------------- 150 | 151 | return ( 152 | 153 | 154 | 155 | 156 | 161 | 162 | 163 | 164 | {liquidations.map(liquadationItem => ( 165 | 171 | ))} 172 | 173 |
157 | 158 | 159 | 160 |
174 | 180 |
181 | ) 182 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/UserProfileSection/UserReservesBoard/Row.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { formatUnits } from "viem"; 3 | import { useContractRead } from "wagmi"; 4 | import Td from "../../../../components/tableComponents/Td"; 5 | import { IAsset, IReturnValueOfPoolInfo, IUserInfo } from "../../../../utils/interfaces"; 6 | import { APY_DECIMAL, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS } from "../../../../utils/constants"; 7 | 8 | // ---------------------------------------------------------------------------------------------------- 9 | 10 | interface IProps { 11 | asset: IAsset; 12 | ethPriceInUsd: number; 13 | usdcPriceInUsd: number; 14 | userInfo: IUserInfo; 15 | } 16 | 17 | // ---------------------------------------------------------------------------------------------------- 18 | 19 | export default function Row({ asset, ethPriceInUsd, usdcPriceInUsd, userInfo }: IProps) { 20 | const [assetPriceInUsd, setAssetPriceInUsd] = useState(0) 21 | const [depositApy, setDepositApy] = useState(0) 22 | const [borrowApy, setBorrowApy] = useState(0) 23 | const [depositAmount, setDepositAmount] = useState(0) 24 | const [borrowAmount, setBorrowAmount] = useState(0) 25 | const [depositAmountInUsd, setDepositAmountInUsd] = useState(0) 26 | const [borrowAmountInUsd, setBorrowAmountInUsd] = useState(0) 27 | 28 | // ---------------------------------------------------------------------------- 29 | 30 | const { data: poolInfo }: IReturnValueOfPoolInfo = useContractRead({ 31 | address: POOL_CONTRACT_ADDRESS, 32 | abi: POOL_CONTRACT_ABI, 33 | functionName: 'getPoolInfo', 34 | args: [asset.contractAddress], 35 | watch: true 36 | }) 37 | 38 | // ---------------------------------------------------------------------------- 39 | 40 | useEffect(() => { 41 | if (asset.symbol === 'eth') { 42 | setAssetPriceInUsd(ethPriceInUsd) 43 | } else if (asset.symbol === 'usdc') { 44 | setAssetPriceInUsd(usdcPriceInUsd) 45 | } 46 | }, [asset]) 47 | 48 | useEffect(() => { 49 | if (userInfo) { 50 | let _depositAmount = 0; 51 | let _borrowAmount = 0; 52 | 53 | if (asset.symbol === 'eth') { 54 | _depositAmount = Number(formatUnits(userInfo.ethDepositAmount + userInfo.ethRewardAmount, asset.decimals)) 55 | _borrowAmount = Number(formatUnits(userInfo.ethBorrowAmount + userInfo.ethInterestAmount, asset.decimals)) 56 | } else { 57 | _depositAmount = Number(formatUnits(userInfo.usdtDepositAmount + userInfo.usdtRewardAmount, asset.decimals)) 58 | _borrowAmount = Number(formatUnits(userInfo.usdtBorrowAmount + userInfo.usdtInterestAmount, asset.decimals)) 59 | } 60 | 61 | setDepositAmount(_depositAmount) 62 | setBorrowAmount(_borrowAmount) 63 | 64 | if (asset.symbol === 'eth') { 65 | setDepositAmountInUsd(_depositAmount * ethPriceInUsd) 66 | setBorrowAmountInUsd(_borrowAmount * ethPriceInUsd) 67 | } else if (asset.symbol === 'usdc') { 68 | setDepositAmountInUsd(_depositAmount * usdcPriceInUsd) 69 | setBorrowAmountInUsd(_borrowAmount * usdcPriceInUsd) 70 | } 71 | } 72 | }, [userInfo, asset]) 73 | 74 | useEffect(() => { 75 | if (poolInfo) { 76 | setDepositApy(Number(formatUnits(poolInfo.depositApy, APY_DECIMAL))) 77 | setBorrowApy(Number(formatUnits(poolInfo.borrowApy, APY_DECIMAL))) 78 | } 79 | }, [poolInfo]) 80 | 81 | // ---------------------------------------------------------------------------- 82 | 83 | return ( 84 | <> 85 | {depositAmount > 0 && ( 86 | 87 | {/* Asset */} 88 | 89 |
90 | 91 |
92 |

{asset.symbol}(deposit)

93 | 94 | ${assetPriceInUsd.toFixed(2)} 95 | 96 |
97 |
98 | 99 | 100 | {/* APY */} 101 | 102 | {depositApy.toFixed(2)}% 103 | 104 | 105 | {/* Amount */} 106 | 107 |
108 | {depositAmount.toFixed(4)} {asset.symbol} 109 | ${depositAmountInUsd.toFixed(2)} 110 |
111 | 112 | 113 | )} 114 | 115 | {borrowAmount > 0 && ( 116 | 117 | {/* Asset */} 118 | 119 |
120 | 121 |
122 |

{asset.symbol}(borrow)

123 | 124 | ${assetPriceInUsd.toFixed(2)} 125 | 126 |
127 |
128 | 129 | 130 | {/* APY */} 131 | 132 | {borrowApy.toFixed(2)}% 133 | 134 | 135 | {/* Amount */} 136 | 137 |
138 | {borrowAmount.toFixed(4)} {asset.symbol} 139 | ${borrowAmountInUsd.toFixed(2)} 140 |
141 | 142 | 143 | )} 144 | 145 | ) 146 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/UserProfileSection/UserReservesBoard/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useMemo } from "react"; 2 | import PrimaryBoard from "../../../../components/boards/PrimaryBoard"; 3 | import Table from "../../../../components/tableComponents/Table"; 4 | import Th from "../../../../components/tableComponents/Th"; 5 | import { IUserInfo } from "../../../../utils/interfaces"; 6 | import { ASSETS, USDC_DECIMAL } from "../../../../utils/constants"; 7 | import { formatEther, formatUnits } from "viem"; 8 | 9 | // --------------------------------------------------------------------------------------------- 10 | 11 | const Row = lazy(() => import('./Row')) 12 | 13 | // --------------------------------------------------------------------------------------------- 14 | 15 | interface IProps { 16 | userInfo: IUserInfo; 17 | ethPriceInUsd: number; 18 | usdcPriceInUsd: number; 19 | } 20 | 21 | // --------------------------------------------------------------------------------------------- 22 | 23 | export default function UserReservesBoard({ userInfo, ethPriceInUsd, usdcPriceInUsd }: IProps) { 24 | const totalAmountInUsd = useMemo(() => { 25 | const depositAmountInUsd = Number(formatEther(userInfo.ethDepositAmount)) * ethPriceInUsd + Number(formatUnits(userInfo.usdtDepositAmount, USDC_DECIMAL)) * usdcPriceInUsd; 26 | const borrowAmountInUsd = Number(formatEther(userInfo.ethBorrowAmount)) * ethPriceInUsd + Number(formatUnits(userInfo.usdtBorrowAmount, USDC_DECIMAL)) * usdcPriceInUsd 27 | 28 | return depositAmountInUsd - borrowAmountInUsd 29 | }, [userInfo]) 30 | 31 | return ( 32 | ${totalAmountInUsd.toFixed(2)}} 36 | > 37 | {/*

You have no profile to deposit or borrow.

38 | Create profile */} 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | {ASSETS.map(asset => ( 50 | 51 | ))} 52 | 53 |
43 | 44 | 45 |
54 |
55 | ) 56 | } -------------------------------------------------------------------------------- /src/pages/Dashboard/UserProfileSection/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from "react"; 2 | import PrimaryBoard from "../../../components/boards/PrimaryBoard"; 3 | import Section from "../../../components/Section"; 4 | import { IUserInfo } from "../../../utils/interfaces"; 5 | 6 | // -------------------------------------------------------------------------------------------- 7 | 8 | const UserReservesBoard = lazy(() => import('./UserReservesBoard')) 9 | const LiquidationsBoard = lazy(() => import('./LiquidationsBoard')) 10 | 11 | // -------------------------------------------------------------------------------------------- 12 | 13 | interface IProps { 14 | userInfo: IUserInfo; 15 | ethPriceInUsd: number; 16 | usdcPriceInUsd: number; 17 | } 18 | 19 | // -------------------------------------------------------------------------------------------- 20 | 21 | export default function UserProfileSection({ userInfo, ethPriceInUsd, usdcPriceInUsd }: IProps) { 22 | 23 | return ( 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | ) 32 | } -------------------------------------------------------------------------------- /src/pages/Lending/AssetDialog/MoreInfo.tsx: -------------------------------------------------------------------------------- 1 | export default function MoreInfo() { 2 | return ( 3 |
4 |
5 | Reserve Address 6 |
7 |
8 | Reserve Address 9 |
10 |
11 | Reserve Address 12 |
13 |
14 | Reserve Address 15 |
16 |
17 | Reserve Address 18 |
19 |
20 | Reserve Address 21 |
22 |
23 | Reserve Address 24 |
25 |
26 | Reserve Address 27 |
28 |
29 | ) 30 | } -------------------------------------------------------------------------------- /src/pages/Lending/AssetDialog/index.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { useAccount, useBalance, useContractRead } from "wagmi"; 3 | import TextButton from "../../../components/buttons/TextButton"; 4 | import CustomDialog from "../../../components/dialogs/CustomDialog"; 5 | import DepositTab from "./DepositTab"; 6 | import WithdrawTab from "./WithdrawTab"; 7 | import BorrowTab from "./BorrowTab"; 8 | import RepayTab from "./RepayTab"; 9 | import { POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, USDC_CONTRACT_ADDRESS } from "../../../utils/constants"; 10 | import { IAsset, IReturnValueOfPoolInfo, IUserInfo } from "../../../utils/interfaces"; 11 | 12 | // -------------------------------------------------------------------------------------------- 13 | 14 | type TTabValue = 'deposit' | 'withdraw' | 'borrow' | 'repay' 15 | 16 | interface IProps { 17 | visible: boolean; 18 | setVisible: Function; 19 | asset: IAsset 20 | ethPriceInUsd: number; 21 | usdcPriceInUsd: number; 22 | userInfo?: IUserInfo; 23 | } 24 | 25 | // -------------------------------------------------------------------------------------------- 26 | 27 | export default function AssetDialog({ visible, setVisible, asset, ethPriceInUsd, usdcPriceInUsd, userInfo }: IProps) { 28 | const [tabValue, setTabValue] = useState('deposit') 29 | 30 | // ----------------------------------------------------------------- 31 | 32 | const { address } = useAccount(); 33 | 34 | // ----------------------------------------------------------------- 35 | 36 | // Balance data 37 | const { data: balanceData } = useBalance({ 38 | address, 39 | token: asset.symbol === 'usdc' ? USDC_CONTRACT_ADDRESS : undefined, 40 | watch: true 41 | }) 42 | 43 | // Get PoolInfo 44 | const { data: poolInfo }: IReturnValueOfPoolInfo = useContractRead({ 45 | address: POOL_CONTRACT_ADDRESS, 46 | abi: POOL_CONTRACT_ABI, 47 | functionName: 'getPoolInfo', 48 | args: [asset.contractAddress], 49 | watch: true 50 | }) 51 | 52 | // ----------------------------------------------------------------- 53 | 54 | return ( 55 | 56 |
57 | setTabValue('deposit')} 60 | >Deposit 61 | setTabValue('withdraw')} 64 | >Withdraw 65 | setTabValue('borrow')} 68 | >Borrow 69 | setTabValue('repay')} 72 | >Repay 73 |
74 |
75 | {tabValue === 'deposit' ? 76 | : tabValue === 'withdraw' ? 83 | : tabValue === 'borrow' ? 92 | : 106 | } 107 |
108 |
109 | ) 110 | } -------------------------------------------------------------------------------- /src/pages/Lending/BorrowBoard/Position.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import { IAsset, IUserInfo } from "../../../utils/interfaces"; 4 | 5 | // -------------------------------------------------------------------------------------------- 6 | 7 | interface IProps { 8 | asset: IAsset; 9 | ethPriceInUsd: number; 10 | usdcPriceInUsd: number; 11 | userInfo: IUserInfo; 12 | } 13 | 14 | // -------------------------------------------------------------------------------------------- 15 | 16 | export default function Position({ asset, ethPriceInUsd, usdcPriceInUsd, userInfo }: IProps) { 17 | const [assetAmount, setAssetAmount] = useState(0) 18 | const [assetAmountInUsd, setAssetAmountInUsd] = useState(0) 19 | 20 | useEffect(() => { 21 | let _assetAmount = 0; 22 | if (asset.symbol === 'eth') { 23 | _assetAmount = Number(formatEther(userInfo.ethBorrowAmount)) + Number(formatEther(userInfo.ethInterestAmount)) 24 | setAssetAmount(_assetAmount) 25 | setAssetAmountInUsd(_assetAmount * ethPriceInUsd) 26 | } else { 27 | _assetAmount = Number(formatUnits(userInfo.usdtBorrowAmount, asset.decimals)) + Number(formatUnits(userInfo.usdtInterestAmount, asset.decimals)) 28 | setAssetAmount(_assetAmount) 29 | setAssetAmountInUsd(_assetAmount * usdcPriceInUsd) 30 | } 31 | }, [asset, userInfo]) 32 | 33 | return ( 34 |
35 |
36 | 37 |
38 | {asset.symbol} 39 | ${asset.symbol === 'eth' ? ethPriceInUsd.toFixed(2) : usdcPriceInUsd.toFixed(2)} 40 |
41 |
42 |
43 | 44 | {assetAmount.toFixed(4)} {asset.symbol} 45 | 46 | 47 | ${assetAmountInUsd.toFixed(2)} 48 | 49 |
50 |
51 | ) 52 | } -------------------------------------------------------------------------------- /src/pages/Lending/BorrowBoard/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useMemo } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import PrimaryBoard from "../../../components/boards/PrimaryBoard"; 4 | import { ASSETS, USDC_DECIMAL } from "../../../utils/constants"; 5 | import { IUserInfo } from "../../../utils/interfaces"; 6 | 7 | // ---------------------------------------------------------------------------------------------- 8 | 9 | const Position = lazy(() => import('./Position')) 10 | 11 | // ---------------------------------------------------------------------------------------------- 12 | 13 | interface IProps { 14 | ethPriceInUsd: number; 15 | usdcPriceInUsd: number; 16 | userInfo: IUserInfo; 17 | } 18 | 19 | // ---------------------------------------------------------------------------------------------- 20 | 21 | export default function BorrowBoard({ userInfo, ethPriceInUsd, usdcPriceInUsd }: IProps) { 22 | const totalAmountInUsd = useMemo(() => { 23 | const ethAmountInUsd = Number(formatEther(userInfo.ethBorrowAmount)) * ethPriceInUsd; 24 | const usdcAmountInUsd = Number(formatUnits(userInfo.usdtBorrowAmount, USDC_DECIMAL)) * usdcPriceInUsd; 25 | return ethAmountInUsd + usdcAmountInUsd 26 | }, [userInfo]) 27 | 28 | return ( 29 | ${totalAmountInUsd.toFixed(2)}}> 30 |
31 | {ASSETS.map(asset => ( 32 | 33 | ))} 34 |
35 |
36 | ) 37 | } -------------------------------------------------------------------------------- /src/pages/Lending/DPRow.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useMemo, useState } from "react"; 2 | import { useAccount, useBalance, useContractRead } from "wagmi"; 3 | import { formatEther, formatUnits } from "viem"; 4 | import Td from "../../components/tableComponents/Td"; 5 | import Tr from "../../components/tableComponents/Tr"; 6 | import { IAsset, IReturnValueOfBalance, IReturnValueOfPoolInfo } from "../../utils/interfaces"; 7 | import { APY_DECIMAL, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, USDC_CONTRACT_ADDRESS, USDC_DECIMAL } from "../../utils/constants"; 8 | 9 | // ---------------------------------------------------------------------------------- 10 | 11 | interface IProps { 12 | asset: IAsset; 13 | openDialog: Function; 14 | ethPriceInUsd: number; 15 | usdcPriceInUsd: number; 16 | } 17 | 18 | // ---------------------------------------------------------------------------------- 19 | 20 | export default function DPRow({ asset, openDialog, ethPriceInUsd, usdcPriceInUsd }: IProps) { 21 | const [marketSize, setMarketSize] = useState(0) 22 | const [marketSizeInUsd, setMarketSizeInUsd] = useState(0) 23 | const [totalBorrowed, setTotalBorrowed] = useState(0) 24 | const [totalBorrowedInUsd, setTotalBorrowedInUsd] = useState(0) 25 | const [depositApyInPercentage, setDepositApyInPercentage] = useState(0) 26 | const [borrowApyInPercentage, setBorrowApyInPercentage] = useState(0) 27 | 28 | // --------------------------------------------------------------------------------- 29 | 30 | const { address, isConnected } = useAccount() 31 | 32 | // --------------------------------------------------------------------------------- 33 | // Balance data of the wallet 34 | const { data: balanceDataOfWallet }: IReturnValueOfBalance = useBalance({ 35 | address, 36 | token: asset.symbol === 'usdc' ? USDC_CONTRACT_ADDRESS : undefined, 37 | watch: true 38 | }) 39 | 40 | // The info of the pool 41 | const { data: poolInfo }: IReturnValueOfPoolInfo = useContractRead({ 42 | address: POOL_CONTRACT_ADDRESS, 43 | abi: POOL_CONTRACT_ABI, 44 | functionName: 'getPoolInfo', 45 | args: [asset.contractAddress], 46 | watch: true 47 | }) 48 | 49 | // ---------------------------------------------------------------------------------- 50 | 51 | const balanceOfWalletInUsd = useMemo(() => { 52 | if (balanceDataOfWallet) { 53 | return Number(balanceDataOfWallet.formatted) * (asset.symbol === 'eth' ? ethPriceInUsd : usdcPriceInUsd); 54 | } 55 | return 0 56 | }, [balanceDataOfWallet]) 57 | 58 | // ---------------------------------------------------------------------------------- 59 | 60 | // Get market size, total borrowed, deposit APY, and borrow APY. 61 | 62 | useEffect(() => { 63 | if (poolInfo) { 64 | setMarketSize(Number(formatEther(poolInfo.totalAmount))) 65 | if (asset.symbol === 'eth') { 66 | setMarketSize(Number(formatEther(poolInfo.totalAmount))) 67 | setMarketSizeInUsd(Number(formatEther(poolInfo.totalAmount)) * ethPriceInUsd) 68 | setTotalBorrowed(Number(formatEther(poolInfo.borrowAmount))) 69 | setTotalBorrowedInUsd(Number(formatEther(poolInfo.borrowAmount)) * ethPriceInUsd) 70 | } else { 71 | setMarketSize(Number(formatUnits(poolInfo.totalAmount, USDC_DECIMAL))) 72 | setMarketSizeInUsd(Number(formatUnits(poolInfo.totalAmount, USDC_DECIMAL)) * usdcPriceInUsd) 73 | setTotalBorrowed(Number(formatUnits(poolInfo.borrowAmount, asset.decimals))) 74 | setTotalBorrowedInUsd(Number(formatUnits(poolInfo.borrowAmount, asset.decimals)) * usdcPriceInUsd) 75 | } 76 | setDepositApyInPercentage(Number(formatUnits(poolInfo.depositApy, APY_DECIMAL))) 77 | setBorrowApyInPercentage(Number(formatUnits(poolInfo.borrowApy, APY_DECIMAL))) 78 | } else { 79 | setMarketSize(0) 80 | setMarketSizeInUsd(0) 81 | setTotalBorrowed(0) 82 | setTotalBorrowedInUsd(0) 83 | setDepositApyInPercentage(0) 84 | setBorrowApyInPercentage(0) 85 | } 86 | }, [poolInfo]) 87 | 88 | // ---------------------------------------------------------------------------------- 89 | 90 | return ( 91 | openDialog(asset)}> 92 | {/* Asset Name */} 93 | 94 |
95 | 96 |
97 | {asset.name} 98 | 99 | ${asset.symbol === 'eth' ? ethPriceInUsd.toFixed(2) : usdcPriceInUsd.toFixed(2)} 100 | 101 |
102 |
103 | 104 | 105 | {/* LTV */} 106 | {Number(poolInfo?.LTV)}% 107 | 108 | {/* Deposit APY */} 109 | {depositApyInPercentage.toFixed(2)}% 110 | 111 | {/* Market size */} 112 | 113 |
114 | {marketSize.toFixed(4)} {asset.symbol} 115 | ${marketSizeInUsd.toFixed(2)} 116 |
117 | 118 | 119 | {/* Borrow APY */} 120 | {borrowApyInPercentage.toFixed(2)}% 121 | 122 | {/* Total Borrowed */} 123 | 124 |
125 | {totalBorrowed.toFixed(4)} {asset.symbol} 126 | ${totalBorrowedInUsd.toFixed(2)} 127 |
128 | 129 | 130 | {/* Wallet */} 131 | {isConnected && ( 132 | 133 |
134 | {balanceDataOfWallet?.formatted ? Number(balanceDataOfWallet.formatted).toFixed(4) : 0} {asset.symbol} 135 | ${balanceOfWalletInUsd.toFixed(2)} 136 |
137 | 138 | )} 139 | 140 | ) 141 | } -------------------------------------------------------------------------------- /src/pages/Lending/DepositBoard/Position.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import { IAsset, IUserInfo } from "../../../utils/interfaces"; 4 | 5 | // -------------------------------------------------------------------------------------------- 6 | 7 | interface IProps { 8 | asset: IAsset; 9 | ethPriceInUsd: number; 10 | usdcPriceInUsd: number; 11 | userInfo: IUserInfo; 12 | } 13 | 14 | // -------------------------------------------------------------------------------------------- 15 | 16 | export default function Position({ asset, ethPriceInUsd, usdcPriceInUsd, userInfo }: IProps) { 17 | const [assetAmount, setAssetAmount] = useState(0) 18 | const [assetAmountInUsd, setAssetAmountInUsd] = useState(0) 19 | 20 | useEffect(() => { 21 | let _assetAmount = 0; 22 | if (asset.symbol === 'eth') { 23 | _assetAmount = Number(formatEther(userInfo.ethDepositAmount)) + Number(formatEther(userInfo.ethRewardAmount)) 24 | setAssetAmount(_assetAmount) 25 | setAssetAmountInUsd(_assetAmount * ethPriceInUsd) 26 | } else { 27 | _assetAmount = Number(formatUnits(userInfo.usdtDepositAmount, asset.decimals)) + Number(formatUnits(userInfo.usdtRewardAmount, asset.decimals)) 28 | setAssetAmount(_assetAmount) 29 | setAssetAmountInUsd(_assetAmount * usdcPriceInUsd) 30 | } 31 | }, [asset, userInfo]) 32 | 33 | return ( 34 |
35 |
36 | 37 |
38 | {asset.symbol} 39 | ${asset.symbol === 'eth' ? ethPriceInUsd.toFixed(2) : usdcPriceInUsd.toFixed(2)} 40 |
41 |
42 |
43 | 44 | {assetAmount.toFixed(4)} {asset.symbol} 45 | 46 | 47 | ${assetAmountInUsd.toFixed(2)} 48 | 49 |
50 |
51 | ) 52 | } -------------------------------------------------------------------------------- /src/pages/Lending/DepositBoard/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useMemo } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import PrimaryBoard from "../../../components/boards/PrimaryBoard"; 4 | import { ASSETS, USDC_DECIMAL } from "../../../utils/constants"; 5 | import { IUserInfo } from "../../../utils/interfaces"; 6 | 7 | // ---------------------------------------------------------------------------------------------- 8 | 9 | const Position = lazy(() => import('./Position')) 10 | 11 | // ---------------------------------------------------------------------------------------------- 12 | 13 | interface IProps { 14 | ethPriceInUsd: number; 15 | usdcPriceInUsd: number; 16 | userInfo: IUserInfo; 17 | } 18 | 19 | // ---------------------------------------------------------------------------------------------- 20 | 21 | export default function DepositBoard({ userInfo, ethPriceInUsd, usdcPriceInUsd }: IProps) { 22 | const totalAmountInUsd = useMemo(() => { 23 | const ethAmountInUsd = Number(formatEther(userInfo.ethDepositAmount + userInfo.ethRewardAmount)) * ethPriceInUsd; 24 | const usdcAmountInUsd = Number(formatUnits(userInfo.usdtDepositAmount + userInfo.usdtRewardAmount, USDC_DECIMAL)) * usdcPriceInUsd; 25 | console.log('>>>>>>>>> ethAmountInUsd + usdcAmountInUsd => ', ethAmountInUsd + usdcAmountInUsd) 26 | return ethAmountInUsd + usdcAmountInUsd 27 | }, [userInfo]) 28 | 29 | return ( 30 | ${totalAmountInUsd.toFixed(2)}}> 31 |
32 | {ASSETS.map(asset => ( 33 | 34 | ))} 35 |
36 |
37 | ) 38 | } -------------------------------------------------------------------------------- /src/pages/Lending/MBRow.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useMemo, useState } from "react"; 2 | import { useAccount, useBalance, useContractRead } from "wagmi"; 3 | import { ListItem } from "@material-tailwind/react"; 4 | import { IAsset, IReturnValueOfBalance, IReturnValueOfPoolInfo } from "../../utils/interfaces"; 5 | import { APY_DECIMAL, POOL_CONTRACT_ABI, POOL_CONTRACT_ADDRESS, USDC_CONTRACT_ADDRESS, USDC_DECIMAL } from "../../utils/constants"; 6 | import { formatEther, formatUnits } from "viem"; 7 | 8 | // ---------------------------------------------------------------------------------- 9 | 10 | interface IProps { 11 | asset: IAsset; 12 | openDialog: Function; 13 | ethPriceInUsd: number; 14 | usdcPriceInUsd: number; 15 | } 16 | 17 | // ---------------------------------------------------------------------------------- 18 | 19 | export default function MBRow({ asset, openDialog, ethPriceInUsd, usdcPriceInUsd }: IProps) { 20 | const [marketSize, setMarketSize] = useState(0) 21 | const [marketSizeInUsd, setMarketSizeInUsd] = useState(0) 22 | const [totalBorrowed, setTotalBorrowed] = useState(0) 23 | const [totalBorrowedInUsd, setTotalBorrowedInUsd] = useState(0) 24 | const [depositApyInPercentage, setDepositApyInPercentage] = useState(0) 25 | const [borrowApyInPercentage, setBorrowApyInPercentage] = useState(0) 26 | 27 | // --------------------------------------------------------------------------------- 28 | 29 | const { address, isConnected } = useAccount() 30 | 31 | // --------------------------------------------------------------------------------- 32 | // Balance data of the wallet 33 | const { data: balanceDataOfWallet }: IReturnValueOfBalance = useBalance({ 34 | address, 35 | token: asset.symbol === 'usdc' ? USDC_CONTRACT_ADDRESS : undefined, 36 | watch: true 37 | }) 38 | 39 | // The info of the pool 40 | const { data: poolInfo }: IReturnValueOfPoolInfo = useContractRead({ 41 | address: POOL_CONTRACT_ADDRESS, 42 | abi: POOL_CONTRACT_ABI, 43 | functionName: 'getPoolInfo', 44 | args: [asset.contractAddress], 45 | watch: true 46 | }) 47 | 48 | // ---------------------------------------------------------------------------------- 49 | 50 | const balanceOfWalletInUsd = useMemo(() => { 51 | if (balanceDataOfWallet) { 52 | return Number(balanceDataOfWallet.formatted) * (asset.symbol === 'eth' ? ethPriceInUsd : usdcPriceInUsd); 53 | } 54 | return 0 55 | }, [balanceDataOfWallet]) 56 | 57 | // ---------------------------------------------------------------------------------- 58 | 59 | useEffect(() => { 60 | if (poolInfo) { 61 | setMarketSize(Number(formatEther(poolInfo.totalAmount))) 62 | if (asset.symbol === 'eth') { 63 | setMarketSize(Number(formatEther(poolInfo.totalAmount))) 64 | setMarketSizeInUsd(Number(formatEther(poolInfo.totalAmount)) * ethPriceInUsd) 65 | setTotalBorrowed(Number(formatEther(poolInfo.borrowAmount))) 66 | setTotalBorrowedInUsd(Number(formatEther(poolInfo.borrowAmount)) * ethPriceInUsd) 67 | } else { 68 | setMarketSize(Number(formatUnits(poolInfo.totalAmount, USDC_DECIMAL))) 69 | setMarketSizeInUsd(Number(formatUnits(poolInfo.totalAmount, USDC_DECIMAL)) * usdcPriceInUsd) 70 | setTotalBorrowed(Number(formatUnits(poolInfo.borrowAmount, asset.decimals))) 71 | setTotalBorrowedInUsd(Number(formatUnits(poolInfo.borrowAmount, asset.decimals)) * usdcPriceInUsd) 72 | } 73 | setDepositApyInPercentage(Number(formatUnits(poolInfo.depositApy, APY_DECIMAL))) 74 | setBorrowApyInPercentage(Number(formatUnits(poolInfo.borrowApy, APY_DECIMAL))) 75 | } else { 76 | setMarketSize(0) 77 | setMarketSizeInUsd(0) 78 | setTotalBorrowed(0) 79 | setTotalBorrowedInUsd(0) 80 | setDepositApyInPercentage(0) 81 | setBorrowApyInPercentage(0) 82 | } 83 | }, [poolInfo]) 84 | 85 | // ---------------------------------------------------------------------------------- 86 | 87 | return ( 88 | openDialog(asset)} 91 | > 92 | {/* Asset name */} 93 |
94 | Asset Name: 95 |
96 | 97 |
98 | {asset.name} 99 | 100 | ${asset.symbol === 'eth' ? ethPriceInUsd.toFixed(4) : usdcPriceInUsd.toFixed(4)} 101 | 102 |
103 |
104 |
105 | 106 | {/* LTV */} 107 |
108 | LTV: 109 | {Number(poolInfo?.LTV)}% 110 |
111 | 112 | {/* Deposit APY */} 113 |
114 | Deposit APY: 115 | {depositApyInPercentage.toFixed(2)}% 116 |
117 | 118 | {/* Market size */} 119 |
120 | Market size: 121 |
122 | {marketSize.toFixed(4)} {asset.symbol} 123 | ${marketSizeInUsd.toFixed(4)} 124 |
125 |
126 | 127 | {/* Borrow APY */} 128 |
129 | Borrow APY: 130 | {borrowApyInPercentage.toFixed(2)}% 131 |
132 | 133 | {/* Total Borrowed */} 134 |
135 | Total Borrowed: 136 |
137 | {totalBorrowed.toFixed(4)} {asset.symbol} 138 | ${totalBorrowedInUsd.toFixed(4)} 139 |
140 |
141 | 142 | {/* Wallet */} 143 | {isConnected && ( 144 |
145 | Wallet: 146 |
147 | {balanceDataOfWallet?.formatted ? Number(balanceDataOfWallet.formatted).toFixed(4) : 0} {asset.symbol} 148 | ${balanceOfWalletInUsd.toFixed(4)} 149 |
150 |
151 | )} 152 | 153 |
154 | ) 155 | } -------------------------------------------------------------------------------- /src/pages/Liquidate/DPRow.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { formatEther, formatUnits } from "viem"; 3 | import Td from "../../components/tableComponents/Td"; 4 | import Tr from "../../components/tableComponents/Tr"; 5 | import { getVisibleWalletAddress } from "../../utils/functions"; 6 | import { ILiquidation } from "../../utils/interfaces" 7 | import { USDC_DECIMAL } from "../../utils/constants"; 8 | import FilledButton from "../../components/buttons/FilledButton"; 9 | 10 | // ----------------------------------------------------------------------------------------- 11 | 12 | interface IProps { 13 | liquidation: ILiquidation; 14 | ethPriceInUsd: number; 15 | usdcPriceInUsd: number; 16 | openLiquidateDialog: Function; 17 | } 18 | 19 | // ----------------------------------------------------------------------------------------- 20 | 21 | export default function DPRow({ liquidation, ethPriceInUsd, usdcPriceInUsd, openLiquidateDialog }: IProps) { 22 | const [borrowedValueInUsd, setBorrowedValueInUsd] = useState(0) 23 | const [depositedValueInUsd, setDepositedValueInUsd] = useState(0) 24 | 25 | // ---------------------------------------------------------------------------------------- 26 | 27 | useEffect(() => { 28 | const _borrowedValueInUsd = Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)) * ethPriceInUsd + 29 | Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)) * usdcPriceInUsd 30 | const _depositedValueInUsd = Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)) * ethPriceInUsd + 31 | Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)) * usdcPriceInUsd 32 | 33 | setBorrowedValueInUsd(_borrowedValueInUsd) 34 | setDepositedValueInUsd(_depositedValueInUsd) 35 | }, [liquidation]) 36 | 37 | // ---------------------------------------------------------------------------------------- 38 | 39 | return ( 40 | 41 | {/* User */} 42 | {getVisibleWalletAddress(liquidation.accountAddress)} 43 | 44 | {/* Borrowed Asset(s) */} 45 | 46 |
47 | {liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 48 |
49 | 50 | 51 |
52 | ) : !liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 53 | 54 | ) : ( 55 | 56 | )} 57 |
58 | 59 | 60 | {/* Borrowed Value */} 61 | 62 | {/* {liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 63 |
64 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 65 | 66 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 67 | 68 |
69 | ) : !liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 70 | 71 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 72 | 73 | ) : ( 74 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 75 | )} */} 76 | ${borrowedValueInUsd.toFixed(2)} 77 | 78 | 79 | {/* Deposited Asset(s) */} 80 | 81 |
82 | {liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 83 |
84 | 85 | 86 |
87 | ) : !liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 88 | 89 | ) : ( 90 | 91 | )} 92 |
93 | 94 | 95 | {/* Deposited Value */} 96 | 97 | {/* {liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 98 |
99 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 100 | 101 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 102 | 103 |
104 | ) : !liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 105 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 106 | ) : ( 107 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 108 | )} */} 109 | ${depositedValueInUsd.toFixed(2)} 110 | 111 | 112 | {/* Risk Factor */} 113 | 114 | {liquidation.riskFactor.toFixed(4)} % 115 | 116 | 117 | 118 | {/* handleLiquidate()} 121 | > 122 | {approveIsLoading || liquidateIsLoading ? IN_PROGRESS : 'Liquidate'} 123 | */} 124 | openLiquidateDialog(liquidation)}> 125 | Liquidate 126 | 127 | 128 | 129 | ) 130 | } -------------------------------------------------------------------------------- /src/pages/Liquidate/MBRow.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { ListItem } from "@material-tailwind/react"; 3 | import { formatEther, formatUnits } from "viem"; 4 | import { getVisibleWalletAddress } from "../../utils/functions"; 5 | import { ILiquidation } from "../../utils/interfaces"; 6 | import { USDC_DECIMAL } from "../../utils/constants"; 7 | import FilledButton from "../../components/buttons/FilledButton"; 8 | 9 | // ----------------------------------------------------------------------------------------- 10 | 11 | interface IProps { 12 | liquidation: ILiquidation; 13 | ethPriceInUsd: number; 14 | usdcPriceInUsd: number; 15 | openLiquidateDialog: Function; 16 | } 17 | 18 | // ----------------------------------------------------------------------------------------- 19 | 20 | export default function MBRow({ liquidation, ethPriceInUsd, usdcPriceInUsd, openLiquidateDialog }: IProps) { 21 | const [borrowedValueInUsd, setBorrowedValueInUsd] = useState(0) 22 | const [depositedValueInUsd, setDepositedValueInUsd] = useState(0) 23 | 24 | // ---------------------------------------------------------------------------------------- 25 | 26 | useEffect(() => { 27 | const _borrowedValueInUsd = Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)) * ethPriceInUsd + 28 | Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)) * usdcPriceInUsd 29 | const _depositedValueInUsd = Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)) * ethPriceInUsd + 30 | Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)) * usdcPriceInUsd 31 | 32 | setBorrowedValueInUsd(_borrowedValueInUsd) 33 | setDepositedValueInUsd(_depositedValueInUsd) 34 | }, [liquidation]) 35 | 36 | // ---------------------------------------------------------------------------------------- 37 | 38 | return ( 39 | 42 | {/* User */} 43 |
44 | User: 45 | {getVisibleWalletAddress('0x5da095266ec7ec1d979f01a9d7e4ee902e0182bc')} 46 |
47 | 48 | {/* Borrowed assets */} 49 |
50 | Borrowed Asset(s): 51 |
52 | {liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 53 |
54 | 55 | 56 |
57 | ) : !liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 58 | 59 | ) : ( 60 | 61 | )} 62 |
63 |
64 | 65 | {/* Borrowed value */} 66 |
67 | Borrowed Value: 68 | {/* {liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 69 |
70 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 71 | 72 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 73 | 74 |
75 | ) : !liquidation.ethBorrowAmount && liquidation.usdtBorrowAmount ? ( 76 | 77 | {Number(formatUnits(liquidation.usdtBorrowAmount + liquidation.usdtInterestAmount, USDC_DECIMAL)).toFixed(4)} USDC 78 | 79 | ) : ( 80 | {Number(formatEther(liquidation.ethBorrowAmount + liquidation.ethInterestAmount)).toFixed(4)} ETH 81 | )} */} 82 | ${borrowedValueInUsd.toFixed(2)} 83 |
84 | 85 | {/* Deposited assets */} 86 |
87 | Deposited Asset(s): 88 | {liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 89 |
90 | 91 | 92 |
93 | ) : !liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 94 | 95 | ) : ( 96 | 97 | )} 98 |
99 | 100 | {/* Deposited value */} 101 |
102 | Deposited Value: 103 | {/* {liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 104 |
105 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 106 | 107 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 108 | 109 |
110 | ) : !liquidation.ethDepositAmount && liquidation.usdtDepositAmount ? ( 111 | {Number(formatUnits(liquidation.usdtDepositAmount + liquidation.usdtRewardAmount, USDC_DECIMAL)).toFixed(4)} USDC 112 | ) : ( 113 | {Number(formatEther(liquidation.ethDepositAmount + liquidation.ethRewardAmount)).toFixed(4)} ETH 114 | )} */} 115 | ${depositedValueInUsd.toFixed(2)} 116 |
117 | 118 | {/* Risk factor */} 119 |
120 | Risk Factor: 121 | {liquidation.riskFactor.toFixed(4)}% 122 |
123 | 124 | {/* Operation */} 125 |
126 | Operation: 127 | {/* handleLiquidate()} 130 | > 131 | {approveIsLoading || liquidateIsLoading ? IN_PROGRESS : 'Liquidate'} 132 | */} 133 | openLiquidateDialog(liquidation)}> 134 | Liquidate 135 | 136 |
137 |
138 | ) 139 | } -------------------------------------------------------------------------------- /src/pages/Swap/BorrowPanel.tsx: -------------------------------------------------------------------------------- 1 | import { Progress } from "@material-tailwind/react"; 2 | import Table from "../../components/tableComponents/Table"; 3 | import Th from "../../components/tableComponents/Th"; 4 | import Tr from "../../components/tableComponents/Tr"; 5 | import Td from "../../components/tableComponents/Td"; 6 | import { TEMP_CRYPTO_LOGO_URL } from "../../utils/constants"; 7 | import { IPropsOfComponent } from "../../utils/interfaces"; 8 | 9 | // ----------------------------------------------------------------------------------- 10 | 11 | const TEMP_INDEXES_OF_TABLE: Array = [1, 2, 3, 4, 5, 6, 7]; 12 | 13 | // ----------------------------------------------------------------------------------- 14 | 15 | export default function BorrowPanel({ className = '', ...others }: IPropsOfComponent) { 16 | return ( 17 |
18 |

Borrow API

19 |
20 |
21 | Borrowing Amount 22 | 0 USDC 23 |
24 |
25 | Borrowable 26 | 0 USDC 27 |
28 |
29 | APY 30 | 1.15% 31 |
32 |
33 | Borrower Power 34 |
35 | 36 | 10% 37 |
38 |
39 |
40 | 41 |
42 | Your Assets 43 |
44 | 45 | 46 | 47 | 51 | 52 | 53 | {TEMP_INDEXES_OF_TABLE.map(index => ( 54 | 55 | 61 | 67 | 73 | 74 | ))} 75 | 76 |
48 | 49 | 50 |
56 |
57 | 58 | USDC 59 |
60 |
62 |
63 | 0 64 | $0.00 65 |
66 |
68 |
69 | 0 70 | $0.00 71 |
72 |
77 |
78 |
79 |
80 | ) 81 | } -------------------------------------------------------------------------------- /src/pages/Swap/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import { Switch } from "@material-tailwind/react"; 3 | import { Icon } from "@iconify/react"; 4 | import Slider from "rc-slider"; 5 | import 'rc-slider/assets/index.css'; 6 | import PageHeader from "../../components/PageHeader"; 7 | import TextButton from "../../components/buttons/TextButton"; 8 | import { IToken } from "../../utils/interfaces"; 9 | import OutlinedButton from "../../components/buttons/OutlinedButton"; 10 | import FilledButton from "../../components/buttons/FilledButton"; 11 | 12 | // --------------------------------------------------------------------------------------------- 13 | 14 | const BorrowPanel = lazy(() => import('./BorrowPanel')) 15 | const SelectTokenWithPrice = lazy(() => import('../../components/form/SelectTokenWithPrice')) 16 | 17 | // --------------------------------------------------------------------------------------------- 18 | 19 | const TOKENS: Array = [ 20 | { 21 | id: 1, 22 | name: 'Bitcoin', 23 | symbol: 'BTC', 24 | imgSrc: 'https://cryptologos.cc/logos/bitcoin-btc-logo.svg?v=025', 25 | depositedAmount: 0 26 | }, 27 | { 28 | id: 2, 29 | name: 'BNB', 30 | symbol: 'BNB', 31 | imgSrc: 'https://cryptologos.cc/logos/bnb-bnb-logo.svg?v=025', 32 | depositedAmount: 0 33 | }, 34 | { 35 | id: 3, 36 | name: 'USD Coin', 37 | symbol: 'USDC', 38 | imgSrc: 'https://cryptologos.cc/logos/usd-coin-usdc-logo.svg?v=025', 39 | depositedAmount: 0 40 | }, 41 | { 42 | id: 4, 43 | name: 'Ethereum', 44 | symbol: 'ETH', 45 | imgSrc: 'https://cryptologos.cc/logos/ethereum-eth-logo.svg?v=025', 46 | depositedAmount: 0 47 | }, 48 | { 49 | id: 5, 50 | name: 'Solana', 51 | symbol: 'SOL', 52 | imgSrc: 'https://cryptologos.cc/logos/solana-sol-logo.svg?v=025', 53 | depositedAmount: 0 54 | } 55 | ] 56 | 57 | // --------------------------------------------------------------------------------------------- 58 | 59 | export default function Swap() { 60 | const [payToken, setPayToken] = useState(null) 61 | const [payTokenAmount, setPayTokenAmount] = useState('0') 62 | const [receiveToken, setReceiveToken] = useState(null) 63 | const [receiveTokenAmount, setReceiveTokenAmount] = useState('0') 64 | const [borrowAllowed, setBorrowAllowed] = useState(false) 65 | 66 | return ( 67 |
68 | 69 | 70 |
71 |
72 |
73 | {/* You pay */} 74 |
75 |
76 |
77 |

You Pay

78 |
79 | Allow Borrowing} 81 | checked={borrowAllowed} 82 | onChange={() => setBorrowAllowed(!borrowAllowed)} 83 | className="bg-gray-800" 84 | /> 85 | 86 | 87 | 88 | 0.5% 89 | 90 |
91 |
92 | 93 | {/* */} 100 | 101 |
102 | 114 |
115 |
116 | 117 |
118 | Select target token to see borrow ability 119 |
120 | half 121 | max 122 |
123 |
124 |
125 | 126 | {/* Swap button */} 127 |
128 |
129 | 132 |
133 |
134 | 135 | {/* You Receive */} 136 |
137 |

You Receive

138 | 139 | {/* */} 146 | 147 | 148 |
149 | 150 | {/* Button */} 151 |
152 | 153 | Select a token to swap 154 | 155 |
156 |
157 | 158 | {borrowAllowed && ( 159 | 160 | )} 161 |
162 |
163 |
164 | ) 165 | } -------------------------------------------------------------------------------- /src/pages/Trading/BidCard.tsx: -------------------------------------------------------------------------------- 1 | interface IBidData { 2 | id: number; 3 | amount: number; 4 | price: number; 5 | } 6 | 7 | interface IProps { 8 | setBuySellTabValue: Function; 9 | } 10 | 11 | // ----------------------------------------------------------------------------------------- 12 | 13 | const BIDS: Array = [ 14 | { 15 | id: 1, 16 | amount: 1, 17 | price: 8.41 18 | }, 19 | { 20 | id: 2, 21 | amount: 1, 22 | price: 8.41 23 | }, 24 | { 25 | id: 3, 26 | amount: 1, 27 | price: 8.41 28 | }, 29 | { 30 | id: 4, 31 | amount: 1, 32 | price: 8.41 33 | }, 34 | { 35 | id: 5, 36 | amount: 1, 37 | price: 8.41 38 | }, 39 | { 40 | id: 6, 41 | amount: 1, 42 | price: 8.41 43 | }, 44 | { 45 | id: 7, 46 | amount: 1, 47 | price: 8.41 48 | }, 49 | { 50 | id: 8, 51 | amount: 1, 52 | price: 8.41 53 | } 54 | ] 55 | 56 | // ----------------------------------------------------------------------------------------- 57 | 58 | export default function BidCard({ setBuySellTabValue }: IProps) { 59 | return ( 60 |
61 |
62 | BID 63 | ASK 64 |
65 |
66 | Amount(USDC) 67 | Price(tUSDC) 68 | Amount(USDC) 69 |
70 |
71 |
setBuySellTabValue('buy')}> 72 | {BIDS.map(bidItem => ( 73 |
74 | {bidItem.amount} 75 | {bidItem.price} 76 |
77 | ))} 78 |
79 | 80 |
setBuySellTabValue('sell')}> 81 | {BIDS.map(bidItem => ( 82 |
83 | {bidItem.price} 84 | {bidItem.amount} 85 |
86 | ))} 87 |
88 |
89 |
90 | ) 91 | } -------------------------------------------------------------------------------- /src/pages/Trading/BuySellCard.tsx: -------------------------------------------------------------------------------- 1 | import { ChangeEvent, useState } from "react"; 2 | import MainSelect from "../../components/form/MainSelect"; 3 | import { IOption } from "../../utils/interfaces"; 4 | import MainInput from "../../components/form/MainInput"; 5 | import { REGEX_NUMBER_VALID, TEMP_CRYPTO_LOGO_URL } from "../../utils/constants"; 6 | import FilledButton from "../../components/buttons/FilledButton"; 7 | import OutlinedButton from "../../components/buttons/OutlinedButton"; 8 | import { TBuySellTabValue } from "../../utils/types"; 9 | 10 | // --------------------------------------------------------------------------------- 11 | 12 | interface IProps { 13 | tabValue: TBuySellTabValue; 14 | setTabValue: Function; 15 | } 16 | 17 | // --------------------------------------------------------------------------------- 18 | 19 | const ORDER_TYPES: Array = [ 20 | { 21 | id: 1, 22 | label: 'Limit', 23 | value: 'limit' 24 | } 25 | ] 26 | 27 | // --------------------------------------------------------------------------------- 28 | 29 | export default function BuySellCard({ tabValue, setTabValue }: IProps) { 30 | const [orderType, setOrderType] = useState(ORDER_TYPES[0]) 31 | const [price, setPrice] = useState('0') 32 | const [amount, setAmount] = useState('0') 33 | 34 | const handlePrice = (e: ChangeEvent) => { 35 | const { value } = e.target 36 | if (value.match(REGEX_NUMBER_VALID)) { 37 | setPrice(value); 38 | } 39 | } 40 | 41 | const handleAmount = (e: ChangeEvent) => { 42 | const { value } = e.target 43 | if (value.match(REGEX_NUMBER_VALID)) { 44 | setAmount(value); 45 | } 46 | } 47 | 48 | return ( 49 |
50 |
51 |
setTabValue('buy')} 54 | > 55 | Buy 56 |
57 |
setTabValue('sell')} 60 | > 61 | Sell 62 |
63 |
64 | 65 |
66 | {/* Order Type */} 67 |
68 | 69 | 75 |
76 | 77 | {/* Price */} 78 |
79 |
80 | 81 |

Min Ask: 8.45

82 |
83 | 84 | 87 | 88 | tUSDC 89 |
} 90 | placeholder="0" 91 | value={price} 92 | onChange={handlePrice} 93 | /> 94 |
95 | 96 | {/* Amount */} 97 |
98 |
99 | 100 |

Available: 10 tUSDC

101 |
102 | 105 | 106 | USDC 107 |
} 108 | placeholder="0" 109 | value={amount} 110 | onChange={handleAmount} 111 | /> 112 |
113 | 114 |
115 | Deposit tUSDC 116 | Please input price 117 |
118 | 119 | 120 | ) 121 | } -------------------------------------------------------------------------------- /src/pages/Trading/MarketCard.tsx: -------------------------------------------------------------------------------- 1 | import Table from "../../components/tableComponents/Table"; 2 | import Td from "../../components/tableComponents/Td"; 3 | import Th from "../../components/tableComponents/Th"; 4 | import Tr from "../../components/tableComponents/Tr"; 5 | import { IPropsOfComponent } from "../../utils/interfaces"; 6 | 7 | export default function MarketCard({ className = '' }: IPropsOfComponent) { 8 | return ( 9 |
10 |

Market Trades

11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
15 | 16 | 17 | 18 |
ASK0.164844444
29 |
30 | ) 31 | } -------------------------------------------------------------------------------- /src/pages/Trading/OrdersCard.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import TextButton from "../../components/buttons/TextButton"; 3 | import { IPropsOfComponent } from "../../utils/interfaces"; 4 | import Table from "../../components/tableComponents/Table"; 5 | import Th from "../../components/tableComponents/Th"; 6 | import Tr from "../../components/tableComponents/Tr"; 7 | import Td from "../../components/tableComponents/Td"; 8 | import { TEMP_CRYPTO_LOGO_URL } from "../../utils/constants"; 9 | 10 | // ---------------------------------------------------------------------------------------------------- 11 | 12 | type TTabValue = 'orders' | 'balances'; 13 | 14 | // ---------------------------------------------------------------------------------------------------- 15 | 16 | export default function OrdersCard({ className = '' }: IPropsOfComponent) { 17 | const [tabValue, setTabValue] = useState('orders') 18 | 19 | return ( 20 |
21 | {/* Tab buttons */} 22 |
23 | setTabValue('orders')} 26 | >Orders 27 | setTabValue('balances')} 30 | >Balances 31 |
32 | 33 | {tabValue === 'orders' ? ( 34 | 35 | 36 | 37 | 44 | 45 | 46 | 47 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
38 | 39 | 40 | 41 | 42 | 43 |
48 |
49 |
50 | 51 | 52 |
53 | USDC / tUSDC 54 |
55 |
ASK0.1 USDC25 tUSDC2.5 tUSDCCancel
64 | ) : ( 65 | 66 | 67 | 68 | 74 | 75 | 76 | 77 | 83 | 89 | 95 | 101 | 102 | 108 | 109 | 110 |
69 | 70 | 71 | 72 | 73 |
78 |
79 | 80 | USDC 81 |
82 |
84 |
85 | 0 USDC 86 | $0.00 87 |
88 |
90 |
91 | 0 USDC 92 | $0.00 93 |
94 |
96 |
97 | 0 USDC 98 | $0.00 99 |
100 |
103 |
104 | Deposit 105 | Withdraw 106 |
107 |
111 | )} 112 |
113 | ) 114 | } -------------------------------------------------------------------------------- /src/pages/Trading/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import Container from "../../components/containers/Container"; 3 | import { TEMP_LPS } from "../../utils/constants"; 4 | import { ILP } from "../../utils/interfaces"; 5 | import { TBuySellTabValue } from "../../utils/types"; 6 | import OrdersCard from "./OrdersCard"; 7 | import MarketCard from "./MarketCard"; 8 | 9 | // --------------------------------------------------------------------------------------------- 10 | 11 | const SelectLP = lazy(() => import('../../components/form/SelectLP')) 12 | const BuySellCard = lazy(() => import('./BuySellCard')) 13 | const BidCard = lazy(() => import('./BidCard')) 14 | 15 | // --------------------------------------------------------------------------------------------- 16 | 17 | export default function Trading() { 18 | const [lp, setLp] = useState(TEMP_LPS[0]) 19 | const [buySellTabValue, setBuySellTabValue] = useState('buy') 20 | 21 | return ( 22 | 23 |
24 |
25 | 30 |
31 |
32 | 33 |
34 |
35 |

Trading View

36 |
37 | 38 | 39 | 40 | 41 |
42 |
43 | ) 44 | } -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/service-worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /* eslint-disable no-restricted-globals */ 3 | 4 | // This service worker can be customized! 5 | // See https://developers.google.com/web/tools/workbox/modules 6 | // for the list of available Workbox modules, or add any other 7 | // code you'd like. 8 | // You can also remove this file if you'd prefer not to use a 9 | // service worker, and the Workbox build step will be skipped. 10 | 11 | import { clientsClaim } from 'workbox-core'; 12 | import { ExpirationPlugin } from 'workbox-expiration'; 13 | import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'; 14 | import { registerRoute } from 'workbox-routing'; 15 | import { StaleWhileRevalidate } from 'workbox-strategies'; 16 | 17 | declare const self: ServiceWorkerGlobalScope; 18 | 19 | clientsClaim(); 20 | 21 | // Precache all of the assets generated by your build process. 22 | // Their URLs are injected into the manifest variable below. 23 | // This variable must be present somewhere in your service worker file, 24 | // even if you decide not to use precaching. See https://cra.link/PWA 25 | precacheAndRoute(self.__WB_MANIFEST); 26 | 27 | // Set up App Shell-style routing, so that all navigation requests 28 | // are fulfilled with your index.html shell. Learn more at 29 | // https://developers.google.com/web/fundamentals/architecture/app-shell 30 | const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$'); 31 | registerRoute( 32 | // Return false to exempt requests from being fulfilled by index.html. 33 | ({ request, url }: { request: Request; url: URL }) => { 34 | // If this isn't a navigation, skip. 35 | if (request.mode !== 'navigate') { 36 | return false; 37 | } 38 | 39 | // If this is a URL that starts with /_, skip. 40 | if (url.pathname.startsWith('/_')) { 41 | return false; 42 | } 43 | 44 | // If this looks like a URL for a resource, because it contains 45 | // a file extension, skip. 46 | if (url.pathname.match(fileExtensionRegexp)) { 47 | return false; 48 | } 49 | 50 | // Return true to signal that we want to use the handler. 51 | return true; 52 | }, 53 | createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html') 54 | ); 55 | 56 | // An example runtime caching route for requests that aren't handled by the 57 | // precache, in this case same-origin .png requests like those from in public/ 58 | registerRoute( 59 | // Add in any other file extensions or routing criteria as needed. 60 | ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), 61 | // Customize this strategy as needed, e.g., by changing to CacheFirst. 62 | new StaleWhileRevalidate({ 63 | cacheName: 'images', 64 | plugins: [ 65 | // Ensure that once this runtime cache reaches a maximum size the 66 | // least-recently used images are removed. 67 | new ExpirationPlugin({ maxEntries: 50 }), 68 | ], 69 | }) 70 | ); 71 | 72 | // This allows the web app to trigger skipWaiting via 73 | // registration.waiting.postMessage({type: 'SKIP_WAITING'}) 74 | self.addEventListener('message', (event) => { 75 | if (event.data && event.data.type === 'SKIP_WAITING') { 76 | self.skipWaiting(); 77 | } 78 | }); 79 | 80 | // Any other custom service worker logic can go here. 81 | -------------------------------------------------------------------------------- /src/serviceWorkerRegistration.ts: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://cra.link/PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) 19 | ); 20 | 21 | type Config = { 22 | onSuccess?: (registration: ServiceWorkerRegistration) => void; 23 | onUpdate?: (registration: ServiceWorkerRegistration) => void; 24 | }; 25 | 26 | export function register(config?: Config) { 27 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 28 | // The URL constructor is available in all browsers that support SW. 29 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 30 | if (publicUrl.origin !== window.location.origin) { 31 | // Our service worker won't work if PUBLIC_URL is on a different origin 32 | // from what our page is served on. This might happen if a CDN is used to 33 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 34 | return; 35 | } 36 | 37 | window.addEventListener('load', () => { 38 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 39 | 40 | if (isLocalhost) { 41 | // This is running on localhost. Let's check if a service worker still exists or not. 42 | checkValidServiceWorker(swUrl, config); 43 | 44 | // Add some additional logging to localhost, pointing developers to the 45 | // service worker/PWA documentation. 46 | navigator.serviceWorker.ready.then(() => { 47 | console.log( 48 | 'This web app is being served cache-first by a service ' + 49 | 'worker. To learn more, visit https://cra.link/PWA' 50 | ); 51 | }); 52 | } else { 53 | // Is not localhost. Just register service worker 54 | registerValidSW(swUrl, config); 55 | } 56 | }); 57 | } 58 | } 59 | 60 | function registerValidSW(swUrl: string, config?: Config) { 61 | navigator.serviceWorker 62 | .register(swUrl) 63 | .then((registration) => { 64 | registration.onupdatefound = () => { 65 | const installingWorker = registration.installing; 66 | if (installingWorker == null) { 67 | return; 68 | } 69 | installingWorker.onstatechange = () => { 70 | if (installingWorker.state === 'installed') { 71 | if (navigator.serviceWorker.controller) { 72 | // At this point, the updated precached content has been fetched, 73 | // but the previous service worker will still serve the older 74 | // content until all client tabs are closed. 75 | console.log( 76 | 'New content is available and will be used when all ' + 77 | 'tabs for this page are closed. See https://cra.link/PWA.' 78 | ); 79 | 80 | // Execute callback 81 | if (config && config.onUpdate) { 82 | config.onUpdate(registration); 83 | } 84 | } else { 85 | // At this point, everything has been precached. 86 | // It's the perfect time to display a 87 | // "Content is cached for offline use." message. 88 | console.log('Content is cached for offline use.'); 89 | 90 | // Execute callback 91 | if (config && config.onSuccess) { 92 | config.onSuccess(registration); 93 | } 94 | } 95 | } 96 | }; 97 | }; 98 | }) 99 | .catch((error) => { 100 | console.error('Error during service worker registration:', error); 101 | }); 102 | } 103 | 104 | function checkValidServiceWorker(swUrl: string, config?: Config) { 105 | // Check if the service worker can be found. If it can't reload the page. 106 | fetch(swUrl, { 107 | headers: { 'Service-Worker': 'script' }, 108 | }) 109 | .then((response) => { 110 | // Ensure service worker exists, and that we really are getting a JS file. 111 | const contentType = response.headers.get('content-type'); 112 | if ( 113 | response.status === 404 || 114 | (contentType != null && contentType.indexOf('javascript') === -1) 115 | ) { 116 | // No service worker found. Probably a different app. Reload the page. 117 | navigator.serviceWorker.ready.then((registration) => { 118 | registration.unregister().then(() => { 119 | window.location.reload(); 120 | }); 121 | }); 122 | } else { 123 | // Service worker found. Proceed as normal. 124 | registerValidSW(swUrl, config); 125 | } 126 | }) 127 | .catch(() => { 128 | console.log('No internet connection found. App is running in offline mode.'); 129 | }); 130 | } 131 | 132 | export function unregister() { 133 | if ('serviceWorker' in navigator) { 134 | navigator.serviceWorker.ready 135 | .then((registration) => { 136 | registration.unregister(); 137 | }) 138 | .catch((error) => { 139 | console.error(error.message); 140 | }); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/utils/functions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert wallet address to be visible 3 | * @param walletAddress 0x5da095266ec7ec1d979f01a9d7e4ee902e0182bc 4 | * @param numberOfFirstLetters 6 5 | * @param numberOfLastLetters 4 6 | * @returns 0x5da0...82bc 7 | */ 8 | export const getVisibleWalletAddress = ( 9 | walletAddress: string, 10 | numberOfFirstLetters: number = 6, 11 | numberOfLastLetters: number = 4 12 | ): string => { 13 | if (walletAddress.length <= 10) { 14 | return walletAddress; 15 | } 16 | return `${walletAddress.slice( 17 | 0, 18 | numberOfFirstLetters 19 | )}...${walletAddress.slice(0 - numberOfLastLetters)}`; 20 | }; 21 | -------------------------------------------------------------------------------- /src/utils/interfaces.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { TAssetSymbol } from "./types"; 3 | 4 | export interface IPropsOfComponent { 5 | className?: string; 6 | children?: ReactNode | string; 7 | [key: string]: any; 8 | } 9 | 10 | export interface IPropsOfCustomDialog { 11 | visible: boolean; 12 | setVisible: Function; 13 | } 14 | 15 | export interface IToken { 16 | id: number; 17 | name: string; 18 | symbol: string; 19 | imgSrc: string; 20 | depositedAmount: number; 21 | tokenAddress?: string; 22 | } 23 | 24 | export interface IChain { 25 | id: number; 26 | imgSrc: string; 27 | name: string; 28 | } 29 | 30 | export interface ILP { 31 | id: number; 32 | token: IToken; 33 | coin: IToken; 34 | powererBrandSrc: string; 35 | } 36 | 37 | export interface IOption { 38 | id: number; 39 | label: string; 40 | value: string; 41 | } 42 | 43 | export interface IAsset { 44 | id: number; 45 | name: string; 46 | symbol: TAssetSymbol; 47 | imgSrc: string; 48 | contractAddress: string; 49 | decimals: number; 50 | } 51 | 52 | export interface IMetadataOfAsset { 53 | [key: string]: IAsset; 54 | } 55 | 56 | export interface IUserInfo { 57 | ethDepositAmount: bigint; 58 | usdtDepositAmount: bigint; 59 | ethBorrowAmount: bigint; 60 | usdtBorrowAmount: bigint; 61 | ethInterestAmount: bigint; 62 | usdtInterestAmount: bigint; 63 | ethRewardAmount: bigint; 64 | usdtRewardAmount: bigint; 65 | pekoRewardAmount: bigint; 66 | ethDepositTotalInUsdtAmount: bigint; 67 | usdtDepositTotalAmount: bigint; 68 | ethBorrowTotalInUsdtAmount: bigint; 69 | usdtBorrowTotalAmount: bigint; 70 | accountAddress: string; 71 | } 72 | 73 | export interface IPoolInfo { 74 | LTV: bigint; 75 | depositApy: bigint; 76 | borrowApy: bigint; 77 | totalAmount: bigint; 78 | borrowAmount: bigint; 79 | } 80 | 81 | export interface IBalanceData { 82 | decimals: number; 83 | formatted: string; 84 | symbol: string; 85 | value: bigint; 86 | } 87 | 88 | export interface ILiquidation extends IUserInfo { 89 | riskFactor: number; 90 | } 91 | 92 | export interface IReturnValueOfUserInfo { 93 | data?: IUserInfo; 94 | [key: string]: any; 95 | } 96 | 97 | export interface IReturnValueOfPoolInfo { 98 | data?: IPoolInfo; 99 | [key: string]: any; 100 | } 101 | 102 | export interface IReturnValueOfBalance { 103 | data?: IBalanceData; 104 | [key: string]: any; 105 | } 106 | 107 | export interface IReturnValueOfListOfUsers { 108 | data?: Array; 109 | [key: string]: any; 110 | } 111 | 112 | export interface IReturnValueOfCalcTokenPrice { 113 | data?: bigint; 114 | [key: string]: any; 115 | } 116 | 117 | export interface IReturnValueOfPools { 118 | data?: Array; 119 | [key: string]: any; 120 | } 121 | 122 | export interface IReturnValueOfGetMarketInfo { 123 | data?: Array; 124 | [key: string]: any; 125 | } 126 | 127 | export interface IReturnValueOfAllowance { 128 | data?: bigint; 129 | [key: string]: any; 130 | } 131 | -------------------------------------------------------------------------------- /src/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type TBuySellTabValue = "buy" | "sell"; 2 | export type TAssetSymbol = "eth" | "usdc"; 3 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | const withMT = require("@material-tailwind/react/utils/withMT"); 3 | 4 | module.exports = withMT({ 5 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 6 | theme: { 7 | extend: {}, 8 | container: { 9 | center: true 10 | } 11 | }, 12 | plugins: [], 13 | }); 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | --------------------------------------------------------------------------------