Upgrade next (#100)
* upgrade to next 13 * WIP: adjust to app dir * add docker + wallet connector * fix: update the wallet connect component * tidy: format * wip: make the wallet balance fetcher work * fix balance retrieval * MP-2258: added estimateFee hook (#94) * Mp 2259 queries to api (#96) * update next config for build errors * Convert queries to API + remove config * tidy: save some bytes by adding constants/env.ts * tidy: added URL_ prefix to REST, RPC and GQL --------- Co-authored-by: Linkie Link <linkielink.dev@gmail.com> * MP-2261: created useBroadcast hook for transactions (#95) * tidy: remove unneeded wallet images * Mp 2264 convert store (#97) * Merge stores into 1 * refactor codebase to use new store * fiex build and rename whitelisted to marketassets * tidy: import refactor * updated account navigation basics * feat: added loading component and fixed the disconnect button * fix: format * update new routing system * update config and dependencies * feat: create and delete credit account are restored * tidy: format * fix: fixed the deployment * update route structure (#98) * fix: creditAccountDeposit works again * fix: bugfixes * add apis, remove allowedCoins, get basic borrow tables (#99) Co-authored-by: bwvdhelm <34470358+bobthebuidlr@users.noreply.github.com> --------- Co-authored-by: bwvdhelm <34470358+bobthebuidlr@users.noreply.github.com>
This commit is contained in:
parent
2b91adf438
commit
b5c097d661
13
.env.example
Normal file
13
.env.example
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
NEXT_PUBLIC_NETWORK=testnet
|
||||||
|
NEXT_PUBLIC_CHAIN_ID=osmo-test-4
|
||||||
|
NEXT_PUBLIC_RPC=https://testnet-osmosis-node.marsprotocol.io/XF32UOOU55CX/osmosis-rpc-front/
|
||||||
|
NEXT_PUBLIC_GQL=https://testnet-osmosis-node.marsprotocol.io/XF32UOOU55CX/osmosis-hive-front/graphql
|
||||||
|
NEXT_PUBLIC_REST=https://testnet-osmosis-node.marsprotocol.io/XF32UOOU55CX/osmosis-lcd-front/
|
||||||
|
NEXT_PUBLIC_SWAP=https://testnet.osmosis.zone
|
||||||
|
NEXT_PUBLIC_WALLETS=keplr,cosmostation
|
||||||
|
NEXT_PUBLIC_ACCOUNT_NFT=osmo1l8c3g6zy7kjhuh8d2kqyvxkw0myn4puxv0tzcdf9nwxd386r9l7s3vlhzq
|
||||||
|
NEXT_PUBLIC_ORACLE=osmo1dqz2u3c8rs5e7w5fnchsr2mpzzsxew69wtdy0aq4jsd76w7upmsstqe0s8
|
||||||
|
NEXT_PUBLIC_RED_BANK=osmo1g30recyv8pfy3qd4qn3dn7plc0rn5z68y5gn32j39e96tjhthzxsw3uvvu
|
||||||
|
NEXT_PUBLIC_CREDIT_MANAGER=osmo12hgn4jec4tftahm7spf7c2aqsqrxzzk50hkq60e89atumyu0zvys7vzxdc
|
||||||
|
NEXT_PUBLIC_ZAPPER=osmo1ua8dwc9v8qjh7n3qf8kg6xvrwjm5yu9xxln7yjvgmrvfzaxvzsuqfcdnjq
|
||||||
|
NEXT_PUBLIC_SWAPPER=osmo1uj6r9tu440wwp2mhtagh48yvmeyeaqt2xa7kdnlhyrqcuthlj4ss7ghg6n
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -37,3 +37,7 @@ next-env.d.ts
|
|||||||
|
|
||||||
# Sentry
|
# Sentry
|
||||||
.sentryclirc
|
.sentryclirc
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env.local
|
||||||
|
.env.production
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||||
|
}
|
59
Dockerfile
Normal file
59
Dockerfile
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
FROM node:18-alpine AS base
|
||||||
|
|
||||||
|
# Install dependencies only when needed
|
||||||
|
FROM base AS deps
|
||||||
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies based on the preferred package manager
|
||||||
|
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||||
|
RUN \
|
||||||
|
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||||
|
elif [ -f package-lock.json ]; then npm ci; \
|
||||||
|
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
|
||||||
|
else echo "Lockfile not found." && exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Rebuild the source code only when needed
|
||||||
|
FROM base AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Next.js collects completely anonymous telemetry data about general usage.
|
||||||
|
# Learn more here: https://nextjs.org/telemetry
|
||||||
|
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||||
|
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
|
RUN yarn build
|
||||||
|
|
||||||
|
# If using npm comment out above and use below instead
|
||||||
|
# RUN npm run build
|
||||||
|
|
||||||
|
# Production image, copy all the files and run next
|
||||||
|
FROM base AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV production
|
||||||
|
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||||
|
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
@ -1,11 +1,11 @@
|
|||||||
const { withSentryConfig } = require('@sentry/nextjs')
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
output: 'standalone',
|
||||||
sentry: {
|
experimental: {
|
||||||
hideSourceMaps: true,
|
appDir: true,
|
||||||
},
|
},
|
||||||
|
reactStrictMode: true,
|
||||||
async redirects() {
|
async redirects() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -13,9 +13,34 @@ const nextConfig = {
|
|||||||
destination: '/trade',
|
destination: '/trade',
|
||||||
permanent: true,
|
permanent: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
source: '/wallets',
|
||||||
|
destination: '/trade',
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/wallets/:wallet',
|
||||||
|
destination: '/wallets/:wallet/trade',
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/wallets/:wallet/accounts',
|
||||||
|
destination: '/wallets/:wallet/accounts/trade',
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
webpack(config) {
|
webpack(config, {isServer}) {
|
||||||
|
if (isServer) {
|
||||||
|
config.resolve.fallback = {
|
||||||
|
...config.resolve.fallback,
|
||||||
|
'utf-8-validate': false,
|
||||||
|
bufferutil: false,
|
||||||
|
'./build/Release/ecdh': false,
|
||||||
|
eccrypto: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
test: /\.svg$/i,
|
test: /\.svg$/i,
|
||||||
issuer: /\.[jt]sx?$/,
|
issuer: /\.[jt]sx?$/,
|
||||||
@ -40,4 +65,4 @@ const sentryWebpackPluginOptions = {
|
|||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
// Make sure adding Sentry options is the last code to run before exporting, to
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
// ensure that your source maps include changes from all other Webpack plugins
|
||||||
module.exports = withSentryConfig(nextConfig, sentryWebpackPluginOptions)
|
module.exports = nextConfig
|
||||||
|
24
package.json
24
package.json
@ -6,17 +6,16 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"lint": "eslint ./src/ && yarn prettier-check",
|
"lint": "eslint ./src/ && yarn prettier-check",
|
||||||
|
"index": "vscode-generate-index-standalone src/",
|
||||||
"format": "yarn index && eslint ./src/ --fix && prettier --write ./src/",
|
"format": "yarn index && eslint ./src/ --fix && prettier --write ./src/",
|
||||||
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
|
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
|
||||||
"start": "next start",
|
"start": "next start"
|
||||||
"index": "vscode-generate-index-standalone src/"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cosmjs/cosmwasm-stargate": "^0.29.4",
|
"@cosmjs/cosmwasm-stargate": "^0.29.4",
|
||||||
"@cosmjs/stargate": "^0.29.5",
|
"@cosmjs/stargate": "^0.29.5",
|
||||||
"@headlessui/react": "^1.7.0",
|
"@headlessui/react": "^1.7.0",
|
||||||
"@marsprotocol/wallet-connector": "^0.9.5",
|
"@marsprotocol/wallet-connector": "^1.4.2",
|
||||||
"@metamask/detect-provider": "^1.2.0",
|
|
||||||
"@radix-ui/react-slider": "^1.0.0",
|
"@radix-ui/react-slider": "^1.0.0",
|
||||||
"@sentry/nextjs": "^7.12.1",
|
"@sentry/nextjs": "^7.12.1",
|
||||||
"@tanstack/react-query": "^4.3.4",
|
"@tanstack/react-query": "^4.3.4",
|
||||||
@ -30,14 +29,16 @@
|
|||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"graphql-request": "^5.0.0",
|
"graphql-request": "^5.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"next": "12.3.1",
|
"next": "^13.1.6",
|
||||||
"react": "18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-device-detect": "^2.2.3",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
"react-number-format": "^5.1.0",
|
"react-number-format": "^5.1.0",
|
||||||
"react-spring": "^9.5.5",
|
"react-spring": "^9.5.5",
|
||||||
"react-toastify": "^9.0.8",
|
"react-toastify": "^9.0.8",
|
||||||
"react-use-clipboard": "^1.0.9",
|
"react-use-clipboard": "^1.0.9",
|
||||||
"recharts": "^2.2.0",
|
"recharts": "^2.2.0",
|
||||||
|
"swr": "^2.0.3",
|
||||||
"tailwindcss-border-gradient-radius": "^3.0.1",
|
"tailwindcss-border-gradient-radius": "^3.0.1",
|
||||||
"use-local-storage-state": "^18.1.1",
|
"use-local-storage-state": "^18.1.1",
|
||||||
"zustand": "^4.1.4"
|
"zustand": "^4.1.4"
|
||||||
@ -49,13 +50,16 @@
|
|||||||
"@types/react-dom": "18.0.9",
|
"@types/react-dom": "18.0.9",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"eslint": "8.30.0",
|
"eslint": "8.30.0",
|
||||||
"eslint-config-next": "12.3.1",
|
"eslint-config-next": "^13.1.6",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"postcss": "^8.4.16",
|
"postcss": "^8.4.16",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prettier-plugin-tailwindcss": "^0.1.13",
|
"prettier-plugin-tailwindcss": "^0.1.13",
|
||||||
"tailwindcss": "^3.2.1",
|
"tailwindcss": "^3.2.1",
|
||||||
"typescript": "4.9.4",
|
"typescript": "4.9.4"
|
||||||
"vscode-generate-index-standalone": "^1.6.0"
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@types/react": "18.0.26",
|
||||||
|
"@types/react-dom": "18.0.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
src/app/borrow/loading.tsx
Normal file
3
src/app/borrow/loading.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function laoding() {
|
||||||
|
return '...isLoading'
|
||||||
|
}
|
7
src/app/borrow/page.tsx
Normal file
7
src/app/borrow/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { getBorrowData } from 'utils/api'
|
||||||
|
|
||||||
|
export default async function page() {
|
||||||
|
const borrowData = await getBorrowData()
|
||||||
|
|
||||||
|
return `You are a guest`
|
||||||
|
}
|
3
src/app/council/page.tsx
Normal file
3
src/app/council/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a guest`
|
||||||
|
}
|
3
src/app/earn/page.tsx
Normal file
3
src/app/earn/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a guest`
|
||||||
|
}
|
30
src/app/head.tsx
Normal file
30
src/app/head.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export default function Head() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<title>Mars Protocol V2</title>
|
||||||
|
<meta charSet='utf-8' />
|
||||||
|
<link href='/favicon.svg' rel='icon' />
|
||||||
|
<link href='/apple-touch-icon.png' rel='apple-touch-icon' sizes='180x180' />
|
||||||
|
<link href='/site.webmanifest' rel='manifest' />
|
||||||
|
<link color='#dd5b65' href='/safari-pinned-tab.svg' rel='mask-icon' />
|
||||||
|
<meta content='index,follow' name='robots' />
|
||||||
|
<meta
|
||||||
|
content="Lend, borrow and earn on the galaxy's most powerful credit protocol or enter the Fields of Mars for advanced DeFi strategies."
|
||||||
|
name='description'
|
||||||
|
/>
|
||||||
|
<meta content='summary_large_image' name='twitter:card' />
|
||||||
|
<meta content='@mars_protocol' name='twitter:site' />
|
||||||
|
<meta content='@mars_protocol' name='twitter:creator' />
|
||||||
|
<meta content='https://osmosis.marsprotocol.io' property='og:url' />
|
||||||
|
<meta content='Mars Protocol V2 - Powered by Osmosis' property='og:title' />
|
||||||
|
<meta
|
||||||
|
content="Lend, borrow and earn on the galaxy's most powerful credit protocol or enter the Fields of Mars for advanced DeFi strategies."
|
||||||
|
property='og:description'
|
||||||
|
/>
|
||||||
|
<meta content='https://osmosis.marsprotocol.io/banner.png' property='og:image' />
|
||||||
|
<meta content='Mars Protocol V2' property='og:site_name' />
|
||||||
|
<meta content='#ffffff' name='msapplication-TileColor' />
|
||||||
|
<meta content='#ffffff' name='theme-color' />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
29
src/app/layout.tsx
Normal file
29
src/app/layout.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import Background from 'components/Background'
|
||||||
|
import { Modals } from 'components/Modals'
|
||||||
|
import DesktopNavigation from 'components/Navigation/DesktopNavigation'
|
||||||
|
import Toaster from 'components/Toaster'
|
||||||
|
import { WalletConnectProvider } from 'components/Wallet/WalletConnectProvider'
|
||||||
|
import 'react-toastify/dist/ReactToastify.min.css'
|
||||||
|
import 'styles/globals.css'
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html lang='en'>
|
||||||
|
<head />
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div className='relative min-h-screen w-full'>
|
||||||
|
<WalletConnectProvider>
|
||||||
|
<Background />
|
||||||
|
<DesktopNavigation />
|
||||||
|
</WalletConnectProvider>
|
||||||
|
<Modals />
|
||||||
|
<Toaster />
|
||||||
|
<main className='relative flex lg:min-h-[calc(100vh-120px)]'>
|
||||||
|
<div className='flex flex-grow flex-col flex-wrap'>{children}</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
3
src/app/page.tsx
Normal file
3
src/app/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return 'Connect to your wallet'
|
||||||
|
}
|
3
src/app/portfolio/page.tsx
Normal file
3
src/app/portfolio/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a guest`
|
||||||
|
}
|
3
src/app/trade/page.tsx
Normal file
3
src/app/trade/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a guest`
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function Loading() {
|
||||||
|
return '...isLoading'
|
||||||
|
}
|
31
src/app/wallets/[wallet]/accounts/[account]/borrow/page.tsx
Normal file
31
src/app/wallets/[wallet]/accounts/[account]/borrow/page.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { BorrowTable } from 'components/BorrowTable'
|
||||||
|
import { AccountDebtTable } from 'components/AccountDebtTable'
|
||||||
|
import { Card } from 'components/Card'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
import { Suspense } from 'react'
|
||||||
|
|
||||||
|
export default function page({ params }: { params: PageParams }) {
|
||||||
|
return (
|
||||||
|
<div className='flex w-full flex-col'>
|
||||||
|
<Card className='mb-4'>
|
||||||
|
<Text size='lg' uppercase>
|
||||||
|
Debt data
|
||||||
|
</Text>
|
||||||
|
<Suspense fallback={<Loading className='h-full w-full' />}>
|
||||||
|
{/* @ts-expect-error Server Component */}
|
||||||
|
<AccountDebtTable account={params.account} />
|
||||||
|
</Suspense>
|
||||||
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<Text size='lg' uppercase>
|
||||||
|
Borrow data
|
||||||
|
</Text>
|
||||||
|
<Suspense fallback={<Loading className='h-full w-full' />}>
|
||||||
|
{/* @ts-expect-error Server Component */}
|
||||||
|
<BorrowTable />
|
||||||
|
</Suspense>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function loading() {
|
||||||
|
return '...isLoading'
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { Card, Text } from 'components'
|
import { Card } from 'components/Card'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
|
||||||
const Council = () => {
|
export default function page() {
|
||||||
return (
|
return (
|
||||||
<div className='flex w-full'>
|
<div className='flex w-full'>
|
||||||
<Card>
|
<Card>
|
||||||
@ -11,5 +12,3 @@ const Council = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Council
|
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function loading() {
|
||||||
|
return '...isLoading'
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { Card, Text } from 'components'
|
import { Card } from 'components/Card'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
|
||||||
const Earn = () => {
|
export default function page() {
|
||||||
return (
|
return (
|
||||||
<div className='flex w-full gap-4'>
|
<div className='flex w-full gap-4'>
|
||||||
<Card>
|
<Card>
|
||||||
@ -18,5 +19,3 @@ const Earn = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Earn
|
|
3
src/app/wallets/[wallet]/accounts/[account]/page.tsx
Normal file
3
src/app/wallets/[wallet]/accounts/[account]/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return 'Trade page'
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
export default function page({ params }: { params: PageParams }) {
|
||||||
|
return 'error!'
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import { getCreditAccounts } from 'utils/api'
|
||||||
|
|
||||||
|
export default async function page({ params }: { params: PageParams }) {
|
||||||
|
const creditAccounts = await getCreditAccounts(params.wallet)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex w-full items-start gap-4'>
|
||||||
|
<ul>
|
||||||
|
{creditAccounts.map((account: string, index: number) => (
|
||||||
|
<li key={index}>{account}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function loading() {
|
||||||
|
return '...isLoading'
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Card, Text } from 'components'
|
import { Card } from 'components/Card'
|
||||||
import { TradeActionModule } from 'components/Trade'
|
import { Text } from 'components/Text'
|
||||||
|
|
||||||
const Trade = () => {
|
export default function page() {
|
||||||
return (
|
return (
|
||||||
<div className='flex w-full flex-wrap'>
|
<div className='flex w-full flex-wrap'>
|
||||||
<div className='mb-4 flex flex-grow gap-4'>
|
<div className='mb-4 flex flex-grow gap-4'>
|
||||||
@ -11,9 +11,7 @@ const Trade = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
<div className='flex flex-col gap-4'>
|
<div className='flex flex-col gap-4'>
|
||||||
<Card>
|
<Card>{/* <TradeActionModule /> */}</Card>
|
||||||
<TradeActionModule />
|
|
||||||
</Card>
|
|
||||||
<Card>
|
<Card>
|
||||||
<Text size='lg' uppercase>
|
<Text size='lg' uppercase>
|
||||||
Orderbook module (optional)
|
Orderbook module (optional)
|
||||||
@ -29,5 +27,3 @@ const Trade = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Trade
|
|
3
src/app/wallets/[wallet]/borrow/council/page.tsx
Normal file
3
src/app/wallets/[wallet]/borrow/council/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/borrow/earn/page.tsx
Normal file
3
src/app/wallets/[wallet]/borrow/earn/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/borrow/page.tsx
Normal file
3
src/app/wallets/[wallet]/borrow/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/borrow/portfolio/page.tsx
Normal file
3
src/app/wallets/[wallet]/borrow/portfolio/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/borrow/trade/page.tsx
Normal file
3
src/app/wallets/[wallet]/borrow/trade/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/council/page.tsx
Normal file
3
src/app/wallets/[wallet]/council/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/earn/page.tsx
Normal file
3
src/app/wallets/[wallet]/earn/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
21
src/app/wallets/[wallet]/layout.tsx
Normal file
21
src/app/wallets/[wallet]/layout.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { AccountNavigation } from 'components/Account/AccountNavigation'
|
||||||
|
import { getCreditAccounts } from 'utils/api'
|
||||||
|
|
||||||
|
export default async function RootLayout({
|
||||||
|
children,
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
params: PageParams
|
||||||
|
}) {
|
||||||
|
const creditAccounts = await getCreditAccounts(params.wallet)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='relative hidden bg-header lg:block'>
|
||||||
|
<AccountNavigation creditAccounts={creditAccounts} />
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
3
src/app/wallets/[wallet]/portfolio/page.tsx
Normal file
3
src/app/wallets/[wallet]/portfolio/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
3
src/app/wallets/[wallet]/trade/page.tsx
Normal file
3
src/app/wallets/[wallet]/trade/page.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function page() {
|
||||||
|
return `You are a viewer or a user`
|
||||||
|
}
|
@ -1,20 +1,27 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { Button, LabelValuePair, PositionsList } from 'components'
|
import { AccountManageOverlay } from 'components/Account/AccountManageOverlay'
|
||||||
import { AccountManageOverlay, RiskChart } from 'components/Account'
|
import { RiskChart } from 'components/Account/RiskChart'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
import { ArrowRightLine, ChevronDown, ChevronLeft } from 'components/Icons'
|
import { ArrowRightLine, ChevronDown, ChevronLeft } from 'components/Icons'
|
||||||
import { useAccountStats, useBalances } from 'hooks/data'
|
import { LabelValuePair } from 'components/LabelValuePair'
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore, useSettingsStore } from 'stores'
|
import { PositionsList } from 'components/PositionsList'
|
||||||
import { lookup } from 'utils/formatters'
|
import { useAccountStats } from 'hooks/data/useAccountStats'
|
||||||
|
import { useBalances } from 'hooks/data/useBalances'
|
||||||
|
import { convertFromGwei } from 'utils/formatters'
|
||||||
import { createRiskData } from 'utils/risk'
|
import { createRiskData } from 'utils/risk'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getBaseAsset, getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
export const AccountDetails = () => {
|
export const AccountDetails = () => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const isOpen = useAccountDetailsStore((s) => s.isOpen)
|
const isOpen = useStore((s) => s.isOpen)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
const baseAsset = useNetworkConfigStore((s) => s.assets.base)
|
const baseAsset = getBaseAsset()
|
||||||
|
|
||||||
const balances = useBalances()
|
const balances = useBalances()
|
||||||
const accountStats = useAccountStats()
|
const accountStats = useAccountStats()
|
||||||
@ -36,7 +43,7 @@ export const AccountDetails = () => {
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useAccountDetailsStore.setState({ isOpen: true })
|
useStore.setState({ isOpen: true })
|
||||||
}}
|
}}
|
||||||
variant='text'
|
variant='text'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@ -75,7 +82,7 @@ export const AccountDetails = () => {
|
|||||||
enableAnimations && 'transition-[color]',
|
enableAnimations && 'transition-[color]',
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useAccountDetailsStore.setState({ isOpen: false })
|
useStore.setState({ isOpen: false })
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ArrowRightLine />
|
<ArrowRightLine />
|
||||||
@ -93,7 +100,11 @@ export const AccountDetails = () => {
|
|||||||
label='Total Position:'
|
label='Total Position:'
|
||||||
value={{
|
value={{
|
||||||
format: 'number',
|
format: 'number',
|
||||||
amount: lookup(accountStats?.totalPosition ?? 0, baseAsset.denom, whitelistedAssets),
|
amount: convertFromGwei(
|
||||||
|
accountStats?.totalPosition ?? 0,
|
||||||
|
baseAsset.denom,
|
||||||
|
marketAssets,
|
||||||
|
),
|
||||||
prefix: '$',
|
prefix: '$',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -101,7 +112,7 @@ export const AccountDetails = () => {
|
|||||||
label='Total Liabilities:'
|
label='Total Liabilities:'
|
||||||
value={{
|
value={{
|
||||||
format: 'number',
|
format: 'number',
|
||||||
amount: lookup(accountStats?.totalDebt ?? 0, baseAsset.denom, whitelistedAssets),
|
amount: convertFromGwei(accountStats?.totalDebt ?? 0, baseAsset.denom, marketAssets),
|
||||||
prefix: '$',
|
prefix: '$',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { useEffect } from 'react'
|
'use client'
|
||||||
|
|
||||||
import { Button, Text } from 'components'
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
|
import { Button } from 'components/Button'
|
||||||
import { Add, ArrowDown, ArrowsLeftRight, ArrowUp, Rubbish } from 'components/Icons'
|
import { Add, ArrowDown, ArrowsLeftRight, ArrowUp, Rubbish } from 'components/Icons'
|
||||||
import { Overlay, OverlayAction } from 'components/Overlay'
|
import { Overlay } from 'components/Overlay/Overlay'
|
||||||
import { useCreateCreditAccount, useDeleteCreditAccount } from 'hooks/mutations'
|
import { OverlayAction } from 'components/Overlay/OverlayAction'
|
||||||
import { useAccountDetailsStore, useModalStore } from 'stores'
|
import { Text } from 'components/Text'
|
||||||
|
import useParams from 'hooks/useParams'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { hardcodedFee } from 'utils/contants'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
@ -13,20 +18,22 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
|
export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const createCreditAccount = useStore((s) => s.createCreditAccount)
|
||||||
|
const deleteCreditAccount = useStore((s) => s.deleteCreditAccount)
|
||||||
|
|
||||||
const { mutate: createCreditAccount, isLoading: isLoadingCreate } = useCreateCreditAccount()
|
async function createAccount() {
|
||||||
const { mutate: deleteCreditAccount, isLoading: isLoadingDelete } = useDeleteCreditAccount(
|
const newAccountId = await createCreditAccount({ fee: hardcodedFee })
|
||||||
selectedAccount || '',
|
router.push(`/wallets/${params.wallet}/accounts/${newAccountId}`)
|
||||||
)
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
async function deleteAccountHandler() {
|
||||||
useModalStore.setState({ createAccountModal: isLoadingCreate })
|
const isSuccess = await deleteCreditAccount({ fee: hardcodedFee, accountId: params.account })
|
||||||
}, [isLoadingCreate])
|
if (isSuccess) {
|
||||||
|
router.push(`/wallets/${params.wallet}/accounts`)
|
||||||
useEffect(() => {
|
}
|
||||||
useModalStore.setState({ deleteAccountModal: isLoadingDelete })
|
}
|
||||||
}, [isLoadingDelete])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay className={className} show={show} setShow={setShow}>
|
<Overlay className={className} show={show} setShow={setShow}>
|
||||||
@ -38,7 +45,7 @@ export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
|
|||||||
<Button
|
<Button
|
||||||
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useModalStore.setState({ fundAccountModal: true })
|
useStore.setState({ fundAccountModal: true })
|
||||||
setShow(false)
|
setShow(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -51,7 +58,7 @@ export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
|
|||||||
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
||||||
color='secondary'
|
color='secondary'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useModalStore.setState({ withdrawModal: true })
|
useStore.setState({ withdrawModal: true })
|
||||||
setShow(false)
|
setShow(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -65,13 +72,13 @@ export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
|
|||||||
<OverlayAction
|
<OverlayAction
|
||||||
setShow={setShow}
|
setShow={setShow}
|
||||||
text='Create New Account'
|
text='Create New Account'
|
||||||
onClick={createCreditAccount}
|
onClick={createAccount}
|
||||||
icon={<Add />}
|
icon={<Add />}
|
||||||
/>
|
/>
|
||||||
<OverlayAction
|
<OverlayAction
|
||||||
setShow={setShow}
|
setShow={setShow}
|
||||||
text='Close Account'
|
text='Close Account'
|
||||||
onClick={deleteCreditAccount}
|
onClick={deleteAccountHandler}
|
||||||
icon={<Rubbish />}
|
icon={<Rubbish />}
|
||||||
/>
|
/>
|
||||||
<OverlayAction
|
<OverlayAction
|
||||||
|
@ -1,31 +1,50 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useMemo, useState } from 'react'
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { Button } from 'components'
|
import { AccountManageOverlay } from 'components/Account/AccountManageOverlay'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
import { ChevronDown } from 'components/Icons'
|
import { ChevronDown } from 'components/Icons'
|
||||||
import { Overlay } from 'components/Overlay'
|
import { Overlay } from 'components/Overlay/Overlay'
|
||||||
import { useAccountDetailsStore } from 'stores'
|
import useParams from 'hooks/useParams'
|
||||||
import { AccountManageOverlay } from 'components/Account'
|
import useStore from 'store'
|
||||||
|
import { hardcodedFee } from 'utils/contants'
|
||||||
interface Props {
|
|
||||||
creditAccountsList: string[]
|
|
||||||
selectedAccount: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_VISIBLE_CREDIT_ACCOUNTS = 5
|
const MAX_VISIBLE_CREDIT_ACCOUNTS = 5
|
||||||
|
|
||||||
export const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
|
interface Props {
|
||||||
const { firstCreditAccounts, restCreditAccounts } = useMemo(() => {
|
creditAccounts: string[]
|
||||||
return {
|
|
||||||
firstCreditAccounts: creditAccountsList?.slice(0, MAX_VISIBLE_CREDIT_ACCOUNTS) ?? [],
|
|
||||||
restCreditAccounts: creditAccountsList?.slice(MAX_VISIBLE_CREDIT_ACCOUNTS) ?? [],
|
|
||||||
}
|
}
|
||||||
}, [creditAccountsList])
|
|
||||||
|
export const AccountNavigation = (props: Props) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const address = useStore((s) => s.client?.recentWallet.account?.address) || ''
|
||||||
|
const selectedAccount = params.account
|
||||||
|
const createCreditAccount = useStore((s) => s.createCreditAccount)
|
||||||
|
|
||||||
|
const hasCreditAccounts = !!props.creditAccounts?.length
|
||||||
|
const firstCreditAccounts = props.creditAccounts?.slice(0, MAX_VISIBLE_CREDIT_ACCOUNTS) ?? []
|
||||||
|
const restCreditAccounts = props.creditAccounts?.slice(MAX_VISIBLE_CREDIT_ACCOUNTS) ?? []
|
||||||
|
|
||||||
const [showManageMenu, setShowManageMenu] = useState(false)
|
const [showManageMenu, setShowManageMenu] = useState(false)
|
||||||
const [showMoreMenu, setShowMoreMenu] = useState(false)
|
const [showMoreMenu, setShowMoreMenu] = useState(false)
|
||||||
|
|
||||||
|
async function createAccountHandler() {
|
||||||
|
const accountId = await createCreditAccount({ fee: hardcodedFee })
|
||||||
|
if (!accountId) return
|
||||||
|
router.push(`/wallets/${params.wallet}/accounts/${accountId}`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<section
|
||||||
|
role='navigation'
|
||||||
|
className='flex h-11 w-full items-center gap-6 border-b border-white/20 px-6 text-sm text-white/40'
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{hasCreditAccounts ? (
|
||||||
<>
|
<>
|
||||||
{firstCreditAccounts.map((account) => (
|
{firstCreditAccounts.map((account) => (
|
||||||
<Button
|
<Button
|
||||||
@ -36,7 +55,7 @@ export const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props
|
|||||||
)}
|
)}
|
||||||
variant='text'
|
variant='text'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useAccountDetailsStore.setState({ selectedAccount: account, isOpen: true })
|
router.push(`/wallets/${params.wallet}/accounts/${account}/${params.page}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Account {account}
|
Account {account}
|
||||||
@ -69,7 +88,7 @@ export const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props
|
|||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowMoreMenu(!showMoreMenu)
|
setShowMoreMenu(!showMoreMenu)
|
||||||
useAccountDetailsStore.setState({ selectedAccount: account, isOpen: true })
|
router.push(`/wallets/${params.wallet}/accounts/${account}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Account {account}
|
Account {account}
|
||||||
@ -102,5 +121,10 @@ export const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
<>{address ? <Button onClick={createAccountHandler}>Create Account</Button> : ''}</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
'use client'
|
||||||
import { useEffect } from 'react'
|
|
||||||
|
import BigNumber from 'bignumber.js'
|
||||||
|
|
||||||
import { Button, FormattedNumber, Gauge, Text } from 'components'
|
|
||||||
import { BorrowCapacity } from 'components/BorrowCapacity'
|
import { BorrowCapacity } from 'components/BorrowCapacity'
|
||||||
import { useAccountStats } from 'hooks/data'
|
import { Button } from 'components/Button'
|
||||||
import { useCreateCreditAccount } from 'hooks/mutations'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { useCreditAccounts } from 'hooks/queries'
|
import { Gauge } from 'components/Gauge'
|
||||||
import { useModalStore, useNetworkConfigStore } from 'stores'
|
import { Text } from 'components/Text'
|
||||||
|
import { useAccountStats } from 'hooks/data/useAccountStats'
|
||||||
|
import { useCreditAccounts } from 'hooks/queries/useCreditAccounts'
|
||||||
|
import { getBaseAsset } from 'utils/assets'
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
|
|
||||||
export const AccountStatus = () => {
|
export const AccountStatus = () => {
|
||||||
const baseAsset = useNetworkConfigStore((s) => s.assets.base)
|
const baseAsset = getBaseAsset()
|
||||||
const accountStats = useAccountStats()
|
const accountStats = useAccountStats()
|
||||||
const { data: creditAccountsList } = useCreditAccounts()
|
const { data: creditAccountsList } = useCreditAccounts()
|
||||||
const { mutate: createCreditAccount, isLoading: isLoadingCreate } = useCreateCreditAccount()
|
|
||||||
useEffect(() => {
|
const createCreditAccount = () => {
|
||||||
useModalStore.setState({ createAccountModal: isLoadingCreate })
|
console.log('create credit account')
|
||||||
}, [isLoadingCreate])
|
}
|
||||||
|
|
||||||
const hasCreditAccounts = creditAccountsList && creditAccountsList.length > 0
|
const hasCreditAccounts = creditAccountsList && creditAccountsList.length > 0
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { CircularProgress, Modal, Text } from 'components'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { MarsProtocol } from 'components/Icons'
|
import { MarsProtocol } from 'components/Icons'
|
||||||
import { useModalStore } from 'stores'
|
import { Modal } from 'components/Modal'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
export const ConfirmModal = () => {
|
export const ConfirmModal = () => {
|
||||||
const createOpen = useModalStore((s) => s.createAccountModal)
|
const createOpen = useStore((s) => s.createAccountModal)
|
||||||
const deleteOpen = useModalStore((s) => s.deleteAccountModal)
|
const deleteOpen = useStore((s) => s.deleteAccountModal)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={createOpen || deleteOpen}>
|
<Modal open={createOpen || deleteOpen}>
|
||||||
@ -23,7 +27,7 @@ export const ConfirmModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Text size='2xl' uppercase={true} className='w-full text-center'>
|
<Text size='2xl' uppercase={true} className='w-full text-center'>
|
||||||
{createOpen &&
|
{createOpen &&
|
||||||
'A small step for a Smart Contracts but a big leap for your financial freedom.'}
|
'A small step for a Smart Contract but a big leap for your financial freedom.'}
|
||||||
{deleteOpen && 'Some rovers have to be recycled once in a while...'}
|
{deleteOpen && 'Some rovers have to be recycled once in a while...'}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,28 +1,36 @@
|
|||||||
import { Switch } from '@headlessui/react'
|
'use client'
|
||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import useLocalStorageState from 'use-local-storage-state'
|
|
||||||
|
|
||||||
import { Button, CircularProgress, Modal, Slider, Text } from 'components'
|
import { Switch } from '@headlessui/react'
|
||||||
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { MarsProtocol } from 'components/Icons'
|
import { MarsProtocol } from 'components/Icons'
|
||||||
import { useDepositCreditAccount } from 'hooks/mutations'
|
import { Modal } from 'components/Modal'
|
||||||
import { useAllBalances, useAllowedCoins } from 'hooks/queries'
|
import { Slider } from 'components/Slider'
|
||||||
import { useAccountDetailsStore, useModalStore, useNetworkConfigStore } from 'stores'
|
import { Text } from 'components/Text'
|
||||||
|
import useParams from 'hooks/useParams'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
import { hardcodedFee } from 'utils/contants'
|
||||||
|
import { convertFromGwei, convertToGwei } from 'utils/formatters'
|
||||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||||
|
import { getAccountDeposits } from 'utils/api'
|
||||||
|
|
||||||
export const FundAccountModal = () => {
|
export const FundAccountModal = () => {
|
||||||
// ---------------
|
// ---------------
|
||||||
// STORE
|
// STORE
|
||||||
// ---------------
|
// ---------------
|
||||||
const open = useModalStore((s) => s.fundAccountModal)
|
const open = useStore((s) => s.fundAccountModal)
|
||||||
|
const params = useParams()
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const depositCreditAccount = useStore((s) => s.depositCreditAccount)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const address = useStore((s) => s.client?.recentWallet.account?.address)
|
||||||
const [lendAssets, setLendAssets] = useLocalStorageState(`lendAssets_${selectedAccount}`, {
|
const { data: balancesData, isLoading: balanceIsLoading } = useSWR(address, getAccountDeposits)
|
||||||
defaultValue: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
|
const marketAssets = getMarketAssets()
|
||||||
|
const [lendAssets, setLendAssets] = useState(false)
|
||||||
// ---------------
|
// ---------------
|
||||||
// LOCAL STATE
|
// LOCAL STATE
|
||||||
// ---------------
|
// ---------------
|
||||||
@ -30,41 +38,45 @@ export const FundAccountModal = () => {
|
|||||||
const [selectedToken, setSelectedToken] = useState('')
|
const [selectedToken, setSelectedToken] = useState('')
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// EXTERNAL HOOKS
|
// FUNCTIONS
|
||||||
// ---------------
|
// ---------------
|
||||||
const { data: balancesData } = useAllBalances()
|
async function depositAccountHandler() {
|
||||||
const { data: allowedCoinsData, isLoading: isLoadingAllowedCoins } = useAllowedCoins()
|
if (!selectedToken) return
|
||||||
const { mutate, isLoading } = useDepositCreditAccount(
|
const deposit = {
|
||||||
selectedAccount || '',
|
amount: convertToGwei(amount, selectedToken, marketAssets).toString(),
|
||||||
selectedToken,
|
denom: selectedToken,
|
||||||
BigNumber(amount)
|
}
|
||||||
.times(10 ** getTokenDecimals(selectedToken, whitelistedAssets))
|
const isSuccess = await depositCreditAccount({
|
||||||
.toNumber(),
|
fee: hardcodedFee,
|
||||||
{
|
accountId: params.account,
|
||||||
onSuccess: () => {
|
deposit,
|
||||||
setAmount(0)
|
})
|
||||||
toast.success(
|
if (isSuccess) {
|
||||||
`${amount} ${getTokenSymbol(selectedToken, whitelistedAssets)} successfully Deposited`,
|
useStore.setState({ fundAccountModal: false })
|
||||||
)
|
}
|
||||||
useModalStore.setState({ fundAccountModal: false })
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (allowedCoinsData && allowedCoinsData.length > 0) {
|
if (!marketAssets || !balancesData || selectedToken !== '') return
|
||||||
// initialize selected token when allowedCoins fetch data is available
|
let found = false
|
||||||
setSelectedToken(allowedCoinsData[0])
|
marketAssets.map((asset) => {
|
||||||
|
if (found) return
|
||||||
|
if (balancesData?.find((balance) => balance.denom === asset.denom)?.amount ?? 0 > 0) {
|
||||||
|
setSelectedToken(asset.denom)
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
}, [allowedCoinsData])
|
})
|
||||||
|
}, [marketAssets, balancesData])
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
// VARIABLES
|
||||||
|
// ---------------
|
||||||
const walletAmount = useMemo(() => {
|
const walletAmount = useMemo(() => {
|
||||||
if (!selectedToken) return 0
|
if (!selectedToken) return 0
|
||||||
|
const walletAmount =
|
||||||
return BigNumber(balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0)
|
balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0
|
||||||
.div(10 ** getTokenDecimals(selectedToken, whitelistedAssets))
|
return convertFromGwei(walletAmount, selectedToken, marketAssets)
|
||||||
.toNumber()
|
}, [balancesData, selectedToken, marketAssets])
|
||||||
}, [balancesData, selectedToken, whitelistedAssets])
|
|
||||||
|
|
||||||
const handleValueChange = (value: number) => {
|
const handleValueChange = (value: number) => {
|
||||||
if (value > walletAmount) {
|
if (value > walletAmount) {
|
||||||
@ -76,16 +88,15 @@ export const FundAccountModal = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const setOpen = (open: boolean) => {
|
const setOpen = (open: boolean) => {
|
||||||
useModalStore.setState({ fundAccountModal: open })
|
useStore.setState({ fundAccountModal: open })
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxValue = walletAmount
|
const percentageValue = isNaN(amount) ? 0 : (amount * 100) / walletAmount
|
||||||
const percentageValue = isNaN(amount) ? 0 : (amount * 100) / maxValue
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={open} setOpen={setOpen}>
|
<Modal open={open} setOpen={setOpen}>
|
||||||
<div className='flex min-h-[520px] w-full'>
|
<div className='flex min-h-[520px] w-full'>
|
||||||
{isLoading && (
|
{balanceIsLoading && (
|
||||||
<div className='absolute inset-0 z-40 grid place-items-center bg-black/50'>
|
<div className='absolute inset-0 z-40 grid place-items-center bg-black/50'>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</div>
|
</div>
|
||||||
@ -118,9 +129,6 @@ export const FundAccountModal = () => {
|
|||||||
have any assets in your osmosis wallet use the osmosis bridge to transfer funds to
|
have any assets in your osmosis wallet use the osmosis bridge to transfer funds to
|
||||||
your osmosis wallet.
|
your osmosis wallet.
|
||||||
</Text>
|
</Text>
|
||||||
{isLoadingAllowedCoins ? (
|
|
||||||
<p>Loading...</p>
|
|
||||||
) : (
|
|
||||||
<>
|
<>
|
||||||
<div className='mb-4 rounded-md border border-white/20'>
|
<div className='mb-4 rounded-md border border-white/20'>
|
||||||
<div className='mb-1 flex justify-between border-b border-white/20 p-2'>
|
<div className='mb-1 flex justify-between border-b border-white/20 p-2'>
|
||||||
@ -136,11 +144,16 @@ export const FundAccountModal = () => {
|
|||||||
}}
|
}}
|
||||||
value={selectedToken}
|
value={selectedToken}
|
||||||
>
|
>
|
||||||
{allowedCoinsData?.map((entry) => (
|
{/* {marketAssets?.map((entry) => {
|
||||||
|
const entrySymbol = getTokenSymbol(entry, marketAssets)
|
||||||
|
return (
|
||||||
|
entrySymbol !== '' && (
|
||||||
<option key={entry} value={entry}>
|
<option key={entry} value={entry}>
|
||||||
{getTokenSymbol(entry, whitelistedAssets)}
|
{getTokenSymbol(entry, marketAssets)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
)
|
||||||
|
) */}
|
||||||
|
{/* })} */}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex justify-between p-2'>
|
<div className='flex justify-between p-2'>
|
||||||
@ -159,10 +172,11 @@ export const FundAccountModal = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
<Text size='xs' uppercase className='mb-2 text-white/60'>
|
<Text size='xs' uppercase className='mb-2 text-white/60'>
|
||||||
{`In wallet: ${walletAmount.toLocaleString()} ${getTokenSymbol(
|
{`In wallet: ${walletAmount.toLocaleString()} ${getTokenSymbol(
|
||||||
selectedToken,
|
selectedToken,
|
||||||
whitelistedAssets,
|
marketAssets,
|
||||||
)}`}
|
)}`}
|
||||||
</Text>
|
</Text>
|
||||||
<Slider
|
<Slider
|
||||||
@ -170,16 +184,14 @@ export const FundAccountModal = () => {
|
|||||||
value={percentageValue}
|
value={percentageValue}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const decimal = value[0] / 100
|
const decimal = value[0] / 100
|
||||||
const tokenDecimals = getTokenDecimals(selectedToken, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(selectedToken, marketAssets)
|
||||||
// limit decimal precision based on token contract decimals
|
// limit decimal precision based on token contract decimals
|
||||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
const newAmount = Number((decimal * walletAmount).toFixed(tokenDecimals))
|
||||||
|
|
||||||
setAmount(newAmount)
|
setAmount(newAmount)
|
||||||
}}
|
}}
|
||||||
onMaxClick={() => setAmount(maxValue)}
|
onMaxClick={() => setAmount(walletAmount)}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-2 flex items-center justify-between'>
|
<div className='mb-2 flex items-center justify-between'>
|
||||||
<div>
|
<div>
|
||||||
@ -207,7 +219,7 @@ export const FundAccountModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
className='mt-auto w-full'
|
className='mt-auto w-full'
|
||||||
onClick={() => mutate()}
|
onClick={depositAccountHandler}
|
||||||
disabled={amount === 0 || !amount}
|
disabled={amount === 0 || !amount}
|
||||||
>
|
>
|
||||||
Fund Account
|
Fund Account
|
||||||
|
@ -9,13 +9,14 @@ import {
|
|||||||
YAxis,
|
YAxis,
|
||||||
} from 'recharts'
|
} from 'recharts'
|
||||||
|
|
||||||
import { FormattedNumber, Text } from 'components'
|
|
||||||
import { useAccountStats } from 'hooks/data'
|
|
||||||
import { useSettingsStore } from 'stores'
|
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
import { useAccountStats } from 'hooks/data/useAccountStats'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
export const RiskChart = ({ data }: RiskChartProps) => {
|
export const RiskChart = ({ data }: RiskChartProps) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
const accountStats = useAccountStats()
|
const accountStats = useAccountStats()
|
||||||
const currentRisk = accountStats?.risk ?? 0
|
const currentRisk = accountStats?.risk ?? 0
|
||||||
|
|
||||||
|
@ -4,40 +4,36 @@ import classNames from 'classnames'
|
|||||||
import React, { useEffect, useMemo, useState } from 'react'
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
CircularProgress,
|
|
||||||
FormattedNumber,
|
|
||||||
Gauge,
|
|
||||||
LabelValuePair,
|
|
||||||
Modal,
|
|
||||||
PositionsList,
|
|
||||||
Slider,
|
|
||||||
Text,
|
|
||||||
} from 'components'
|
|
||||||
import { BorrowCapacity } from 'components/BorrowCapacity'
|
import { BorrowCapacity } from 'components/BorrowCapacity'
|
||||||
import { useAccountStats, useBalances, useCalculateMaxWithdrawAmount } from 'hooks/data'
|
import { convertFromGwei, formatValue } from 'utils/formatters'
|
||||||
import { useWithdrawFunds } from 'hooks/mutations'
|
|
||||||
import { useCreditAccountPositions, useTokenPrices } from 'hooks/queries'
|
|
||||||
import {
|
|
||||||
useAccountDetailsStore,
|
|
||||||
useModalStore,
|
|
||||||
useNetworkConfigStore,
|
|
||||||
useWalletStore,
|
|
||||||
} from 'stores'
|
|
||||||
import { formatValue, lookup } from 'utils/formatters'
|
|
||||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||||
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
import { Slider } from 'components/Slider'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import { Gauge } from 'components/Gauge'
|
||||||
|
import { LabelValuePair } from 'components/LabelValuePair'
|
||||||
|
import { Modal } from 'components/Modal'
|
||||||
|
import { PositionsList } from 'components/PositionsList'
|
||||||
|
import { useAccountStats } from 'hooks/data/useAccountStats'
|
||||||
|
import { useBalances } from 'hooks/data/useBalances'
|
||||||
|
import { useCalculateMaxWithdrawAmount } from 'hooks/data/useCalculateMaxWithdrawAmount'
|
||||||
|
import { useWithdrawFunds } from 'hooks/mutations/useWithdrawFunds'
|
||||||
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getBaseAsset, getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
export const WithdrawModal = () => {
|
export const WithdrawModal = () => {
|
||||||
// ---------------
|
// ---------------
|
||||||
// STORE
|
// STORE
|
||||||
// ---------------
|
// ---------------
|
||||||
const open = useModalStore((s) => s.withdrawModal)
|
const open = useStore((s) => s.withdrawModal)
|
||||||
const chainInfo = useWalletStore((s) => s.chainInfo)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
const baseAsset = useNetworkConfigStore((s) => s.assets.base)
|
const baseAsset = getBaseAsset()
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// LOCAL STATE
|
// LOCAL STATE
|
||||||
@ -52,8 +48,8 @@ export const WithdrawModal = () => {
|
|||||||
const { data: tokenPrices } = useTokenPrices()
|
const { data: tokenPrices } = useTokenPrices()
|
||||||
const balances = useBalances()
|
const balances = useBalances()
|
||||||
|
|
||||||
const selectedTokenSymbol = getTokenSymbol(selectedToken, whitelistedAssets)
|
const selectedTokenSymbol = getTokenSymbol(selectedToken, marketAssets)
|
||||||
const selectedTokenDecimals = getTokenDecimals(selectedToken, whitelistedAssets)
|
const selectedTokenDecimals = getTokenDecimals(selectedToken, marketAssets)
|
||||||
|
|
||||||
const tokenAmountInCreditAccount = useMemo(() => {
|
const tokenAmountInCreditAccount = useMemo(() => {
|
||||||
return BigNumber(positionsData?.coins.find((coin) => coin.denom === selectedToken)?.amount ?? 0)
|
return BigNumber(positionsData?.coins.find((coin) => coin.denom === selectedToken)?.amount ?? 0)
|
||||||
@ -96,7 +92,7 @@ export const WithdrawModal = () => {
|
|||||||
|
|
||||||
const { mutate, isLoading } = useWithdrawFunds(withdrawAmount, borrowAmount, selectedToken, {
|
const { mutate, isLoading } = useWithdrawFunds(withdrawAmount, borrowAmount, selectedToken, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
useModalStore.setState({ withdrawModal: false })
|
useStore.setState({ withdrawModal: false })
|
||||||
toast.success(`${amount} ${selectedTokenSymbol} successfully withdrawn`)
|
toast.success(`${amount} ${selectedTokenSymbol} successfully withdrawn`)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -131,13 +127,13 @@ export const WithdrawModal = () => {
|
|||||||
setAmount(0)
|
setAmount(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTokenTotalUSDValue = (amount: string, denom: string, whitelistedAssets: Asset[]) => {
|
const getTokenTotalUSDValue = (amount: string, denom: string, marketAssets: Asset[]) => {
|
||||||
// early return if prices are not fetched yet
|
// early return if prices are not fetched yet
|
||||||
if (!tokenPrices) return 0
|
if (!tokenPrices) return 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
BigNumber(amount)
|
BigNumber(amount)
|
||||||
.div(10 ** getTokenDecimals(denom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(denom, marketAssets))
|
||||||
.toNumber() * tokenPrices[denom]
|
.toNumber() * tokenPrices[denom]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -149,7 +145,7 @@ export const WithdrawModal = () => {
|
|||||||
}, [amount, maxWithdrawAmount])
|
}, [amount, maxWithdrawAmount])
|
||||||
|
|
||||||
const setOpen = (open: boolean) => {
|
const setOpen = (open: boolean) => {
|
||||||
useModalStore.setState({ withdrawModal: open })
|
useStore.setState({ withdrawModal: open })
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -183,7 +179,7 @@ export const WithdrawModal = () => {
|
|||||||
>
|
>
|
||||||
{positionsData?.coins?.map((coin) => (
|
{positionsData?.coins?.map((coin) => (
|
||||||
<option key={coin.denom} value={coin.denom}>
|
<option key={coin.denom} value={coin.denom}>
|
||||||
{getTokenSymbol(coin.denom, whitelistedAssets)}
|
{getTokenSymbol(coin.denom, marketAssets)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@ -310,10 +306,10 @@ export const WithdrawModal = () => {
|
|||||||
label='Total Position:'
|
label='Total Position:'
|
||||||
value={{
|
value={{
|
||||||
format: 'number',
|
format: 'number',
|
||||||
amount: lookup(
|
amount: convertFromGwei(
|
||||||
accountStats?.totalPosition ?? 0,
|
accountStats?.totalPosition ?? 0,
|
||||||
baseAsset.denom,
|
baseAsset.denom,
|
||||||
whitelistedAssets,
|
marketAssets,
|
||||||
),
|
),
|
||||||
prefix: '$',
|
prefix: '$',
|
||||||
}}
|
}}
|
||||||
@ -322,7 +318,11 @@ export const WithdrawModal = () => {
|
|||||||
label='Total Liabilities:'
|
label='Total Liabilities:'
|
||||||
value={{
|
value={{
|
||||||
format: 'number',
|
format: 'number',
|
||||||
amount: lookup(accountStats?.totalDebt ?? 0, baseAsset.denom, whitelistedAssets),
|
amount: convertFromGwei(
|
||||||
|
accountStats?.totalDebt ?? 0,
|
||||||
|
baseAsset.denom,
|
||||||
|
marketAssets,
|
||||||
|
),
|
||||||
prefix: '$',
|
prefix: '$',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { AccountDetails } from './AccountDetails'
|
|
||||||
export { AccountManageOverlay } from './AccountManageOverlay'
|
|
||||||
export { AccountNavigation } from './AccountNavigation'
|
|
||||||
export { AccountStatus } from './AccountStatus'
|
|
||||||
export { ConfirmModal } from './ConfirmModal'
|
|
||||||
export { FundAccountModal } from './FundAccountModal'
|
|
||||||
export { RiskChart } from './RiskChart'
|
|
||||||
export { WithdrawModal } from './WithdrawModal'
|
|
||||||
// @endindex
|
|
17
src/components/AccountDebtTable.tsx
Normal file
17
src/components/AccountDebtTable.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { getAccountDebts } from 'utils/api'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function AccountDebtTable(props: Props) {
|
||||||
|
const debtData = await getAccountDebts(props.account)
|
||||||
|
|
||||||
|
return debtData.map((debt) => {
|
||||||
|
return (
|
||||||
|
<p key={debt.denom}>
|
||||||
|
{debt.denom} {debt.amount}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
21
src/components/Background.tsx
Normal file
21
src/components/Background.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useWalletManager, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
day: 'brightness-100 hue-rotate-0',
|
||||||
|
night: '-hue-rotate-82 brightness-30',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Background() {
|
||||||
|
const { status } = useWalletManager()
|
||||||
|
|
||||||
|
const backgroundClasses = classNames(
|
||||||
|
status === WalletConnectionStatus.Connected ? filter.day : filter.night,
|
||||||
|
'top-0 left-0 absolute block h-full w-full flex-col bg-body bg-mars bg-desktop bg-top bg-no-repeat filter',
|
||||||
|
true && 'transition-background duration-3000 ease-linear',
|
||||||
|
)
|
||||||
|
|
||||||
|
return <div className={backgroundClasses} />
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { Button } from 'components'
|
|
||||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||||
import { formatCurrency } from 'utils/formatters'
|
import { formatCurrency } from 'utils/formatters'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
|
||||||
type AssetRowProps = {
|
type AssetRowProps = {
|
||||||
data: {
|
data: {
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { AssetRow } from 'components/Borrow'
|
import { AssetRow } from 'components/Borrow/AssetRow'
|
||||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||||
import { formatCurrency } from 'utils/formatters'
|
import { formatCurrency } from 'utils/formatters'
|
||||||
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
// @index(['./**/*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { AssetRow } from './AssetRow'
|
|
||||||
export { BorrowTable } from './BorrowTable'
|
|
||||||
// @endindex
|
|
@ -1,8 +1,10 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { FormattedNumber, Text, Tooltip } from 'components'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { useSettingsStore } from 'stores'
|
import { Text } from 'components/Text'
|
||||||
|
import { Tooltip } from 'components/Tooltip'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
balance: number
|
balance: number
|
||||||
@ -27,7 +29,7 @@ export const BorrowCapacity = ({
|
|||||||
hideValues,
|
hideValues,
|
||||||
decimals = 2,
|
decimals = 2,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
const [percentOfMaxRound, setPercentOfMaxRound] = useState(0)
|
const [percentOfMaxRound, setPercentOfMaxRound] = useState(0)
|
||||||
const [percentOfMaxRange, setPercentOfMaxRange] = useState(0)
|
const [percentOfMaxRange, setPercentOfMaxRange] = useState(0)
|
||||||
|
@ -4,23 +4,26 @@ import React, { useMemo, useState } from 'react'
|
|||||||
import { NumericFormat } from 'react-number-format'
|
import { NumericFormat } from 'react-number-format'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
import {
|
import { Button } from 'components/Button'
|
||||||
Button,
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
CircularProgress,
|
import { ContainerSecondary } from 'components/ContainerSecondary'
|
||||||
ContainerSecondary,
|
import { Gauge } from 'components/Gauge'
|
||||||
Gauge,
|
import { PositionsList } from 'components/PositionsList'
|
||||||
PositionsList,
|
import { ProgressBar } from 'components/ProgressBar'
|
||||||
ProgressBar,
|
import { Slider } from 'components/Slider'
|
||||||
Slider,
|
import { Text } from 'components/Text'
|
||||||
Text,
|
import { Tooltip } from 'components/Tooltip'
|
||||||
Tooltip,
|
import { useAccountStats } from 'hooks/data/useAccountStats'
|
||||||
} from 'components'
|
import { useBalances } from 'hooks/data/useBalances'
|
||||||
import { useAccountStats, useBalances, useCalculateMaxBorrowAmount } from 'hooks/data'
|
import { useCalculateMaxBorrowAmount } from 'hooks/data/useCalculateMaxBorrowAmount'
|
||||||
import { useBorrowFunds } from 'hooks/mutations'
|
import { useBorrowFunds } from 'hooks/mutations/useBorrowFunds'
|
||||||
import { useAllBalances, useMarkets, useTokenPrices } from 'hooks/queries'
|
import { useAllBalances } from 'hooks/queries/useAllBalances'
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
import { formatCurrency, formatValue } from 'utils/formatters'
|
import { formatCurrency, formatValue } from 'utils/formatters'
|
||||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getBaseAsset, getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
show: boolean
|
show: boolean
|
||||||
@ -32,15 +35,15 @@ export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
const [amount, setAmount] = useState(0)
|
const [amount, setAmount] = useState(0)
|
||||||
const [isBorrowToCreditAccount, setIsBorrowToCreditAccount] = useState(false)
|
const [isBorrowToCreditAccount, setIsBorrowToCreditAccount] = useState(false)
|
||||||
|
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
const baseAsset = useNetworkConfigStore((s) => s.assets.base)
|
const baseAsset = getBaseAsset()
|
||||||
|
|
||||||
const balances = useBalances()
|
const balances = useBalances()
|
||||||
|
|
||||||
const { actions, borrowAmount } = useMemo(() => {
|
const { actions, borrowAmount } = useMemo(() => {
|
||||||
const borrowAmount = BigNumber(amount)
|
const borrowAmount = BigNumber(amount)
|
||||||
.times(10 ** getTokenDecimals(tokenDenom, whitelistedAssets))
|
.times(10 ** getTokenDecimals(tokenDenom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
|
|
||||||
const withdrawAmount = isBorrowToCreditAccount ? 0 : borrowAmount
|
const withdrawAmount = isBorrowToCreditAccount ? 0 : borrowAmount
|
||||||
@ -61,11 +64,11 @@ export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
},
|
},
|
||||||
] as AccountStatsAction[],
|
] as AccountStatsAction[],
|
||||||
}
|
}
|
||||||
}, [amount, isBorrowToCreditAccount, tokenDenom, whitelistedAssets])
|
}, [amount, isBorrowToCreditAccount, tokenDenom, marketAssets])
|
||||||
|
|
||||||
const accountStats = useAccountStats(actions)
|
const accountStats = useAccountStats(actions)
|
||||||
|
|
||||||
const tokenSymbol = getTokenSymbol(tokenDenom, whitelistedAssets)
|
const tokenSymbol = getTokenSymbol(tokenDenom, marketAssets)
|
||||||
|
|
||||||
const { mutate, isLoading } = useBorrowFunds(borrowAmount, tokenDenom, !isBorrowToCreditAccount, {
|
const { mutate, isLoading } = useBorrowFunds(borrowAmount, tokenDenom, !isBorrowToCreditAccount, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@ -84,9 +87,9 @@ export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
|
|
||||||
const walletAmount = useMemo(() => {
|
const walletAmount = useMemo(() => {
|
||||||
return BigNumber(balancesData?.find((balance) => balance.denom === tokenDenom)?.amount ?? 0)
|
return BigNumber(balancesData?.find((balance) => balance.denom === tokenDenom)?.amount ?? 0)
|
||||||
.div(10 ** getTokenDecimals(tokenDenom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(tokenDenom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
}, [balancesData, tokenDenom, whitelistedAssets])
|
}, [balancesData, tokenDenom, marketAssets])
|
||||||
|
|
||||||
const tokenPrice = tokenPrices?.[tokenDenom] ?? 0
|
const tokenPrice = tokenPrices?.[tokenDenom] ?? 0
|
||||||
const borrowRate = Number(marketsData?.[tokenDenom]?.borrow_rate)
|
const borrowRate = Number(marketsData?.[tokenDenom]?.borrow_rate)
|
||||||
@ -110,7 +113,7 @@ export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
|
|
||||||
const handleSliderValueChange = (value: number[]) => {
|
const handleSliderValueChange = (value: number[]) => {
|
||||||
const decimal = value[0] / 100
|
const decimal = value[0] / 100
|
||||||
const tokenDecimals = getTokenDecimals(tokenDenom, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(tokenDenom, marketAssets)
|
||||||
// limit decimal precision based on token contract decimals
|
// limit decimal precision based on token contract decimals
|
||||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||||
|
|
||||||
@ -175,7 +178,7 @@ export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
allowNegative={false}
|
allowNegative={false}
|
||||||
onValueChange={(v) => handleValueChange(v.floatValue || 0)}
|
onValueChange={(v) => handleValueChange(v.floatValue || 0)}
|
||||||
suffix={` ${tokenSymbol}`}
|
suffix={` ${tokenSymbol}`}
|
||||||
decimalScale={getTokenDecimals(tokenDenom, whitelistedAssets)}
|
decimalScale={getTokenDecimals(tokenDenom, marketAssets)}
|
||||||
/>
|
/>
|
||||||
<div className='flex justify-between text-xs tracking-widest'>
|
<div className='flex justify-between text-xs tracking-widest'>
|
||||||
<div>
|
<div>
|
||||||
|
13
src/components/BorrowTable.tsx
Normal file
13
src/components/BorrowTable.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { getBorrowData } from 'utils/api'
|
||||||
|
|
||||||
|
export async function BorrowTable() {
|
||||||
|
const borrowData = await getBorrowData()
|
||||||
|
|
||||||
|
return borrowData.map((borrow) => {
|
||||||
|
return (
|
||||||
|
<p key={borrow.denom}>
|
||||||
|
{borrow.denom} {borrow.borrowRate} {borrow.marketLiquidity}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import React, { LegacyRef, ReactNode } from 'react'
|
import React, { LegacyRef, ReactNode } from 'react'
|
||||||
|
|
||||||
import { CircularProgress } from 'components'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children?: string | ReactNode
|
children?: string | ReactNode
|
||||||
@ -74,7 +74,7 @@ export const Button = React.forwardRef(function Button(
|
|||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const buttonClasses = []
|
const buttonClasses = []
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
case 'round':
|
case 'round':
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { Text } from 'components'
|
import { Text } from 'components/Text'
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
color?: string
|
color?: string
|
||||||
@ -10,7 +10,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CircularProgress = ({ color = '#FFFFFF', size = 20, className }: Props) => {
|
export const CircularProgress = ({ color = '#FFFFFF', size = 20, className }: Props) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
const borderWidth = `${size / 10}px`
|
const borderWidth = `${size / 10}px`
|
||||||
const borderColor = `${color} transparent transparent transparent`
|
const borderColor = `${color} transparent transparent transparent`
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import classNames from 'classnames'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import { DocURL } from 'types/enums/docURL'
|
|
||||||
|
|
||||||
import { Button } from './Button'
|
|
||||||
|
|
||||||
export const CookieConsent = () => {
|
|
||||||
const [cookieConsent, setCookieConsent] = useState<boolean>(true)
|
|
||||||
|
|
||||||
const createCookie = () => {
|
|
||||||
setCookieConsent(true)
|
|
||||||
document.cookie = 'viewed_cookie_policy=yes; path=/'
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCookieConsent(!!document.cookie.match(new RegExp('(^| )viewed_cookie_policy=([^;]+)')))
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return cookieConsent ? null : (
|
|
||||||
<section
|
|
||||||
className={classNames(
|
|
||||||
'fixed bottom-0 left-0 z-50 flex w-full bg-black/90 p-4',
|
|
||||||
'md:bg-black/70',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'mx-auto my-0 flex max-w-screen-xl flex-wrap items-center justify-center gap-4',
|
|
||||||
'md:flex-nowrap',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<p className='basis-full text-sm'>
|
|
||||||
This website uses cookies to improve its functionality and optimize content delivery. By
|
|
||||||
using this website, you agree to the use of cookies for these purposes. Learn more,
|
|
||||||
including how to modify your cookie settings, in Marsprotocol.io's{' '}
|
|
||||||
<a
|
|
||||||
href={DocURL.PRIVACY_POLICY_URL}
|
|
||||||
target='_blank'
|
|
||||||
rel='nofollow noreferrer'
|
|
||||||
title='Privacy Policy'
|
|
||||||
>
|
|
||||||
privacy
|
|
||||||
</a>{' '}
|
|
||||||
and{' '}
|
|
||||||
<a
|
|
||||||
href={DocURL.COOKIE_POLICY_URL}
|
|
||||||
target='_blank'
|
|
||||||
rel='nofollow noreferrer'
|
|
||||||
title='Cookie Policy'
|
|
||||||
>
|
|
||||||
cookie
|
|
||||||
</a>{' '}
|
|
||||||
policies.
|
|
||||||
</p>
|
|
||||||
<Button onClick={createCookie} text='Understood' />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,8 +1,10 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import React, { useEffect, useRef } from 'react'
|
import React, { useEffect, useRef } from 'react'
|
||||||
import { animated, useSpring } from 'react-spring'
|
import { animated, useSpring } from 'react-spring'
|
||||||
|
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
|
|
||||||
export const FormattedNumber = React.memo(
|
export const FormattedNumber = React.memo(
|
||||||
@ -18,7 +20,7 @@ export const FormattedNumber = React.memo(
|
|||||||
rounded = false,
|
rounded = false,
|
||||||
abbreviated = false,
|
abbreviated = false,
|
||||||
}: FormattedNumberProps) => {
|
}: FormattedNumberProps) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
const prevAmountRef = useRef<number>(0)
|
const prevAmountRef = useRef<number>(0)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import { Tooltip } from 'components'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tooltip: string | ReactNode
|
tooltip: string | ReactNode
|
||||||
@ -20,7 +20,7 @@ export const Gauge = ({
|
|||||||
label,
|
label,
|
||||||
tooltip,
|
tooltip,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
const percentage = value * 100
|
const percentage = value * 100
|
||||||
const percentageValue = percentage > 100 ? 100 : percentage < 0 ? 0 : percentage
|
const percentageValue = percentage > 100 ? 100 : percentage < 0 ? 0 : percentage
|
||||||
|
@ -1,48 +1,48 @@
|
|||||||
// @index(['./*.svg'], f => `export { default as ${f.name} } from '${f.path}.svg'`)
|
// @index(['./*.svg'], f => `export { default as ${f.name} } from 'components/Icons/${f.name}.svg'`)
|
||||||
export { default as Add } from './Add.svg'
|
export { default as Add } from 'components/Icons/Add.svg'
|
||||||
export { default as ArrowBack } from './ArrowBack.svg'
|
export { default as ArrowBack } from 'components/Icons/ArrowBack.svg'
|
||||||
export { default as ArrowDown } from './ArrowDown.svg'
|
export { default as ArrowDown } from 'components/Icons/ArrowDown.svg'
|
||||||
export { default as ArrowLeftLine } from './ArrowLeftLine.svg'
|
export { default as ArrowLeftLine } from 'components/Icons/ArrowLeftLine.svg'
|
||||||
export { default as ArrowRightLine } from './ArrowRightLine.svg'
|
export { default as ArrowRightLine } from 'components/Icons/ArrowRightLine.svg'
|
||||||
export { default as ArrowsLeftRight } from './ArrowsLeftRight.svg'
|
export { default as ArrowsLeftRight } from 'components/Icons/ArrowsLeftRight.svg'
|
||||||
export { default as ArrowsUpDown } from './ArrowsUpDown.svg'
|
export { default as ArrowsUpDown } from 'components/Icons/ArrowsUpDown.svg'
|
||||||
export { default as ArrowUp } from './ArrowUp.svg'
|
export { default as ArrowUp } from 'components/Icons/ArrowUp.svg'
|
||||||
export { default as BurgerMenu } from './BurgerMenu.svg'
|
export { default as BurgerMenu } from 'components/Icons/BurgerMenu.svg'
|
||||||
export { default as Check } from './Check.svg'
|
export { default as Check } from 'components/Icons/Check.svg'
|
||||||
export { default as ChevronDown } from './ChevronDown.svg'
|
export { default as ChevronDown } from 'components/Icons/ChevronDown.svg'
|
||||||
export { default as ChevronLeft } from './ChevronLeft.svg'
|
export { default as ChevronLeft } from 'components/Icons/ChevronLeft.svg'
|
||||||
export { default as ChevronRight } from './ChevronRight.svg'
|
export { default as ChevronRight } from 'components/Icons/ChevronRight.svg'
|
||||||
export { default as ChevronUp } from './ChevronUp.svg'
|
export { default as ChevronUp } from 'components/Icons/ChevronUp.svg'
|
||||||
export { default as Close } from './Close.svg'
|
export { default as Close } from 'components/Icons/Close.svg'
|
||||||
export { default as Copy } from './Copy.svg'
|
export { default as Copy } from 'components/Icons/Copy.svg'
|
||||||
export { default as Deposit } from './Deposit.svg'
|
export { default as Deposit } from 'components/Icons/Deposit.svg'
|
||||||
export { default as Discord } from './Discord.svg'
|
export { default as Discord } from 'components/Icons/Discord.svg'
|
||||||
export { default as Edit } from './Edit.svg'
|
export { default as Edit } from 'components/Icons/Edit.svg'
|
||||||
export { default as Ellipsis } from './Ellipsis.svg'
|
export { default as Ellipsis } from 'components/Icons/Ellipsis.svg'
|
||||||
export { default as ExternalLink } from './ExternalLink.svg'
|
export { default as ExternalLink } from 'components/Icons/ExternalLink.svg'
|
||||||
export { default as Failed } from './Failed.svg'
|
export { default as Failed } from 'components/Icons/Failed.svg'
|
||||||
export { default as Github } from './Github.svg'
|
export { default as Github } from 'components/Icons/Github.svg'
|
||||||
export { default as Info } from './Info.svg'
|
export { default as Info } from 'components/Icons/Info.svg'
|
||||||
export { default as Logo } from './Logo.svg'
|
export { default as Logo } from 'components/Icons/Logo.svg'
|
||||||
export { default as MarsProtocol } from './MarsProtocol.svg'
|
export { default as MarsProtocol } from 'components/Icons/MarsProtocol.svg'
|
||||||
export { default as Medium } from './Medium.svg'
|
export { default as Medium } from 'components/Icons/Medium.svg'
|
||||||
export { default as Osmo } from './Osmo.svg'
|
export { default as Osmo } from 'components/Icons/Osmo.svg'
|
||||||
export { default as Questionmark } from './Questionmark.svg'
|
export { default as Questionmark } from 'components/Icons/Questionmark.svg'
|
||||||
export { default as Reddit } from './Reddit.svg'
|
export { default as Reddit } from 'components/Icons/Reddit.svg'
|
||||||
export { default as Rubbish } from './Rubbish.svg'
|
export { default as Rubbish } from 'components/Icons/Rubbish.svg'
|
||||||
export { default as Search } from './Search.svg'
|
export { default as Search } from 'components/Icons/Search.svg'
|
||||||
export { default as SmallClose } from './SmallClose.svg'
|
export { default as SmallClose } from 'components/Icons/SmallClose.svg'
|
||||||
export { default as SortAsc } from './SortAsc.svg'
|
export { default as SortAsc } from 'components/Icons/SortAsc.svg'
|
||||||
export { default as SortDesc } from './SortDesc.svg'
|
export { default as SortDesc } from 'components/Icons/SortDesc.svg'
|
||||||
export { default as SortNone } from './SortNone.svg'
|
export { default as SortNone } from 'components/Icons/SortNone.svg'
|
||||||
export { default as Subtract } from './Subtract.svg'
|
export { default as Subtract } from 'components/Icons/Subtract.svg'
|
||||||
export { default as Success } from './Success.svg'
|
export { default as Success } from 'components/Icons/Success.svg'
|
||||||
export { default as Telegram } from './Telegram.svg'
|
export { default as Telegram } from 'components/Icons/Telegram.svg'
|
||||||
export { default as TriangleDown } from './TriangleDown.svg'
|
export { default as TriangleDown } from 'components/Icons/TriangleDown.svg'
|
||||||
export { default as Twitter } from './Twitter.svg'
|
export { default as Twitter } from 'components/Icons/Twitter.svg'
|
||||||
export { default as Wallet } from './Wallet.svg'
|
export { default as Wallet } from 'components/Icons/Wallet.svg'
|
||||||
export { default as WalletConnect } from './WalletConnect.svg'
|
export { default as WalletConnect } from 'components/Icons/WalletConnect.svg'
|
||||||
export { default as Warning } from './Warning.svg'
|
export { default as Warning } from 'components/Icons/Warning.svg'
|
||||||
export { default as Withdraw } from './Withdraw.svg'
|
export { default as Withdraw } from 'components/Icons/Withdraw.svg'
|
||||||
export { default as YouTube } from './YouTube.svg'
|
export { default as YouTube } from 'components/Icons/YouTube.svg'
|
||||||
// @endindex
|
// @endindex
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { FormattedNumber, Text } from 'components'
|
import { Text } from 'components/Text'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
|
||||||
interface ValueData extends FormattedNumberProps {
|
interface ValueData extends FormattedNumberProps {
|
||||||
format?: 'number' | 'string'
|
format?: 'number' | 'string'
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import { useWallet, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
|
||||||
import classNames from 'classnames'
|
|
||||||
import React, { useEffect } from 'react'
|
|
||||||
|
|
||||||
import { AccountDetails } from 'components/Account'
|
|
||||||
import { DesktopNavigation } from 'components/Navigation'
|
|
||||||
import { useCreditAccounts } from 'hooks/queries'
|
|
||||||
import { useSettingsStore, useWalletStore } from 'stores'
|
|
||||||
|
|
||||||
import { CookieConsent } from './CookieConsent'
|
|
||||||
|
|
||||||
const filter = {
|
|
||||||
day: 'brightness-100 hue-rotate-0',
|
|
||||||
night: '-hue-rotate-82 brightness-30',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Layout = ({ children }: { children: React.ReactNode }) => {
|
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
|
||||||
|
|
||||||
const { data: creditAccountsList } = useCreditAccounts()
|
|
||||||
const hasCreditAccounts = creditAccountsList && creditAccountsList.length > 0
|
|
||||||
|
|
||||||
const { status, signingCosmWasmClient, chainInfo, address, name } = useWallet()
|
|
||||||
const initialize = useWalletStore((s) => s.actions.initialize)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
initialize(status, signingCosmWasmClient, address, name, chainInfo)
|
|
||||||
}, [status, signingCosmWasmClient, chainInfo, address, name, initialize])
|
|
||||||
|
|
||||||
const isConnected = status === WalletConnectionStatus.Connected
|
|
||||||
|
|
||||||
const backgroundClasses = classNames(
|
|
||||||
isConnected ? filter.day : filter.night,
|
|
||||||
'top-0 left-0 absolute block h-full w-full flex-col bg-body bg-mars bg-desktop bg-top bg-no-repeat filter',
|
|
||||||
enableAnimations && 'transition-background duration-3000 ease-linear',
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='relative min-h-screen w-full'>
|
|
||||||
<div className={backgroundClasses} />
|
|
||||||
<DesktopNavigation />
|
|
||||||
<main className='relative flex lg:min-h-[calc(100vh-120px)]'>
|
|
||||||
<div className='flex flex-grow flex-wrap p-6'>{children}</div>
|
|
||||||
{hasCreditAccounts && <AccountDetails />}
|
|
||||||
</main>
|
|
||||||
<CookieConsent />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
28
src/components/Loading.tsx
Normal file
28
src/components/Loading.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
className?: string
|
||||||
|
count?: number
|
||||||
|
height?: number
|
||||||
|
width?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Loading(props: Props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Array.from({ length: props.count ?? 1 }, (_, i) => (
|
||||||
|
<div
|
||||||
|
role='status'
|
||||||
|
className={classNames(
|
||||||
|
'animate-pulse rounded-full bg-white/40',
|
||||||
|
props.className,
|
||||||
|
props.height ? `h-${props.height}` : 'h-3',
|
||||||
|
props.width ? `w-${props.width}` : 'w-full',
|
||||||
|
)}
|
||||||
|
key={i}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<span className='sr-only'>Loading...</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import { Card } from 'components'
|
|
||||||
import { Close } from 'components/Icons'
|
import { Close } from 'components/Icons'
|
||||||
|
import { Card } from 'components/Card'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children?: ReactNode | string
|
children?: ReactNode | string
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { ConfirmModal, FundAccountModal, WithdrawModal } from './Account'
|
'use client'
|
||||||
|
|
||||||
|
import { ConfirmModal } from 'components/Account/ConfirmModal'
|
||||||
|
import { FundAccountModal } from 'components/Account/FundAccountModal'
|
||||||
|
|
||||||
export const Modals = () => (
|
export const Modals = () => (
|
||||||
<>
|
<>
|
||||||
<FundAccountModal />
|
<FundAccountModal />
|
||||||
<WithdrawModal />
|
{/* <WithdrawModal /> */}
|
||||||
<ConfirmModal />
|
<ConfirmModal />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,33 +1,36 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { usePathname } from 'next/navigation'
|
||||||
|
|
||||||
import { AccountNavigation, AccountStatus } from 'components/Account'
|
|
||||||
import { Logo } from 'components/Icons'
|
import { Logo } from 'components/Icons'
|
||||||
import { menuTree, NavLink, SearchInput } from 'components/Navigation'
|
import { NavLink } from 'components/Navigation/NavLink'
|
||||||
import { Wallet } from 'components/Wallet'
|
import Wallet from 'components/Wallet/Wallet'
|
||||||
import { useCreditAccounts } from 'hooks/queries'
|
import { getRoute } from 'utils/route'
|
||||||
import { useAccountDetailsStore, useWalletStore } from 'stores'
|
|
||||||
|
|
||||||
export const DesktopNavigation = () => {
|
export const menuTree: { href: RouteSegment; label: string }[] = [
|
||||||
const address = useWalletStore((s) => s.address)
|
{ href: 'trade', label: 'Trade' },
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
{ href: 'earn', label: 'Earn' },
|
||||||
|
{ href: 'borrow', label: 'Borrow' },
|
||||||
|
{ href: 'portfolio', label: 'Portfolio' },
|
||||||
|
{ href: 'council', label: 'Council' },
|
||||||
|
]
|
||||||
|
|
||||||
const { data: creditAccountsList } = useCreditAccounts()
|
export default function DesktopNavigation() {
|
||||||
|
const pathname = usePathname() || ''
|
||||||
const isConnected = !!address
|
|
||||||
const hasCreditAccounts = creditAccountsList && creditAccountsList.length > 0
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative hidden bg-header lg:block'>
|
<div className='relative hidden bg-header lg:block'>
|
||||||
<div className='flex items-center justify-between border-b border-white/20 px-6 py-3'>
|
<div className='flex items-center justify-between border-b border-white/20 px-6 py-3'>
|
||||||
<div className='flex flex-grow items-center'>
|
<div className='flex flex-grow items-center'>
|
||||||
<Link href='/trade' passHref>
|
<Link href={getRoute(pathname, { page: 'trade' })}>
|
||||||
<span className='h-10 w-10'>
|
<span className='block h-10 w-10'>
|
||||||
<Logo />
|
<Logo />
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
<div className='flex gap-8 px-6'>
|
<div className='flex gap-8 px-6'>
|
||||||
{menuTree.map((item, index) => (
|
{menuTree.map((item, index) => (
|
||||||
<NavLink key={index} href={item.href}>
|
<NavLink key={index} href={getRoute(pathname, { page: item.href })}>
|
||||||
{item.label}
|
{item.label}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
))}
|
))}
|
||||||
@ -35,19 +38,6 @@ export const DesktopNavigation = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Wallet />
|
<Wallet />
|
||||||
</div>
|
</div>
|
||||||
{/* Sub navigation bar */}
|
|
||||||
<div className='flex items-center justify-between border-b border-white/20 pl-6 text-sm text-white/40'>
|
|
||||||
<div className='flex items-center'>
|
|
||||||
<SearchInput />
|
|
||||||
{isConnected && hasCreditAccounts && (
|
|
||||||
<AccountNavigation
|
|
||||||
selectedAccount={selectedAccount}
|
|
||||||
creditAccountsList={creditAccountsList}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{isConnected && <AccountStatus />}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { usePathname } from 'next/navigation'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
@ -9,19 +11,18 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const NavLink = ({ href, children }: Props) => {
|
export const NavLink = ({ href, children }: Props) => {
|
||||||
const router = useRouter()
|
const pathname = usePathname()
|
||||||
const isActive = router.pathname === href
|
const isActive = pathname === href
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={href} passHref>
|
<Link
|
||||||
<a
|
href={href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'text-lg-caps hover:text-white active:text-white',
|
'text-lg-caps hover:text-white active:text-white',
|
||||||
isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import { Search } from 'components/Icons'
|
|
||||||
export const SearchInput = () => (
|
|
||||||
<div className='relative mt-[1px] py-2 text-white'>
|
|
||||||
<span className='absolute top-1/2 left-0 flex h-6 w-8 -translate-y-1/2 items-center pl-2'>
|
|
||||||
<Search />
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
className='w-[280px] rounded-md border border-white/20 bg-black/30 py-2 pl-10 text-sm text-white placeholder:text-white/40 focus:border-white/60 focus:outline-none'
|
|
||||||
placeholder='Search'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
@ -1,6 +0,0 @@
|
|||||||
// @index(['./*.ts*'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { DesktopNavigation } from './DesktopNavigation'
|
|
||||||
export { menuTree } from './menuTree'
|
|
||||||
export { NavLink } from './NavLink'
|
|
||||||
export { SearchInput } from './SearchInput'
|
|
||||||
// @endindex
|
|
@ -1,7 +0,0 @@
|
|||||||
export const menuTree = [
|
|
||||||
{ href: '/trade', label: 'Trade' },
|
|
||||||
{ href: '/earn', label: 'Earn' },
|
|
||||||
{ href: '/borrow', label: 'Borrow' },
|
|
||||||
{ href: '/portfolio', label: 'Portfolio' },
|
|
||||||
{ href: '/council', label: 'Council' },
|
|
||||||
]
|
|
@ -1,7 +1,7 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import { Button } from 'components'
|
import { Button } from 'components/Button'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { Overlay } from './Overlay'
|
|
||||||
export { OverlayAction } from './OverlayAction'
|
|
||||||
// @endindex
|
|
@ -1,6 +1,7 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { FormattedNumber, Text } from 'components'
|
import { Text } from 'components/Text'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
title: string
|
||||||
|
@ -5,12 +5,18 @@ import React, { useMemo, useState } from 'react'
|
|||||||
import { NumericFormat } from 'react-number-format'
|
import { NumericFormat } from 'react-number-format'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
import { Button, CircularProgress, ContainerSecondary, Slider } from 'components'
|
import { Button } from 'components/Button'
|
||||||
import { useRepayFunds } from 'hooks/mutations'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { useAllBalances, useCreditAccountPositions, useTokenPrices } from 'hooks/queries'
|
import { ContainerSecondary } from 'components/ContainerSecondary'
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
import { Slider } from 'components/Slider'
|
||||||
|
import { useRepayFunds } from 'hooks/mutations/useRepayFunds'
|
||||||
|
import { useAllBalances } from 'hooks/queries/useAllBalances'
|
||||||
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
import { formatCurrency } from 'utils/formatters'
|
import { formatCurrency } from 'utils/formatters'
|
||||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
// 0.001% buffer / slippage to avoid repay action from not fully repaying the debt amount
|
// 0.001% buffer / slippage to avoid repay action from not fully repaying the debt amount
|
||||||
const REPAY_BUFFER = 1.00001
|
const REPAY_BUFFER = 1.00001
|
||||||
@ -24,11 +30,11 @@ type Props = {
|
|||||||
export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
||||||
const [amount, setAmount] = useState(0)
|
const [amount, setAmount] = useState(0)
|
||||||
|
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const tokenSymbol = getTokenSymbol(tokenDenom, whitelistedAssets)
|
const tokenSymbol = getTokenSymbol(tokenDenom, marketAssets)
|
||||||
|
|
||||||
const maxRepayAmount = useMemo(() => {
|
const maxRepayAmount = useMemo(() => {
|
||||||
const tokenDebtAmount =
|
const tokenDebtAmount =
|
||||||
@ -37,13 +43,13 @@ export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
return BigNumber(tokenDebtAmount)
|
return BigNumber(tokenDebtAmount)
|
||||||
.times(REPAY_BUFFER)
|
.times(REPAY_BUFFER)
|
||||||
.decimalPlaces(0)
|
.decimalPlaces(0)
|
||||||
.div(10 ** getTokenDecimals(tokenDenom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(tokenDenom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
}, [positionsData, tokenDenom, whitelistedAssets])
|
}, [positionsData, tokenDenom, marketAssets])
|
||||||
|
|
||||||
const { mutate, isLoading } = useRepayFunds(
|
const { mutate, isLoading } = useRepayFunds(
|
||||||
BigNumber(amount)
|
BigNumber(amount)
|
||||||
.times(10 ** getTokenDecimals(tokenDenom, whitelistedAssets))
|
.times(10 ** getTokenDecimals(tokenDenom, marketAssets))
|
||||||
.toNumber(),
|
.toNumber(),
|
||||||
tokenDenom,
|
tokenDenom,
|
||||||
{
|
{
|
||||||
@ -63,9 +69,9 @@ export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
|
|
||||||
const walletAmount = useMemo(() => {
|
const walletAmount = useMemo(() => {
|
||||||
return BigNumber(balancesData?.find((balance) => balance.denom === tokenDenom)?.amount ?? 0)
|
return BigNumber(balancesData?.find((balance) => balance.denom === tokenDenom)?.amount ?? 0)
|
||||||
.div(10 ** getTokenDecimals(tokenDenom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(tokenDenom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
}, [balancesData, tokenDenom, whitelistedAssets])
|
}, [balancesData, tokenDenom, marketAssets])
|
||||||
|
|
||||||
const tokenPrice = tokenPrices?.[tokenDenom] ?? 0
|
const tokenPrice = tokenPrices?.[tokenDenom] ?? 0
|
||||||
|
|
||||||
@ -143,7 +149,7 @@ export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
allowNegative={false}
|
allowNegative={false}
|
||||||
onValueChange={(v) => handleValueChange(v.floatValue || 0)}
|
onValueChange={(v) => handleValueChange(v.floatValue || 0)}
|
||||||
suffix={` ${tokenSymbol}`}
|
suffix={` ${tokenSymbol}`}
|
||||||
decimalScale={getTokenDecimals(tokenDenom, whitelistedAssets)}
|
decimalScale={getTokenDecimals(tokenDenom, marketAssets)}
|
||||||
/>
|
/>
|
||||||
<div className='flex justify-between text-xs tracking-widest'>
|
<div className='flex justify-between text-xs tracking-widest'>
|
||||||
<div>
|
<div>
|
||||||
@ -158,7 +164,7 @@ export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
|
|||||||
value={percentageValue}
|
value={percentageValue}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const decimal = value[0] / 100
|
const decimal = value[0] / 100
|
||||||
const tokenDecimals = getTokenDecimals(tokenDenom, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(tokenDenom, marketAssets)
|
||||||
// limit decimal precision based on token contract decimals
|
// limit decimal precision based on token contract decimals
|
||||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||||
|
|
||||||
|
18
src/components/Toaster.tsx
Normal file
18
src/components/Toaster.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
'use client'
|
||||||
|
import { Slide, ToastContainer } from 'react-toastify'
|
||||||
|
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
|
export default function Toaster() {
|
||||||
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToastContainer
|
||||||
|
autoClose={3000}
|
||||||
|
closeButton={false}
|
||||||
|
position='bottom-right'
|
||||||
|
newestOnTop
|
||||||
|
transition={enableAnimations ? Slide : undefined}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -3,7 +3,7 @@ import classNames from 'classnames'
|
|||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import { Questionmark } from 'components/Icons'
|
import { Questionmark } from 'components/Icons'
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children?: ReactNode | string
|
children?: ReactNode | string
|
||||||
@ -22,7 +22,7 @@ export const Tooltip = ({
|
|||||||
inderactive = false,
|
inderactive = false,
|
||||||
underline = false,
|
underline = false,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tippy
|
<Tippy
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import { Switch } from '@headlessui/react'
|
import { Switch } from '@headlessui/react'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import React, { useEffect, useMemo, useState } from 'react'
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
import { Button, CircularProgress, Slider } from 'components'
|
|
||||||
import { ArrowsUpDown } from 'components/Icons'
|
import { ArrowsUpDown } from 'components/Icons'
|
||||||
import { useCalculateMaxTradeAmount } from 'hooks/data'
|
|
||||||
import { useTradeAsset } from 'hooks/mutations'
|
|
||||||
import {
|
|
||||||
useAllBalances,
|
|
||||||
useAllowedCoins,
|
|
||||||
useCreditAccountPositions,
|
|
||||||
useMarkets,
|
|
||||||
useTokenPrices,
|
|
||||||
} from 'hooks/queries'
|
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
|
||||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||||
|
import { Slider } from 'components/Slider'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
|
import { useCalculateMaxTradeAmount } from 'hooks/data/useCalculateMaxTradeAmount'
|
||||||
|
import { useTradeAsset } from 'hooks/mutations/useTradeAsset'
|
||||||
|
import { useAllBalances } from 'hooks/queries/useAllBalances'
|
||||||
|
import { useAllowedCoins } from 'hooks/queries/useAllowedCoins'
|
||||||
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
enum FundingMode {
|
enum FundingMode {
|
||||||
Account = 'Account',
|
Account = 'Account',
|
||||||
@ -23,7 +26,7 @@ enum FundingMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TradeActionModule = () => {
|
export const TradeActionModule = () => {
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const [selectedTokenIn, setSelectedTokenIn] = useState('')
|
const [selectedTokenIn, setSelectedTokenIn] = useState('')
|
||||||
const [selectedTokenOut, setSelectedTokenOut] = useState('')
|
const [selectedTokenOut, setSelectedTokenOut] = useState('')
|
||||||
@ -34,7 +37,7 @@ export const TradeActionModule = () => {
|
|||||||
|
|
||||||
const [isMarginEnabled, setIsMarginEnabled] = React.useState(false)
|
const [isMarginEnabled, setIsMarginEnabled] = React.useState(false)
|
||||||
|
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
|
|
||||||
const { data: allowedCoinsData } = useAllowedCoins()
|
const { data: allowedCoinsData } = useAllowedCoins()
|
||||||
const { data: balancesData } = useAllBalances()
|
const { data: balancesData } = useAllBalances()
|
||||||
@ -96,8 +99,8 @@ export const TradeActionModule = () => {
|
|||||||
toast.success(
|
toast.success(
|
||||||
`${amountIn} ${getTokenSymbol(
|
`${amountIn} ${getTokenSymbol(
|
||||||
selectedTokenIn,
|
selectedTokenIn,
|
||||||
whitelistedAssets,
|
marketAssets,
|
||||||
)} swapped for ${amountOut} ${getTokenSymbol(selectedTokenOut, whitelistedAssets)}`,
|
)} swapped for ${amountOut} ${getTokenSymbol(selectedTokenOut, marketAssets)}`,
|
||||||
)
|
)
|
||||||
resetAmounts()
|
resetAmounts()
|
||||||
},
|
},
|
||||||
@ -192,20 +195,20 @@ export const TradeActionModule = () => {
|
|||||||
>
|
>
|
||||||
{allowedCoinsData?.map((entry) => (
|
{allowedCoinsData?.map((entry) => (
|
||||||
<option key={entry} value={entry}>
|
<option key={entry} value={entry}>
|
||||||
{getTokenSymbol(entry, whitelistedAssets)}
|
{getTokenSymbol(entry, marketAssets)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<input
|
<input
|
||||||
type='number'
|
type='number'
|
||||||
className='h-8 flex-1 px-2 text-black outline-0'
|
className='h-8 flex-1 px-2 text-black outline-0'
|
||||||
value={amountIn / 10 ** getTokenDecimals(selectedTokenIn, whitelistedAssets)}
|
value={amountIn / 10 ** getTokenDecimals(selectedTokenIn, marketAssets)}
|
||||||
min='0'
|
min='0'
|
||||||
placeholder='0.00'
|
placeholder='0.00'
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const valueAsNumber = e.target.valueAsNumber
|
const valueAsNumber = e.target.valueAsNumber
|
||||||
const valueWithDecimals =
|
const valueWithDecimals =
|
||||||
valueAsNumber * 10 ** getTokenDecimals(selectedTokenIn, whitelistedAssets)
|
valueAsNumber * 10 ** getTokenDecimals(selectedTokenIn, marketAssets)
|
||||||
|
|
||||||
handleAmountChange(valueWithDecimals, 'in')
|
handleAmountChange(valueWithDecimals, 'in')
|
||||||
}}
|
}}
|
||||||
@ -232,20 +235,20 @@ export const TradeActionModule = () => {
|
|||||||
>
|
>
|
||||||
{allowedCoinsData?.map((entry) => (
|
{allowedCoinsData?.map((entry) => (
|
||||||
<option key={entry} value={entry}>
|
<option key={entry} value={entry}>
|
||||||
{getTokenSymbol(entry, whitelistedAssets)}
|
{getTokenSymbol(entry, marketAssets)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<input
|
<input
|
||||||
type='number'
|
type='number'
|
||||||
className='h-8 flex-1 px-2 text-black outline-0'
|
className='h-8 flex-1 px-2 text-black outline-0'
|
||||||
value={amountOut / 10 ** getTokenDecimals(selectedTokenOut, whitelistedAssets)}
|
value={amountOut / 10 ** getTokenDecimals(selectedTokenOut, marketAssets)}
|
||||||
min='0'
|
min='0'
|
||||||
placeholder='0.00'
|
placeholder='0.00'
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const valueAsNumber = e.target.valueAsNumber
|
const valueAsNumber = e.target.valueAsNumber
|
||||||
const valueWithDecimals =
|
const valueWithDecimals =
|
||||||
valueAsNumber * 10 ** getTokenDecimals(selectedTokenOut, whitelistedAssets)
|
valueAsNumber * 10 ** getTokenDecimals(selectedTokenOut, marketAssets)
|
||||||
|
|
||||||
handleAmountChange(valueWithDecimals, 'out')
|
handleAmountChange(valueWithDecimals, 'out')
|
||||||
}}
|
}}
|
||||||
@ -255,29 +258,29 @@ export const TradeActionModule = () => {
|
|||||||
<div className='mb-1'>
|
<div className='mb-1'>
|
||||||
In Wallet:{' '}
|
In Wallet:{' '}
|
||||||
{BigNumber(walletAmount)
|
{BigNumber(walletAmount)
|
||||||
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, whitelistedAssets))
|
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
.toLocaleString(undefined, {
|
.toLocaleString(undefined, {
|
||||||
maximumFractionDigits: getTokenDecimals(selectedTokenIn, whitelistedAssets),
|
maximumFractionDigits: getTokenDecimals(selectedTokenIn, marketAssets),
|
||||||
})}{' '}
|
})}{' '}
|
||||||
<span>{getTokenSymbol(selectedTokenIn, whitelistedAssets)}</span>
|
<span>{getTokenSymbol(selectedTokenIn, marketAssets)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
In Account:{' '}
|
In Account:{' '}
|
||||||
{BigNumber(accountAmount)
|
{BigNumber(accountAmount)
|
||||||
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, whitelistedAssets))
|
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
.toLocaleString(undefined, {
|
.toLocaleString(undefined, {
|
||||||
maximumFractionDigits: getTokenDecimals(selectedTokenIn, whitelistedAssets),
|
maximumFractionDigits: getTokenDecimals(selectedTokenIn, marketAssets),
|
||||||
})}{' '}
|
})}{' '}
|
||||||
<span>{getTokenSymbol(selectedTokenIn, whitelistedAssets)}</span>
|
<span>{getTokenSymbol(selectedTokenIn, marketAssets)}</span>
|
||||||
</div>
|
</div>
|
||||||
<Slider
|
<Slider
|
||||||
className='mb-6'
|
className='mb-6'
|
||||||
value={percentageValue}
|
value={percentageValue}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const decimal = value[0] / 100
|
const decimal = value[0] / 100
|
||||||
const tokenDecimals = getTokenDecimals(selectedTokenIn, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(selectedTokenIn, marketAssets)
|
||||||
// limit decimal precision based on token contract decimals
|
// limit decimal precision based on token contract decimals
|
||||||
const newAmount = Number((decimal * maxAmount).toFixed(0))
|
const newAmount = Number((decimal * maxAmount).toFixed(0))
|
||||||
|
|
||||||
@ -313,10 +316,10 @@ export const TradeActionModule = () => {
|
|||||||
<p>
|
<p>
|
||||||
{isMarginEnabled
|
{isMarginEnabled
|
||||||
? BigNumber(borrowAmount)
|
? BigNumber(borrowAmount)
|
||||||
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, whitelistedAssets))
|
.dividedBy(10 ** getTokenDecimals(selectedTokenIn, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
.toLocaleString(undefined, {
|
.toLocaleString(undefined, {
|
||||||
maximumFractionDigits: getTokenDecimals(selectedTokenIn, whitelistedAssets),
|
maximumFractionDigits: getTokenDecimals(selectedTokenIn, marketAssets),
|
||||||
})
|
})
|
||||||
: '-'}
|
: '-'}
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { TradeActionModule } from './TradeActionModule'
|
|
||||||
// @endindex
|
|
@ -1,7 +1,7 @@
|
|||||||
import { useWalletManager, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
import { useWalletManager, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
import { CircularProgress } from 'components'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { Wallet } from 'components/Icons'
|
import { Wallet } from 'components/Icons'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -10,17 +10,17 @@ interface Props {
|
|||||||
status?: WalletConnectionStatus
|
status?: WalletConnectionStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConnectButton = ({ textOverride, disabled = false, status }: Props) => {
|
export default function ConnectButton(props: Props) {
|
||||||
const { connect } = useWalletManager()
|
const { connect } = useWalletManager()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<button
|
<button
|
||||||
disabled={disabled}
|
disabled={props.disabled}
|
||||||
className='flex h-[31px] min-w-[186px] flex-1 flex-nowrap content-center items-center justify-center rounded-2xl border border-white/60 bg-black/10 px-4 pt-0.5 text-white text-2xs-caps hover:border-white hover:bg-white/60'
|
className='flex h-[31px] min-w-[186px] flex-1 flex-nowrap content-center items-center justify-center rounded-2xl border border-white/60 bg-black/10 px-4 pt-0.5 text-white text-2xs-caps hover:border-white hover:bg-white/60'
|
||||||
onClick={connect}
|
onClick={connect}
|
||||||
>
|
>
|
||||||
{status === WalletConnectionStatus.Connecting ? (
|
{props.status === WalletConnectionStatus.Connecting ? (
|
||||||
<span className='flex justify-center'>
|
<span className='flex justify-center'>
|
||||||
<CircularProgress size={16} />
|
<CircularProgress size={16} />
|
||||||
</span>
|
</span>
|
||||||
@ -29,7 +29,7 @@ export const ConnectButton = ({ textOverride, disabled = false, status }: Props)
|
|||||||
<span className='flex h-4 w-4 items-center justify-center'>
|
<span className='flex h-4 w-4 items-center justify-center'>
|
||||||
<Wallet />
|
<Wallet />
|
||||||
</span>
|
</span>
|
||||||
<span className='ml-2 mt-0.5'>{textOverride || 'Connect Wallet'}</span>
|
<span className='ml-2 mt-0.5'>{props.textOverride || 'Connect Wallet'}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,61 +1,69 @@
|
|||||||
import { ChainInfoID, SimpleChainInfoList, useWalletManager } from '@marsprotocol/wallet-connector'
|
import { Coin } from '@cosmjs/stargate'
|
||||||
|
import {
|
||||||
|
ChainInfoID,
|
||||||
|
SimpleChainInfoList,
|
||||||
|
useWallet,
|
||||||
|
useWalletManager,
|
||||||
|
} from '@marsprotocol/wallet-connector'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import useClipboard from 'react-use-clipboard'
|
import useClipboard from 'react-use-clipboard'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
|
||||||
import { Button, CircularProgress, FormattedNumber, Text } from 'components'
|
import { Button } from 'components/Button'
|
||||||
import { Check, Copy, ExternalLink, Osmo, Wallet } from 'components/Icons'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { Overlay } from 'components/Overlay'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { useAllBalances } from 'hooks/queries'
|
import { Check, Copy, ExternalLink, Osmo } from 'components/Icons'
|
||||||
import { useNetworkConfigStore, useWalletStore } from 'stores'
|
import { Overlay } from 'components/Overlay/Overlay'
|
||||||
|
import { Text } from 'components/Text'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getBaseAsset } from 'utils/assets'
|
||||||
import { formatValue, truncate } from 'utils/formatters'
|
import { formatValue, truncate } from 'utils/formatters'
|
||||||
|
import { getWalletBalances } from 'utils/api'
|
||||||
|
|
||||||
export const ConnectedButton = () => {
|
export default function ConnectedButton() {
|
||||||
// ---------------
|
// ---------------
|
||||||
// EXTERNAL HOOKS
|
// EXTERNAL HOOKS
|
||||||
// ---------------
|
// ---------------
|
||||||
const { disconnect } = useWalletManager()
|
const { disconnect } = useWallet()
|
||||||
const address = useWalletStore((s) => s.address)
|
const { disconnect: terminate } = useWalletManager()
|
||||||
const chainInfo = useWalletStore((s) => s.chainInfo)
|
const address = useStore((s) => s.client?.recentWallet.account?.address)
|
||||||
const name = useWalletStore((s) => s.name)
|
const network = useStore((s) => s.client?.recentWallet.network)
|
||||||
const baseAsset = useNetworkConfigStore((s) => s.assets.base)
|
const name = useStore((s) => s.name)
|
||||||
|
const baseAsset = getBaseAsset()
|
||||||
|
|
||||||
// ---------------
|
const { data, isLoading } = useSWR(address, getWalletBalances)
|
||||||
// LOCAL HOOKS
|
|
||||||
// ---------------
|
|
||||||
const { data } = useAllBalances()
|
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// LOCAL STATE
|
// LOCAL STATE
|
||||||
// ---------------
|
// ---------------
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
const [showDetails, setShowDetails] = useState(false)
|
const [showDetails, setShowDetails] = useState(false)
|
||||||
const [walletAmount, setWalletAmount] = useState(0)
|
const [walletAmount, setWalletAmount] = useState(0)
|
||||||
const [isCopied, setCopied] = useClipboard(address || '', {
|
const [isCopied, setCopied] = useClipboard(address || '', {
|
||||||
successDuration: 1000 * 5,
|
successDuration: 1000 * 5,
|
||||||
})
|
})
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// VARIABLES
|
// VARIABLES
|
||||||
// ---------------
|
// ---------------
|
||||||
const explorerName =
|
const explorerName = network && SimpleChainInfoList[network.chainId as ChainInfoID].explorerName
|
||||||
chainInfo && SimpleChainInfoList[chainInfo.chainId as ChainInfoID].explorerName
|
|
||||||
|
|
||||||
const viewOnFinder = useCallback(() => {
|
const viewOnFinder = useCallback(() => {
|
||||||
const explorerUrl = chainInfo && SimpleChainInfoList[chainInfo.chainId as ChainInfoID].explorer
|
const explorerUrl = network && SimpleChainInfoList[network.chainId as ChainInfoID].explorer
|
||||||
|
|
||||||
window.open(`${explorerUrl}account/${address}`, '_blank')
|
window.open(`${explorerUrl}/account/${address}`, '_blank')
|
||||||
}, [chainInfo, address])
|
}, [network, address])
|
||||||
|
|
||||||
useEffect(() => {
|
const disconnectWallet = () => {
|
||||||
const loading = !(address && name && chainInfo)
|
disconnect()
|
||||||
setIsLoading(loading)
|
terminate()
|
||||||
}, [address, name, chainInfo])
|
useStore.setState({ client: undefined })
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!data || data.length === 0) return
|
||||||
setWalletAmount(
|
setWalletAmount(
|
||||||
BigNumber(data?.find((balance) => balance.denom === baseAsset.denom)?.amount ?? 0)
|
BigNumber(data?.find((coin: Coin) => coin.denom === baseAsset.denom)?.amount ?? 0)
|
||||||
.div(10 ** baseAsset.decimals)
|
.div(10 ** baseAsset.decimals)
|
||||||
.toNumber(),
|
.toNumber(),
|
||||||
)
|
)
|
||||||
@ -63,13 +71,13 @@ export const ConnectedButton = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'relative'}>
|
<div className={'relative'}>
|
||||||
{chainInfo?.chainId !== ChainInfoID.Osmosis1 && (
|
{network?.chainId !== ChainInfoID.Osmosis1 && (
|
||||||
<Text
|
<Text
|
||||||
className='absolute -right-2 -top-2.5 rounded-lg bg-secondary-highlight p-0.5 px-2'
|
className='absolute -right-2 -top-2.5 rounded-lg bg-secondary-highlight p-0.5 px-2'
|
||||||
size='3xs'
|
size='3xs'
|
||||||
uppercase
|
uppercase
|
||||||
>
|
>
|
||||||
{chainInfo?.chainId}
|
{network?.chainId}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -84,12 +92,7 @@ export const ConnectedButton = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className='flex h-4 w-4 items-center justify-center'>
|
<span className='flex h-4 w-4 items-center justify-center'>
|
||||||
{chainInfo?.chainId === ChainInfoID.Osmosis1 ||
|
|
||||||
chainInfo?.chainId === ChainInfoID.OsmosisTestnet ? (
|
|
||||||
<Osmo />
|
<Osmo />
|
||||||
) : (
|
|
||||||
<Wallet />
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span className='ml-2'>{name ? name : truncate(address, [2, 4])}</span>
|
<span className='ml-2'>{name ? name : truncate(address, [2, 4])}</span>
|
||||||
<div
|
<div
|
||||||
@ -98,10 +101,10 @@ export const ConnectedButton = () => {
|
|||||||
'before:content-[" "] before:absolute before:top-1.5 before:bottom-1.5 before:left-0 before:h-[calc(100%-12px)] before:border-l before:border-white',
|
'before:content-[" "] before:absolute before:top-1.5 before:bottom-1.5 before:left-0 before:h-[calc(100%-12px)] before:border-l before:border-white',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!isLoading ? (
|
{isLoading ? (
|
||||||
`${formatValue(walletAmount, 2, 2, true, false, ` ${baseAsset.symbol}`)}`
|
|
||||||
) : (
|
|
||||||
<CircularProgress size={12} />
|
<CircularProgress size={12} />
|
||||||
|
) : (
|
||||||
|
`${formatValue(walletAmount, 2, 2, true, false, ` ${baseAsset.symbol}`)}`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
@ -121,7 +124,7 @@ export const ConnectedButton = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex h-[31px] w-[116px] justify-end'>
|
<div className='flex h-[31px] w-[116px] justify-end'>
|
||||||
<Button color='secondary' onClick={disconnect} text='Disconnect' />
|
<Button color='secondary' onClick={disconnectWallet} text='Disconnect' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex w-full flex-wrap'>
|
<div className='flex w-full flex-wrap'>
|
||||||
|
@ -1,18 +1,65 @@
|
|||||||
import { useWallet, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
'use client'
|
||||||
|
|
||||||
|
import {
|
||||||
|
getClient,
|
||||||
|
useWallet,
|
||||||
|
useWalletManager,
|
||||||
|
WalletConnectionStatus,
|
||||||
|
} from '@marsprotocol/wallet-connector'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
import { ConnectButton, ConnectedButton } from 'components/Wallet'
|
import ConnectButton from 'components/Wallet/ConnectButton'
|
||||||
|
import ConnectedButton from 'components/Wallet/ConnectedButton'
|
||||||
|
import useParams from 'hooks/useParams'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
export const Wallet = () => {
|
export default function Wallet() {
|
||||||
const { status } = useWallet()
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const { status } = useWalletManager()
|
||||||
const [isConnected, setIsConnected] = useState(false)
|
const [isConnected, setIsConnected] = useState(false)
|
||||||
|
const { recentWallet, simulate, sign, broadcast } = useWallet()
|
||||||
|
const client = useStore((s) => s.client)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const connectedStatus = status === WalletConnectionStatus.Connected
|
const connectedStatus = status === WalletConnectionStatus.Connected
|
||||||
if (connectedStatus !== isConnected) {
|
if (connectedStatus === isConnected) return
|
||||||
setIsConnected(connectedStatus)
|
setIsConnected(connectedStatus)
|
||||||
}
|
|
||||||
}, [status, isConnected])
|
}, [status, isConnected])
|
||||||
|
|
||||||
return !isConnected ? <ConnectButton status={status} /> : <ConnectedButton />
|
useEffect(() => {
|
||||||
|
if (!isConnected && !params.wallet) {
|
||||||
|
router.push('/')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const address = client?.recentWallet.account.address
|
||||||
|
if (!address || address === params.wallet) return
|
||||||
|
|
||||||
|
router.push(`/wallets/${client.recentWallet.account.address}`)
|
||||||
|
}, [client, params, isConnected])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!recentWallet) return
|
||||||
|
if (!client) {
|
||||||
|
const getCosmWasmClient = async () => {
|
||||||
|
const cosmClient = await getClient(recentWallet.network.rpc)
|
||||||
|
|
||||||
|
const client = {
|
||||||
|
broadcast,
|
||||||
|
cosmWasmClient: cosmClient,
|
||||||
|
recentWallet,
|
||||||
|
sign,
|
||||||
|
simulate,
|
||||||
|
}
|
||||||
|
useStore.setState({ client })
|
||||||
|
}
|
||||||
|
|
||||||
|
getCosmWasmClient()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}, [simulate, sign, recentWallet, broadcast])
|
||||||
|
return isConnected ? <ConnectedButton /> : <ConnectButton status={status} />
|
||||||
}
|
}
|
||||||
|
@ -1,89 +1,40 @@
|
|||||||
import { ChainInfoID, WalletManagerProvider, WalletType } from '@marsprotocol/wallet-connector'
|
'use client'
|
||||||
import classNames from 'classnames'
|
|
||||||
|
import { WalletManagerProvider } from '@marsprotocol/wallet-connector'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
|
|
||||||
import { CircularProgress } from 'components'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { buttonColorClasses, buttonSizeClasses, buttonVariantClasses } from 'components/Button'
|
import { CHAIN_ID, ENV_MISSING_MESSAGE, URL_REST, URL_RPC, WALLETS } from 'constants/env'
|
||||||
import { Close } from 'components/Icons'
|
|
||||||
// TODO: get networkConfig source dynamically
|
|
||||||
import { networkConfig } from 'config/osmo-test-4'
|
|
||||||
import KeplrImage from 'images/wallets/keplr-wallet-extension.png'
|
|
||||||
import WalletConnectImage from 'images/wallets/walletconnect-keplr.png'
|
|
||||||
import { useSettingsStore } from 'stores'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WalletConnectProvider: FC<Props> = ({ children }) => {
|
export const WalletConnectProvider: FC<Props> = ({ children }) => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
if (!CHAIN_ID || !URL_REST || !URL_RPC || !WALLETS) {
|
||||||
|
console.error(ENV_MISSING_MESSAGE)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const chainInfoOverrides = {
|
||||||
|
rpc: URL_RPC,
|
||||||
|
rest: URL_REST,
|
||||||
|
chainID: CHAIN_ID,
|
||||||
|
}
|
||||||
|
const enabledWallets: string[] = WALLETS
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WalletManagerProvider
|
<WalletManagerProvider
|
||||||
chainInfoOverrides={{
|
chainInfoOverrides={chainInfoOverrides}
|
||||||
[ChainInfoID.OsmosisTestnet]: {
|
// closeIcon={<SVG.Close />}
|
||||||
rpc: networkConfig.rpcUrl,
|
defaultChainId={chainInfoOverrides.chainID}
|
||||||
rest: networkConfig.restUrl,
|
enabledWallets={enabledWallets}
|
||||||
},
|
persistent
|
||||||
}}
|
|
||||||
classNames={{
|
|
||||||
modalContent:
|
|
||||||
'flex h-fit w-[500px] max-w-full overflow-hidden rounded-xl border-[7px] border-accent-highlight p-4 gradient-card flex-col outline-none relative',
|
|
||||||
modalOverlay:
|
|
||||||
'bg-black/60 fixed top-0 left-0 w-screen h-screen z-50 flex items-center justify-center cursor-pointer backdrop-blur',
|
|
||||||
modalHeader: 'text-2xl-caps text-center text-white mb-4',
|
|
||||||
walletList: 'flex flex-col gap-4 py-2',
|
|
||||||
wallet:
|
|
||||||
'bg-transparent rounded-base p-2 shadow-none flex items-center appearance-none border-none w-full no-underline cursor-pointer hover:bg-white/10 disabled:pointer-events-none disabled:opacity-50',
|
|
||||||
walletImage: 'h-15 w-15',
|
|
||||||
walletInfo: 'flex flex-col ml-5',
|
|
||||||
walletName: 'text-lg-caps text-white',
|
|
||||||
walletDescription: 'mt-1 text-white/40 text-base text-left',
|
|
||||||
textContent: 'block w-full text-center text-base text-white',
|
|
||||||
}}
|
|
||||||
closeIcon={
|
|
||||||
<span className='flex w-8 text-white/70 hover:text-white'>
|
|
||||||
<Close />
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
defaultChainId={ChainInfoID.OsmosisTestnet}
|
|
||||||
enabledWalletTypes={[WalletType.Keplr, WalletType.WalletConnectKeplr]}
|
|
||||||
enablingMeta={{
|
|
||||||
text: 'If nothing shows up in your wallet try to connect again, by clicking on the button below. Refresh the page if the problem persists.',
|
|
||||||
textClassName: 'block w-full text-center text-base text-white',
|
|
||||||
buttonText: 'Retry the Connection',
|
|
||||||
buttonClassName: classNames(
|
|
||||||
'cursor-pointer appearance-none break-normal rounded-3xl outline-none',
|
|
||||||
enableAnimations && 'transition-colors',
|
|
||||||
buttonColorClasses.primary,
|
|
||||||
buttonSizeClasses.small,
|
|
||||||
buttonVariantClasses.solid,
|
|
||||||
),
|
|
||||||
contentClassName: 'flex flex-wrap w-full justify-center',
|
|
||||||
}}
|
|
||||||
enablingStringOverride='connecting to wallet'
|
|
||||||
localStorageKey='walletConnection'
|
|
||||||
renderLoader={() => (
|
renderLoader={() => (
|
||||||
<div className='my-4 flex w-full justify-center'>
|
<div>
|
||||||
<CircularProgress size={30} />
|
<CircularProgress size={30} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
walletConnectClientMeta={{
|
|
||||||
name: 'Mars Protocol',
|
|
||||||
description: 'Mars V2 Description',
|
|
||||||
url: 'https://marsprotocol.io',
|
|
||||||
icons: ['https://marsprotocol.io/favicon.svg'],
|
|
||||||
}}
|
|
||||||
walletMetaOverride={{
|
|
||||||
[WalletType.Keplr]: {
|
|
||||||
description: 'Keplr browser extension',
|
|
||||||
imageUrl: KeplrImage.src,
|
|
||||||
},
|
|
||||||
[WalletType.WalletConnectKeplr]: {
|
|
||||||
name: 'Wallet Connect',
|
|
||||||
description: 'Keplr mobile WalletConnect',
|
|
||||||
imageUrl: WalletConnectImage.src,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</WalletManagerProvider>
|
</WalletManagerProvider>
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { ConnectButton } from './ConnectButton'
|
|
||||||
export { ConnectedButton } from './ConnectedButton'
|
|
||||||
export { Wallet } from './Wallet'
|
|
||||||
export { WalletConnectProvider } from './WalletConnectProvider'
|
|
||||||
// @endindex
|
|
@ -1,17 +1,19 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useMemo, useRef, useState } from 'react'
|
import { useMemo, useRef, useState } from 'react'
|
||||||
|
|
||||||
import { BorrowModal, Card, RepayModal, Text } from 'components'
|
import { BorrowTable } from 'components/Borrow/BorrowTable'
|
||||||
import { BorrowTable } from 'components/Borrow'
|
import { BorrowModal } from 'components/BorrowModal'
|
||||||
import {
|
import { Card } from 'components/Card'
|
||||||
useAllowedCoins,
|
import { RepayModal } from 'components/RepayModal'
|
||||||
useCreditAccountPositions,
|
import { useAllowedCoins } from 'hooks/queries/useAllowedCoins'
|
||||||
useMarkets,
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
useRedbankBalances,
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
useTokenPrices,
|
import { useRedbankBalances } from 'hooks/queries/useRedbankBalances'
|
||||||
} from 'hooks/queries'
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
import { Text } from 'components/Text'
|
||||||
import { getTokenDecimals, getTokenInfo } from 'utils/tokens'
|
import { getTokenDecimals, getTokenInfo } from 'utils/tokens'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
type ModalState = {
|
type ModalState = {
|
||||||
show: 'borrow' | 'repay' | false
|
show: 'borrow' | 'repay' | false
|
||||||
@ -21,14 +23,14 @@ type ModalState = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Borrow = () => {
|
const Borrow = () => {
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const [modalState, setModalState] = useState<ModalState>({
|
const [modalState, setModalState] = useState<ModalState>({
|
||||||
show: false,
|
show: false,
|
||||||
data: { tokenDenom: '' },
|
data: { tokenDenom: '' },
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
|
|
||||||
const { data: allowedCoinsData } = useAllowedCoins()
|
const { data: allowedCoinsData } = useAllowedCoins()
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
@ -55,17 +57,17 @@ const Borrow = () => {
|
|||||||
allowedCoinsData
|
allowedCoinsData
|
||||||
?.filter((denom) => borrowedAssetsMap.has(denom))
|
?.filter((denom) => borrowedAssetsMap.has(denom))
|
||||||
.map((denom) => {
|
.map((denom) => {
|
||||||
const { symbol, name, logo } = getTokenInfo(denom, whitelistedAssets)
|
const { symbol, name, logo } = getTokenInfo(denom, marketAssets)
|
||||||
const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0
|
const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0
|
||||||
const marketLiquidity = BigNumber(
|
const marketLiquidity = BigNumber(
|
||||||
redbankBalances?.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase())
|
redbankBalances?.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase())
|
||||||
?.amount || 0,
|
?.amount || 0,
|
||||||
)
|
)
|
||||||
.div(10 ** getTokenDecimals(denom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(denom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
|
|
||||||
const borrowAmount = BigNumber(borrowedAssetsMap.get(denom) as string)
|
const borrowAmount = BigNumber(borrowedAssetsMap.get(denom) as string)
|
||||||
.div(10 ** getTokenDecimals(denom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(denom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
const borrowValue = borrowAmount * (tokenPrices?.[denom] ?? 0)
|
const borrowValue = borrowAmount * (tokenPrices?.[denom] ?? 0)
|
||||||
|
|
||||||
@ -88,13 +90,13 @@ const Borrow = () => {
|
|||||||
allowedCoinsData
|
allowedCoinsData
|
||||||
?.filter((denom) => !borrowedAssetsMap.has(denom))
|
?.filter((denom) => !borrowedAssetsMap.has(denom))
|
||||||
.map((denom) => {
|
.map((denom) => {
|
||||||
const { symbol, name, logo } = getTokenInfo(denom, whitelistedAssets)
|
const { symbol, name, logo } = getTokenInfo(denom, marketAssets)
|
||||||
const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0
|
const borrowRate = Number(marketsData?.[denom].borrow_rate) || 0
|
||||||
const marketLiquidity = BigNumber(
|
const marketLiquidity = BigNumber(
|
||||||
redbankBalances?.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase())
|
redbankBalances?.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase())
|
||||||
?.amount || 0,
|
?.amount || 0,
|
||||||
)
|
)
|
||||||
.div(10 ** getTokenDecimals(denom, whitelistedAssets))
|
.div(10 ** getTokenDecimals(denom, marketAssets))
|
||||||
.toNumber()
|
.toNumber()
|
||||||
|
|
||||||
const rowData = {
|
const rowData = {
|
||||||
@ -110,14 +112,7 @@ const Borrow = () => {
|
|||||||
return rowData
|
return rowData
|
||||||
}) ?? [],
|
}) ?? [],
|
||||||
}
|
}
|
||||||
}, [
|
}, [allowedCoinsData, borrowedAssetsMap, marketsData, redbankBalances, tokenPrices, marketAssets])
|
||||||
allowedCoinsData,
|
|
||||||
borrowedAssetsMap,
|
|
||||||
marketsData,
|
|
||||||
redbankBalances,
|
|
||||||
tokenPrices,
|
|
||||||
whitelistedAssets,
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleBorrowClick = (denom: string) => {
|
const handleBorrowClick = (denom: string) => {
|
||||||
setModalState({ show: 'borrow', data: { tokenDenom: denom } })
|
setModalState({ show: 'borrow', data: { tokenDenom: denom } })
|
@ -1,22 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { BorrowCapacity } from './BorrowCapacity'
|
|
||||||
export { BorrowModal } from './BorrowModal'
|
|
||||||
export { Button } from './Button'
|
|
||||||
export { Card } from './Card'
|
|
||||||
export { CircularProgress } from './CircularProgress'
|
|
||||||
export { ContainerSecondary } from './ContainerSecondary'
|
|
||||||
export { CookieConsent } from './CookieConsent'
|
|
||||||
export { FormattedNumber } from './FormattedNumber'
|
|
||||||
export { Gauge } from './Gauge'
|
|
||||||
export { LabelValuePair } from './LabelValuePair'
|
|
||||||
export { Layout } from './Layout'
|
|
||||||
export { Modal } from './Modal'
|
|
||||||
export { Modals } from './Modals'
|
|
||||||
export { PositionsList } from './PositionsList'
|
|
||||||
export { ProgressBar } from './ProgressBar'
|
|
||||||
export { RepayModal } from './RepayModal'
|
|
||||||
export { Slider } from './Slider'
|
|
||||||
export { Text } from './Text'
|
|
||||||
export { TextLink } from './TextLink'
|
|
||||||
export { Tooltip } from './Tooltip'
|
|
||||||
// @endindex
|
|
@ -1,68 +0,0 @@
|
|||||||
import { ChainInfoID } from '@marsprotocol/wallet-connector'
|
|
||||||
|
|
||||||
const Assets: { [key: string]: Asset } = {
|
|
||||||
osmo: {
|
|
||||||
symbol: 'OSMO',
|
|
||||||
name: 'Osmosis',
|
|
||||||
denom: 'uosmo',
|
|
||||||
color: '#9f1ab9',
|
|
||||||
decimals: 6,
|
|
||||||
hasOraclePrice: true,
|
|
||||||
logo: '/tokens/osmo.svg',
|
|
||||||
},
|
|
||||||
atom: {
|
|
||||||
symbol: 'ATOM',
|
|
||||||
name: 'Atom',
|
|
||||||
denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
|
|
||||||
color: '#6f7390',
|
|
||||||
logo: '/tokens/atom.svg',
|
|
||||||
decimals: 6,
|
|
||||||
hasOraclePrice: true,
|
|
||||||
},
|
|
||||||
cro: {
|
|
||||||
symbol: 'CRO',
|
|
||||||
name: 'Cronos',
|
|
||||||
denom: 'ibc/E6931F78057F7CC5DA0FD6CEF82FF39373A6E0452BF1FD76910B93292CF356C1',
|
|
||||||
color: '#002D74',
|
|
||||||
logo: '/tokens/cro.svg',
|
|
||||||
decimals: 8,
|
|
||||||
hasOraclePrice: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const OtherAssets: { [key: string]: OtherAsset } = {
|
|
||||||
mars: {
|
|
||||||
symbol: 'MARS',
|
|
||||||
name: 'Mars',
|
|
||||||
denom: 'ibc/EA3E1640F9B1532AB129A571203A0B9F789A7F14BB66E350DCBFA18E1A1931F0',
|
|
||||||
//denom: 'ibc/1BF910A3C8A30C8E3331764FA0113B920AE14B913F487DF7E1989FD75EFE61FD'
|
|
||||||
color: '#a03b45',
|
|
||||||
logo: '/tokens/mars.svg',
|
|
||||||
decimals: 6,
|
|
||||||
hasOraclePrice: true,
|
|
||||||
poolId: 601,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const networkConfig: NetworkConfig = {
|
|
||||||
name: ChainInfoID.OsmosisTestnet,
|
|
||||||
hiveUrl: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-hive/graphql',
|
|
||||||
rpcUrl: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-rpc',
|
|
||||||
restUrl: 'https://osmosis-delphi-testnet-1.simply-vc.com.mt/XF32UOOU55CX/osmosis-lcd',
|
|
||||||
contracts: {
|
|
||||||
accountNft: 'osmo1xvne7u9svgy9vtqtqnaet4nvn8zcpp984zzrlezfzgk4798tps8srkf5wa',
|
|
||||||
mockVault: 'osmo1yqgjaehalz0pv5j22fdnaaekuprlggd7hth8m66jmdxe58ztqs4sjqtrlk',
|
|
||||||
marsOracleAdapter: 'osmo1tlad2hj9rm7az7atx2qq8pdpl2007hrhpzua42j8wgxr0kc0ct4sahuyh7',
|
|
||||||
swapper: 'osmo15kxcpvjaqlrj8ezecnghf2qs2x87veqx0fcemye0jpdr8jq7qkvsnyvuuf',
|
|
||||||
mockZapper: 'osmo1axad429tgnvzvfax08s4ytmf7ndg0f9z4jy355zyh4m6nasgtnzs5aw8u7',
|
|
||||||
creditManager: 'osmo1krz37p6xkkyu0f240enyt4ccxk7ds69kfgc5pnldsmpmmuvn3vpsnmpjaf',
|
|
||||||
redBank: 'osmo1g30recyv8pfy3qd4qn3dn7plc0rn5z68y5gn32j39e96tjhthzxsw3uvvu',
|
|
||||||
oracle: 'osmo1hkkx42777dyfz7wc8acjjhfdh9x2ugcjvdt7shtft6ha9cn420cquz3u3j',
|
|
||||||
},
|
|
||||||
assets: {
|
|
||||||
base: Assets.osmo,
|
|
||||||
whitelist: [Assets.osmo, Assets.atom, Assets.cro],
|
|
||||||
other: [OtherAssets.mars],
|
|
||||||
},
|
|
||||||
appUrl: 'https://testnet.osmosis.zone',
|
|
||||||
}
|
|
62
src/constants/assets.ts
Normal file
62
src/constants/assets.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { IS_TESTNET } from 'constants/env'
|
||||||
|
|
||||||
|
export const ASSETS: Asset[] = [
|
||||||
|
{
|
||||||
|
symbol: 'OSMO',
|
||||||
|
name: 'Osmosis',
|
||||||
|
denom: 'uosmo',
|
||||||
|
color: '#9f1ab9',
|
||||||
|
decimals: 6,
|
||||||
|
hasOraclePrice: true,
|
||||||
|
logo: '/tokens/osmo.svg',
|
||||||
|
isEnabled: true,
|
||||||
|
isMarket: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
symbol: 'ATOM',
|
||||||
|
name: 'Atom',
|
||||||
|
denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
|
||||||
|
color: '#6f7390',
|
||||||
|
logo: '/tokens/atom.svg',
|
||||||
|
decimals: 6,
|
||||||
|
hasOraclePrice: true,
|
||||||
|
isEnabled: IS_TESTNET ? true : false,
|
||||||
|
isMarket: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
symbol: 'CRO',
|
||||||
|
name: 'Cronos',
|
||||||
|
denom: 'ibc/E6931F78057F7CC5DA0FD6CEF82FF39373A6E0452BF1FD76910B93292CF356C1',
|
||||||
|
color: '#002D74',
|
||||||
|
logo: '/tokens/cro.svg',
|
||||||
|
decimals: 8,
|
||||||
|
hasOraclePrice: true,
|
||||||
|
isEnabled: false,
|
||||||
|
isMarket: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
symbol: 'MARS',
|
||||||
|
name: 'Mars',
|
||||||
|
denom: IS_TESTNET
|
||||||
|
? 'ibc/ACA4C8A815A053CC027DB90D15915ADA31939FA331CE745862CDD00A2904FA17'
|
||||||
|
: 'ibc/573FCD90FACEE750F55A8864EF7D38265F07E5A9273FA0E8DAFD39951332B580',
|
||||||
|
color: '#dd5b65',
|
||||||
|
logo: '/tokens/mars.svg',
|
||||||
|
decimals: 6,
|
||||||
|
poolId: IS_TESTNET ? 768 : 907,
|
||||||
|
hasOraclePrice: true,
|
||||||
|
isMarket: false,
|
||||||
|
isEnabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
symbol: 'JUNO',
|
||||||
|
name: 'Juno',
|
||||||
|
denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
|
||||||
|
color: 'black',
|
||||||
|
logo: '/tokens/juno.svg',
|
||||||
|
decimals: 6,
|
||||||
|
hasOraclePrice: true,
|
||||||
|
isMarket: IS_TESTNET,
|
||||||
|
isEnabled: false,
|
||||||
|
},
|
||||||
|
]
|
18
src/constants/env.ts
Normal file
18
src/constants/env.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const ADDRESS_ACCOUNT_NFT = process.env.NEXT_PUBLIC_ACCOUNT_NFT
|
||||||
|
export const ADDRESS_CREDIT_MANAGER = process.env.NEXT_PUBLIC_CREDIT_MANAGER
|
||||||
|
export const ADDRESS_INCENTIVES = process.env.NEXT_PUBLIC_INCENTIVES
|
||||||
|
export const ADDRESS_ORACLE = process.env.NEXT_PUBLIC_ORACLE
|
||||||
|
export const ADDRESS_RED_BANK = process.env.NEXT_PUBLIC_RED_BANK
|
||||||
|
export const ADDRESS_SWAPPER = process.env.NEXT_PUBLIC_SWAPPER
|
||||||
|
export const ADDRESS_ZAPPER = process.env.NEXT_PUBLIC_ZAPPER
|
||||||
|
|
||||||
|
export const CHAIN_ID = process.env.NEXT_PUBLIC_CHAIN_ID
|
||||||
|
export const NETWORK = process.env.NEXT_PUBLIC_NETWORK
|
||||||
|
export const IS_TESTNET = NETWORK !== 'mainnet'
|
||||||
|
export const URL_GQL = process.env.NEXT_PUBLIC_GQL
|
||||||
|
export const URL_REST = process.env.NEXT_PUBLIC_REST
|
||||||
|
export const URL_RPC = process.env.NEXT_PUBLIC_RPC
|
||||||
|
export const URL_API = process.env.NEXT_PUBLIC_API
|
||||||
|
export const WALLETS = process.env.NEXT_PUBLIC_WALLETS?.split(',') ?? []
|
||||||
|
|
||||||
|
export const ENV_MISSING_MESSAGE = 'Environment variable missing'
|
2
src/constants/gas.ts
Normal file
2
src/constants/gas.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const GAS_ADJUSTMENT = 1.3
|
||||||
|
export const GAS_PRICE = '0.025uosmo'
|
@ -1,8 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { useAccountStats } from './useAccountStats'
|
|
||||||
export { useAnimations } from './useAnimations'
|
|
||||||
export { useBalances } from './useBalances'
|
|
||||||
export { useCalculateMaxBorrowAmount } from './useCalculateMaxBorrowAmount'
|
|
||||||
export { useCalculateMaxTradeAmount } from './useCalculateMaxTradeAmount'
|
|
||||||
export { useCalculateMaxWithdrawAmount } from './useCalculateMaxWithdrawAmount'
|
|
||||||
// @endindex
|
|
@ -1,8 +1,10 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { useCreditAccountPositions, useMarkets, useTokenPrices } from 'hooks/queries'
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
import { useAccountDetailsStore } from 'stores'
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
// displaying 3 levels of risk based on the weighted average of liquidation LTVs
|
// displaying 3 levels of risk based on the weighted average of liquidation LTVs
|
||||||
// 0.85 -> 25% risk
|
// 0.85 -> 25% risk
|
||||||
@ -80,7 +82,7 @@ const calculateStatsFromAccountPositions = (assets: Asset[], debts: Debt[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useAccountStats = (actions?: AccountStatsAction[]) => {
|
export const useAccountStats = (actions?: AccountStatsAction[]) => {
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
|
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const { data: marketsData } = useMarkets()
|
const { data: marketsData } = useMarkets()
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
import { useSettingsStore } from 'stores'
|
import useStore from 'store'
|
||||||
|
|
||||||
export const useAnimations = () => {
|
export const useAnimations = () => {
|
||||||
const enableAnimations = useSettingsStore((s) => s.enableAnimations)
|
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||||
|
|
||||||
const queryChangeHandler = (event: MediaQueryListEvent) => {
|
const queryChangeHandler = (event: MediaQueryListEvent) => {
|
||||||
useSettingsStore.setState({ enableAnimations: !event?.matches ?? true })
|
useStore.setState({ enableAnimations: !event?.matches ?? true })
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mediaQuery: MediaQueryList = window.matchMedia('(prefers-reduced-motion: reduce)')
|
const mediaQuery: MediaQueryList = window.matchMedia('(prefers-reduced-motion: reduce)')
|
||||||
|
|
||||||
if (mediaQuery) {
|
if (mediaQuery) {
|
||||||
useSettingsStore.setState({ enableAnimations: !mediaQuery.matches })
|
useStore.setState({ enableAnimations: !mediaQuery.matches })
|
||||||
mediaQuery.addEventListener('change', queryChangeHandler)
|
mediaQuery.addEventListener('change', queryChangeHandler)
|
||||||
return () => mediaQuery.removeEventListener('change', queryChangeHandler)
|
return () => mediaQuery.removeEventListener('change', queryChangeHandler)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { useCreditAccountPositions, useMarkets, useTokenPrices } from 'hooks/queries'
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
import { formatBalances } from 'utils/balances'
|
import { formatBalances } from 'utils/balances'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
export const useBalances = () => {
|
export const useBalances = () => {
|
||||||
const [balanceData, setBalanceData] = useState<PositionsData[]>()
|
const [balanceData, setBalanceData] = useState<PositionsData[]>()
|
||||||
|
|
||||||
const { data: marketsData } = useMarkets()
|
const { data: marketsData } = useMarkets()
|
||||||
const { data: tokenPrices } = useTokenPrices()
|
const { data: tokenPrices } = useTokenPrices()
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions(
|
const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions(
|
||||||
selectedAccount ?? '',
|
selectedAccount ?? '',
|
||||||
@ -19,15 +22,15 @@ export const useBalances = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const balances =
|
const balances =
|
||||||
positionsData?.coins && tokenPrices
|
positionsData?.coins && tokenPrices
|
||||||
? formatBalances(positionsData.coins, tokenPrices, false, whitelistedAssets)
|
? formatBalances(positionsData.coins, tokenPrices, false, marketAssets)
|
||||||
: []
|
: []
|
||||||
const debtBalances =
|
const debtBalances =
|
||||||
positionsData?.debts && tokenPrices
|
positionsData?.debts && tokenPrices
|
||||||
? formatBalances(positionsData.debts, tokenPrices, true, whitelistedAssets, marketsData)
|
? formatBalances(positionsData.debts, tokenPrices, true, marketAssets, marketsData)
|
||||||
: []
|
: []
|
||||||
|
|
||||||
setBalanceData([...balances, ...debtBalances])
|
setBalanceData([...balances, ...debtBalances])
|
||||||
}, [positionsData, marketsData, tokenPrices, whitelistedAssets])
|
}, [positionsData, marketsData, tokenPrices, marketAssets])
|
||||||
|
|
||||||
return balanceData
|
return balanceData
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import {
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
useCreditAccountPositions,
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
useMarkets,
|
import { useRedbankBalances } from 'hooks/queries/useRedbankBalances'
|
||||||
useRedbankBalances,
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
useTokenPrices,
|
|
||||||
} from 'hooks/queries'
|
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
|
||||||
import { getTokenDecimals } from 'utils/tokens'
|
import { getTokenDecimals } from 'utils/tokens'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
||||||
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
||||||
@ -17,8 +16,8 @@ const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boolean) => {
|
export const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized: boolean) => {
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const { data: marketsData } = useMarkets()
|
const { data: marketsData } = useMarkets()
|
||||||
@ -62,7 +61,7 @@ export const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized
|
|||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
const borrowTokenPrice = tokenPrices[denom]
|
const borrowTokenPrice = tokenPrices[denom]
|
||||||
const tokenDecimals = getTokenDecimals(denom, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(denom, marketAssets)
|
||||||
|
|
||||||
let maxAmountCapacity
|
let maxAmountCapacity
|
||||||
if (isUnderCollateralized) {
|
if (isUnderCollateralized) {
|
||||||
@ -100,6 +99,6 @@ export const useCalculateMaxBorrowAmount = (denom: string, isUnderCollateralized
|
|||||||
positionsData,
|
positionsData,
|
||||||
redbankBalances,
|
redbankBalances,
|
||||||
tokenPrices,
|
tokenPrices,
|
||||||
whitelistedAssets,
|
marketAssets,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import {
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
useCreditAccountPositions,
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
useMarkets,
|
import { useRedbankBalances } from 'hooks/queries/useRedbankBalances'
|
||||||
useRedbankBalances,
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
useTokenPrices,
|
import useStore from 'store'
|
||||||
} from 'hooks/queries'
|
|
||||||
import { useAccountDetailsStore } from 'stores'
|
|
||||||
|
|
||||||
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
||||||
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
||||||
@ -22,7 +20,7 @@ export const useCalculateMaxTradeAmount = (
|
|||||||
tokenOut: string,
|
tokenOut: string,
|
||||||
isMargin: boolean,
|
isMargin: boolean,
|
||||||
) => {
|
) => {
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
|
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const { data: marketsData } = useMarkets()
|
const { data: marketsData } = useMarkets()
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import {
|
import { useCreditAccountPositions } from 'hooks/queries/useCreditAccountPositions'
|
||||||
useCreditAccountPositions,
|
import { useMarkets } from 'hooks/queries/useMarkets'
|
||||||
useMarkets,
|
import { useRedbankBalances } from 'hooks/queries/useRedbankBalances'
|
||||||
useRedbankBalances,
|
import { useTokenPrices } from 'hooks/queries/useTokenPrices'
|
||||||
useTokenPrices,
|
|
||||||
} from 'hooks/queries'
|
|
||||||
import { useAccountDetailsStore, useNetworkConfigStore } from 'stores'
|
|
||||||
import { getTokenDecimals } from 'utils/tokens'
|
import { getTokenDecimals } from 'utils/tokens'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
||||||
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
const hourlyAPY = BigNumber(borrowAPY).div(24 * 365)
|
||||||
@ -17,15 +16,15 @@ const getApproximateHourlyInterest = (amount: string, borrowAPY: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useCalculateMaxWithdrawAmount = (denom: string, borrow: boolean) => {
|
export const useCalculateMaxWithdrawAmount = (denom: string, borrow: boolean) => {
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
|
const selectedAccount = useStore((s) => s.selectedAccount)
|
||||||
const whitelistedAssets = useNetworkConfigStore((s) => s.assets.whitelist)
|
const marketAssets = getMarketAssets()
|
||||||
|
|
||||||
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
const { data: positionsData } = useCreditAccountPositions(selectedAccount ?? '')
|
||||||
const { data: marketsData } = useMarkets()
|
const { data: marketsData } = useMarkets()
|
||||||
const { data: tokenPrices } = useTokenPrices()
|
const { data: tokenPrices } = useTokenPrices()
|
||||||
const { data: redbankBalances } = useRedbankBalances()
|
const { data: redbankBalances } = useRedbankBalances()
|
||||||
|
|
||||||
const tokenDecimals = getTokenDecimals(denom, whitelistedAssets)
|
const tokenDecimals = getTokenDecimals(denom, marketAssets)
|
||||||
|
|
||||||
const getTokenValue = useCallback(
|
const getTokenValue = useCallback(
|
||||||
(amount: string, denom: string) => {
|
(amount: string, denom: string) => {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
|
|
||||||
export { useBorrowFunds } from './useBorrowFunds'
|
|
||||||
export { useCreateCreditAccount } from './useCreateCreditAccount'
|
|
||||||
export { useDeleteCreditAccount } from './useDeleteCreditAccount'
|
|
||||||
export { useDepositCreditAccount } from './useDepositCreditAccount'
|
|
||||||
export { useRepayFunds } from './useRepayFunds'
|
|
||||||
export { useTradeAsset } from './useTradeAsset'
|
|
||||||
export { useWithdrawFunds } from './useWithdrawFunds'
|
|
||||||
// @endindex
|
|
@ -2,7 +2,7 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
import { useAccountDetailsStore, useWalletStore } from 'stores'
|
import useStore from 'store'
|
||||||
import { queryKeys } from 'types/query-keys-factory'
|
import { queryKeys } from 'types/query-keys-factory'
|
||||||
import { hardcodedFee } from 'utils/contants'
|
import { hardcodedFee } from 'utils/contants'
|
||||||
|
|
||||||
@ -12,12 +12,10 @@ export const useBorrowFunds = (
|
|||||||
withdraw = false,
|
withdraw = false,
|
||||||
options: Omit<UseMutationOptions, 'onError'>,
|
options: Omit<UseMutationOptions, 'onError'>,
|
||||||
) => {
|
) => {
|
||||||
const creditManagerClient = useWalletStore((s) => s.clients.creditManager)
|
const creditManagerClient = useStore((s) => s.clients.creditManager)
|
||||||
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount ?? '')
|
const selectedAccount = useStore((s) => s.selectedAccount ?? '')
|
||||||
const address = useWalletStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const actions = useMemo(() => {
|
const actions = useMemo(() => {
|
||||||
if (!withdraw) {
|
if (!withdraw) {
|
||||||
return [
|
return [
|
||||||
@ -29,7 +27,6 @@ export const useBorrowFunds = (
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
borrow: {
|
borrow: {
|
||||||
@ -45,7 +42,6 @@ export const useBorrowFunds = (
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}, [withdraw, denom, amount])
|
}, [withdraw, denom, amount])
|
||||||
|
|
||||||
return useMutation(
|
return useMutation(
|
||||||
async () =>
|
async () =>
|
||||||
await creditManagerClient?.updateCreditAccount(
|
await creditManagerClient?.updateCreditAccount(
|
||||||
@ -56,7 +52,6 @@ export const useBorrowFunds = (
|
|||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
queryClient.invalidateQueries(queryKeys.creditAccountsPositions(selectedAccount))
|
queryClient.invalidateQueries(queryKeys.creditAccountsPositions(selectedAccount))
|
||||||
queryClient.invalidateQueries(queryKeys.redbankBalances())
|
queryClient.invalidateQueries(queryKeys.redbankBalances())
|
||||||
|
|
||||||
// if withdrawing to wallet, need to explicility invalidate balances queries
|
// if withdrawing to wallet, need to explicility invalidate balances queries
|
||||||
if (withdraw) {
|
if (withdraw) {
|
||||||
queryClient.invalidateQueries(queryKeys.tokenBalance(address ?? '', denom))
|
queryClient.invalidateQueries(queryKeys.tokenBalance(address ?? '', denom))
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
|
|
||||||
import {
|
|
||||||
useAccountDetailsStore,
|
|
||||||
useModalStore,
|
|
||||||
useNetworkConfigStore,
|
|
||||||
useWalletStore,
|
|
||||||
} from 'stores'
|
|
||||||
import { queryKeys } from 'types/query-keys-factory'
|
|
||||||
import { hardcodedFee } from 'utils/contants'
|
|
||||||
|
|
||||||
// 200000 gas used
|
|
||||||
const executeMsg = {
|
|
||||||
create_credit_account: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCreateCreditAccount = () => {
|
|
||||||
const signingClient = useWalletStore((s) => s.signingClient)
|
|
||||||
const address = useWalletStore((s) => s.address)
|
|
||||||
const creditManagerAddress = useNetworkConfigStore((s) => s.contracts.creditManager)
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
return useMutation(
|
|
||||||
async () =>
|
|
||||||
await signingClient?.execute(address ?? '', creditManagerAddress, executeMsg, hardcodedFee),
|
|
||||||
{
|
|
||||||
onSettled: () => {
|
|
||||||
queryClient.invalidateQueries(queryKeys.creditAccounts(address ?? ''))
|
|
||||||
},
|
|
||||||
onError: (err: Error) => {
|
|
||||||
toast.error(err.message)
|
|
||||||
},
|
|
||||||
onSuccess: (data) => {
|
|
||||||
if (!data) return
|
|
||||||
|
|
||||||
// TODO: is there some better way to parse response to extract token id???
|
|
||||||
const createdID = data.logs[0].events[2].attributes[6].value
|
|
||||||
useAccountDetailsStore.setState({ selectedAccount: createdID })
|
|
||||||
useModalStore.setState({ fundAccountModal: true })
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
|
|
||||||
import { useNetworkConfigStore, useWalletStore } from 'stores'
|
|
||||||
import { queryKeys } from 'types/query-keys-factory'
|
|
||||||
import { hardcodedFee } from 'utils/contants'
|
|
||||||
|
|
||||||
export const useDeleteCreditAccount = (accountId: string) => {
|
|
||||||
const signingClient = useWalletStore((s) => s.signingClient)
|
|
||||||
const address = useWalletStore((s) => s.address)
|
|
||||||
const accountNftAddress = useNetworkConfigStore((s) => s.contracts.accountNft)
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
return useMutation(
|
|
||||||
async () =>
|
|
||||||
await signingClient?.execute(
|
|
||||||
address ?? '',
|
|
||||||
accountNftAddress,
|
|
||||||
{
|
|
||||||
burn: {
|
|
||||||
token_id: accountId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hardcodedFee,
|
|
||||||
),
|
|
||||||
{
|
|
||||||
onSettled: () => {
|
|
||||||
queryClient.invalidateQueries(queryKeys.creditAccounts(address ?? ''))
|
|
||||||
},
|
|
||||||
onError: (err: Error) => {
|
|
||||||
toast.error(err.message)
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
toast.success('Credit Account Deleted')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
|
|
||||||
import { useNetworkConfigStore, useWalletStore } from 'stores'
|
|
||||||
import { queryKeys } from 'types/query-keys-factory'
|
|
||||||
import { hardcodedFee } from 'utils/contants'
|
|
||||||
|
|
||||||
export const useDepositCreditAccount = (
|
|
||||||
accountId: string,
|
|
||||||
denom: string,
|
|
||||||
amount: number,
|
|
||||||
options?: {
|
|
||||||
onSuccess?: () => void
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
const signingClient = useWalletStore((s) => s.signingClient)
|
|
||||||
const address = useWalletStore((s) => s.address)
|
|
||||||
const creditManagerAddress = useNetworkConfigStore((s) => s.contracts.creditManager)
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
return useMutation(
|
|
||||||
async () =>
|
|
||||||
await signingClient?.execute(
|
|
||||||
address ?? '',
|
|
||||||
creditManagerAddress,
|
|
||||||
{
|
|
||||||
update_credit_account: {
|
|
||||||
account_id: accountId,
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
deposit: {
|
|
||||||
denom,
|
|
||||||
amount: String(amount),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hardcodedFee,
|
|
||||||
undefined,
|
|
||||||
[
|
|
||||||
{
|
|
||||||
denom,
|
|
||||||
amount: String(amount),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
),
|
|
||||||
{
|
|
||||||
onError: (err: Error) => {
|
|
||||||
toast.error(err.message)
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries(queryKeys.allBalances(address ?? ''))
|
|
||||||
queryClient.invalidateQueries(queryKeys.tokenBalance(address ?? '', denom))
|
|
||||||
queryClient.invalidateQueries(queryKeys.creditAccountsPositions(accountId))
|
|
||||||
|
|
||||||
options?.onSuccess && options.onSuccess()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user