Compare commits

...
Author SHA1 Message Date
Bob van der Helm 06db4a2faa update health computer for perps (#823)
* update health computer for perps

* update health computer + fix comments
2024-02-23 13:57:27 +01:00
Linkie Link 5846e893d1 Merge branch 'main' of https://github.com/mars-protocol/mars-v2-frontend into develop 2024-02-16 09:07:22 +01:00
Linkie Link 40224ad201 feat: list DYDX (#815) 2024-02-16 08:58:12 +01:00
Linkie LinkandBob van der Helm 0e6f0edb5d Docker update (#814)
* feat: handle URLs with or without trailing slash (#803)

* feat: handle URLs with or without trailing slash

* tidy: cleanup slashes

* Fix docker build (#805)

* fix: fixed the docker build

* tidy: cleanup

* env: remove env contents (#808)

* Portfolio fix (#809)

* fix: fixed the portfolio account detail page layout

* fix: fixed portfolio cards

* tidy: refactor

* align buttons, perps row clickable (#807)

* align buttons, perps row clickable

* fix comments

* update to v2.2.4

* fix borrowbutton logic, add vault deposit manage btn, fix icon size vault modal

---------

Co-authored-by: Linkie Link <linkielink.dev@gmail.com>

* Update .env.production

* Update Dockerbuild (#813)

* v2.2.4 (#810)

* feat: handle URLs with or without trailing slash (#803)

* feat: handle URLs with or without trailing slash

* tidy: cleanup slashes

* Fix docker build (#805)

* fix: fixed the docker build

* tidy: cleanup

* env: remove env contents (#808)

* Portfolio fix (#809)

* fix: fixed the portfolio account detail page layout

* fix: fixed portfolio cards

* tidy: refactor

* align buttons, perps row clickable (#807)

* align buttons, perps row clickable

* fix comments

* update to v2.2.4

* fix borrowbutton logic, add vault deposit manage btn, fix icon size vault modal

---------

Co-authored-by: Linkie Link <linkielink.dev@gmail.com>

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>

* Update Dockerfile

* remove   .env files

* tidy: format

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2024-02-15 10:49:14 +01:00
Linkie Link e3b5e330ee Merge branch 'main' of https://github.com/mars-protocol/mars-v2-frontend into develop
# Conflicts:
#	.env
#	src/components/perps/BalancesTable/index.tsx
2024-02-14 19:30:55 +01:00
Linkie LinkandBob van der Helm 7eac8e7a35 Update Dockerbuild (#813)
* v2.2.4 (#810)

* feat: handle URLs with or without trailing slash (#803)

* feat: handle URLs with or without trailing slash

* tidy: cleanup slashes

* Fix docker build (#805)

* fix: fixed the docker build

* tidy: cleanup

* env: remove env contents (#808)

* Portfolio fix (#809)

* fix: fixed the portfolio account detail page layout

* fix: fixed portfolio cards

* tidy: refactor

* align buttons, perps row clickable (#807)

* align buttons, perps row clickable

* fix comments

* update to v2.2.4

* fix borrowbutton logic, add vault deposit manage btn, fix icon size vault modal

---------

Co-authored-by: Linkie Link <linkielink.dev@gmail.com>

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>

* Update Dockerfile

* remove   .env files

* tidy: format

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2024-02-14 19:29:41 +01:00
Linkie Link af478c56d5 Update .env.production 2024-02-14 16:43:57 +01:00
Linkie LinkandBob van der Helm c08ee627fc v2.2.4 (#810)
* feat: handle URLs with or without trailing slash (#803)

* feat: handle URLs with or without trailing slash

* tidy: cleanup slashes

* Fix docker build (#805)

* fix: fixed the docker build

* tidy: cleanup

* env: remove env contents (#808)

* Portfolio fix (#809)

* fix: fixed the portfolio account detail page layout

* fix: fixed portfolio cards

* tidy: refactor

* align buttons, perps row clickable (#807)

* align buttons, perps row clickable

* fix comments

* update to v2.2.4

* fix borrowbutton logic, add vault deposit manage btn, fix icon size vault modal

---------

Co-authored-by: Linkie Link <linkielink.dev@gmail.com>

---------

Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2024-02-14 15:01:25 +01:00
Bob van der HelmandLinkie Link a6f4c24f15 align buttons, perps row clickable (#807)
* align buttons, perps row clickable

* fix comments

* update to v2.2.4

* fix borrowbutton logic, add vault deposit manage btn, fix icon size vault modal

---------

Co-authored-by: Linkie Link <linkielink.dev@gmail.com>
2024-02-14 14:49:15 +01:00
Linkie Link 6946ceddfc Portfolio fix (#809)
* fix: fixed the portfolio account detail page layout

* fix: fixed portfolio cards

* tidy: refactor
2024-02-14 14:18:10 +01:00
Linkie Link 0154065ffb env: remove env contents (#808) 2024-02-14 12:33:10 +01:00
Linkie Link 4f64234a75 Merge branch 'main' into develop 2024-02-14 12:01:10 +01:00
Linkie Link 26f1ef4a2c Fix docker build (#805)
* fix: fixed the docker build

* tidy: cleanup
2024-02-14 11:58:48 +01:00
Linkie Link f7f8136b38 feat: handle URLs with or without trailing slash (#803) (#804)
* feat: handle URLs with or without trailing slash

* tidy: cleanup slashes
2024-02-14 11:16:06 +01:00
66 changed files with 1146 additions and 731 deletions
-13
View File
@@ -1,13 +0,0 @@
# DO NOT EDIT THIS FILE WHEN USING DOCKER
# These values are used to replace the values in the built app,
# you should pass environment variables as defined in README.md
# CONFIG #
NEXT_PUBLIC_NETWORK=mainnet
# OSMOSIS-1 #
NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC
NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST
# WALLET CONNECT #
NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID
-13
View File
@@ -1,13 +0,0 @@
# DO NOT EDIT THIS FILE WHEN USING DOCKER
# These values are used to replace the values in the built app,
# you should pass environment variables as defined in README.md
# CONFIG #
NEXT_PUBLIC_NETWORK=mainnet
# OSMOSIS-1 #
NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC
NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST
# WALLET CONNECT #
NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID
+8 -2
View File
@@ -6,18 +6,24 @@ RUN yarn install
COPY . . COPY . .
RUN apk --update add patch RUN apk --update add patch
RUN patch next.config.js next-config.patch RUN patch next.config.js next-config.patch
ENV NEXT_PUBLIC_NETWORK=mainnet
ENV NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC
ENV NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST
ENV NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID
ENV NODE_ENV=production
RUN yarn build RUN yarn build
FROM node:20-alpine as runner FROM node:20-alpine as runner
WORKDIR /app WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/package.json . COPY --from=builder /app/package.json .
COPY --from=builder /app/yarn.lock . COPY --from=builder /app/yarn.lock .
COPY --from=builder /app/next.config.js . COPY --from=builder /app/next.config.js .
COPY --from=builder /app/public ./public COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/.next/static ./.next/static
COPY entrypoint.sh . COPY entrypoint.sh .
RUN apk add --no-cache --upgrade bash RUN apk add --no-cache --upgrade bash
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "mars-v2-frontend", "name": "mars-v2-frontend",
"version": "2.2.3", "version": "2.2.4",
"homepage": "./", "homepage": "./",
"private": false, "private": false,
"license": "SEE LICENSE IN LICENSE FILE", "license": "SEE LICENSE IN LICENSE FILE",
+36
View File
@@ -0,0 +1,36 @@
<svg viewBox="0 0 240 240" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="240" height="240" rx="120" fill="#E50571" />
<path d="M149.107 60.9396L63.3276 181.702H89.6637L175.888 60.9396H149.107Z" fill="white" />
<path
d="M92.4053 60.9396L117.644 96.5239L104.476 115.934L65.5205 60.9396H92.4053Z"
fill="url(#paint0_linear_6269_3439)"
/>
<path
d="M151.664 181.712L123.682 142.354L136.851 123.483L178 181.712H151.664Z"
fill="url(#paint1_linear_6269_3439)"
/>
<defs>
<linearGradient
id="paint0_linear_6269_3439"
x1="86.3698"
y1="68.4878"
x2="121.753"
y2="111.957"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="white" />
<stop offset="1" stop-color="white" stop-opacity="0.75" />
</linearGradient>
<linearGradient
id="paint1_linear_6269_3439"
x1="157.7"
y1="172.547"
x2="114.305"
y2="113.014"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="white" stop-opacity="0.68" />
<stop offset="1" stop-color="white" stop-opacity="0.1" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -18,6 +18,7 @@ import chains from 'configs/chains'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset' import useBaseAsset from 'hooks/assets/useBasetAsset'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets' import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useChainConfig from 'hooks/useChainConfig'
import useCurrentWallet from 'hooks/useCurrentWallet' import useCurrentWallet from 'hooks/useCurrentWallet'
import useICNSDomain from 'hooks/useICNSDomain' import useICNSDomain from 'hooks/useICNSDomain'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
@@ -27,7 +28,6 @@ import { NETWORK } from 'types/enums/network'
import { ChainInfoID } from 'types/enums/wallet' import { ChainInfoID } from 'types/enums/wallet'
import { truncate } from 'utils/formatters' import { truncate } from 'utils/formatters'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
import useChainConfig from 'hooks/useChainConfig'
export default function WalletConnectedButton() { export default function WalletConnectedButton() {
// --------------- // ---------------
@@ -90,7 +90,7 @@ export default function WalletConnectedButton() {
}) })
} }
navigate(getRoute(getPage(pathname), searchParams)) navigate(getRoute(getPage(pathname), new URLSearchParams()))
} }
useEffect(() => { useEffect(() => {
+10 -4
View File
@@ -63,16 +63,22 @@ export default function HealthBar({
health={isUpdated ? updatedHealth : health} health={isUpdated ? updatedHealth : health}
healthFactor={isUpdated ? updatedHealthFactor : healthFactor} healthFactor={isUpdated ? updatedHealthFactor : healthFactor}
> >
<> <div className={classNames('flex w-full', showIcon && 'gap-2')}>
{showIcon && ( {showIcon && (
<HealthIcon <HealthIcon
health={health} health={health}
isLoading={healthFactor === 0} isLoading={healthFactor === 0}
className={classNames('mr-2', iconClassName)} className={iconClassName}
colorClass='text-white' colorClass='text-white'
/> />
)} )}
<div className={classNames('flex w-full', 'rounded-full overflow-hidden', className)}> <div
className={classNames(
'flex w-full flex-shrink',
'rounded-full overflow-hidden',
className,
)}
>
<svg <svg
version='1.1' version='1.1'
xmlns='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg'
@@ -153,7 +159,7 @@ export default function HealthBar({
)} )}
</svg> </svg>
</div> </div>
</> </div>
</HealthTooltip> </HealthTooltip>
) )
} }
+4 -4
View File
@@ -5,7 +5,7 @@ import { ExclamationMarkCircled, Heart } from 'components/common/Icons'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
health: number health: number
className: string className?: string
colorClass?: string colorClass?: string
} }
@@ -14,9 +14,9 @@ export default function HealthIcon(props: Props) {
const color = colorClass ?? 'text-white' const color = colorClass ?? 'text-white'
return ( return (
<> <div className='w-5'>
{!isLoading && health === 0 ? ( {!isLoading && health === 0 ? (
<ExclamationMarkCircled className={classNames('w-5 text-loss animate-pulse', className)} /> <ExclamationMarkCircled className={classNames(' text-loss animate-pulse', className)} />
) : ( ) : (
<Heart <Heart
className={classNames( className={classNames(
@@ -26,6 +26,6 @@ export default function HealthIcon(props: Props) {
)} )}
/> />
)} )}
</> </div>
) )
} }
@@ -1,44 +0,0 @@
import { useCallback } from 'react'
import Button from 'components/common/Button'
import ActionButton from 'components/common/Button/ActionButton'
import { HandCoins, Plus } from 'components/common/Icons'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useStore from 'store'
interface Props {
data: BorrowMarketTableData
}
export default function BorrowActionButtons(props: Props) {
const { asset, accountDebt } = props.data
const marketAssets = useMarketEnabledAssets()
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
const borrowHandler = useCallback(() => {
if (!currentAsset) return null
useStore.setState({ borrowModal: { asset: currentAsset, marketData: props.data } })
}, [currentAsset, props.data])
const repayHandler = useCallback(() => {
if (!currentAsset) return null
useStore.setState({
borrowModal: { asset: currentAsset, marketData: props.data, isRepay: true },
})
}, [currentAsset, props.data])
return (
<div className='flex flex-row space-x-2'>
<ActionButton
leftIcon={<Plus className='w-3' />}
onClick={borrowHandler}
color='secondary'
text={accountDebt ? 'Borrow more' : 'Borrow'}
className='text-center min-w-40'
/>
{accountDebt && (
<Button color='tertiary' leftIcon={<HandCoins />} text='Repay' onClick={repayHandler} />
)}
</div>
)
}
@@ -2,12 +2,10 @@ import { Row } from '@tanstack/react-table'
import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types' import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types'
import { useCallback } from 'react' import { useCallback } from 'react'
import BorrowActionButtons from 'components/borrow/BorrowActionButtons'
import { NAME_META } from 'components/borrow/Table/Columns/Name' import { NAME_META } from 'components/borrow/Table/Columns/Name'
import useAvailableColumns from 'components/borrow/Table/Columns/useAvailableColumns' import useAvailableColumns from 'components/borrow/Table/Columns/useAvailableColumns'
import MarketDetails from 'components/common/MarketDetails' import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
type Props = { type Props = {
data: BorrowMarketTableData[] data: BorrowMarketTableData[]
@@ -20,14 +18,7 @@ export default function AvailableBorrowingsTable(props: Props) {
const renderExpanded = useCallback( const renderExpanded = useCallback(
(row: Row<BorrowMarketTableData>, _: TanstackTable<BorrowMarketTableData>) => { (row: Row<BorrowMarketTableData>, _: TanstackTable<BorrowMarketTableData>) => {
const currentRow = row as Row<BorrowMarketTableData> const currentRow = row as Row<BorrowMarketTableData>
return ( return <MarketDetails row={currentRow} type='borrow' />
<>
<ActionButtonRow row={currentRow}>
<BorrowActionButtons data={row.original} />
</ActionButtonRow>
<MarketDetails row={currentRow} type='borrow' />
</>
)
}, },
[], [],
) )
@@ -0,0 +1,61 @@
import { useCallback } from 'react'
import ActionButton from 'components/common/Button/ActionButton'
import { Plus } from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useStore from 'store'
export const BORROW_BUTTON_META = {
accessorKey: 'borrow',
enableSorting: false,
header: '',
}
interface Props {
data: LendingMarketTableData
}
export default function BorrowButton(props: Props) {
const account = useCurrentAccount()
const address = useStore((s) => s.address)
const hasNoDeposits = !account?.deposits?.length && !account?.lends?.length && !!address
const borrowHandler = useCallback(() => {
if (!props.data.asset) return null
useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } })
}, [props.data])
return (
<div className='flex justify-end'>
<ConditionalWrapper
condition={hasNoDeposits}
wrapper={(children) => (
<Tooltip
type='warning'
content={
<Text size='sm'>{`You dont have any collateral.
Please first deposit into your Credit Account before borrowing.`}</Text>
}
contentClassName='max-w-[200px]'
className='ml-auto'
>
{children}
</Tooltip>
)}
>
<ActionButton
leftIcon={<Plus />}
disabled={hasNoDeposits}
color='tertiary'
onClick={(e) => {
borrowHandler()
e.stopPropagation()
}}
text='Borrow'
/>
</ConditionalWrapper>
</div>
)
}
@@ -4,7 +4,6 @@ import Loading from 'components/common/Loading'
export const BORROW_RATE_META = { export const BORROW_RATE_META = {
accessorKey: 'apy.borrow', accessorKey: 'apy.borrow',
header: 'Borrow Rate APY', header: 'Borrow Rate APY',
meta: { className: 'w-40' },
} }
interface Props { interface Props {
@@ -0,0 +1,21 @@
import { ChevronDown, ChevronUp } from 'components/common/Icons'
export const CHEVRON_META = {
id: 'chevron',
enableSorting: false,
header: '',
meta: {
className: 'w-5',
},
}
interface Props {
isExpanded: boolean
}
export default function Chevron(props: Props) {
return (
<div className='flex items-center justify-end'>
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
</div>
)
}
@@ -10,7 +10,6 @@ export const LIQUIDITY_META = {
accessorKey: 'liquidity', accessorKey: 'liquidity',
header: 'Liquidity Available', header: 'Liquidity Available',
id: 'liquidity', id: 'liquidity',
meta: { className: 'w-40' },
} }
export const liquiditySortingFn = ( export const liquiditySortingFn = (
+41 -6
View File
@@ -1,20 +1,55 @@
import { ChevronDown, ChevronUp } from 'components/common/Icons' import { useCallback, useMemo } from 'react'
import DropDownButton from 'components/common/Button/DropDownButton'
import { HandCoins, Plus } from 'components/common/Icons'
import useStore from 'store'
export const MANAGE_META = { export const MANAGE_META = {
accessorKey: 'manage', accessorKey: 'manage',
enableSorting: false, enableSorting: false,
header: 'Manage', header: '',
meta: { className: 'w-30' },
} }
interface Props { interface Props {
isExpanded: boolean data: BorrowMarketTableData
} }
export default function Manage(props: Props) { export default function Manage(props: Props) {
const address = useStore((s) => s.address)
const borrowHandler = useCallback(() => {
if (!props.data.asset) return null
useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } })
}, [props.data])
const repayHandler = useCallback(() => {
if (!props.data.asset) return null
useStore.setState({
borrowModal: { asset: props.data.asset, marketData: props.data, isRepay: true },
})
}, [props.data])
const ITEMS: DropDownItem[] = useMemo(
() => [
{
icon: <Plus />,
text: 'Borrow more',
onClick: borrowHandler,
},
{
icon: <HandCoins />,
text: 'Repay',
onClick: repayHandler,
},
],
[borrowHandler, repayHandler],
)
if (!address) return null
return ( return (
<div className='flex items-center justify-end'> <div className='flex justify-end z-10'>
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div> <DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div> </div>
) )
} }
@@ -1,12 +1,13 @@
import { ColumnDef } from '@tanstack/react-table' import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import BorrowButton, { BORROW_BUTTON_META } from 'components/borrow/Table/Columns/BorrowButton'
import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate' import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate'
import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
import Liquidity, { import Liquidity, {
LIQUIDITY_META, LIQUIDITY_META,
liquiditySortingFn, liquiditySortingFn,
} from 'components/borrow/Table/Columns/Liquidity' } from 'components/borrow/Table/Columns/Liquidity'
import Manage, { MANAGE_META } from 'components/borrow/Table/Columns/Manage'
import Name, { NAME_META } from 'components/borrow/Table/Columns/Name' import Name, { NAME_META } from 'components/borrow/Table/Columns/Name'
export default function useAvailableColumns() { export default function useAvailableColumns() {
@@ -26,8 +27,12 @@ export default function useAvailableColumns() {
sortingFn: liquiditySortingFn, sortingFn: liquiditySortingFn,
}, },
{ {
...MANAGE_META, ...BORROW_BUTTON_META,
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <BorrowButton data={row.original} />,
},
{
...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, []) }, [])
@@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate' import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate'
import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt' import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt'
import Liquidity, { import Liquidity, {
LIQUIDITY_META, LIQUIDITY_META,
@@ -33,7 +34,11 @@ export default function useDepositedColumns() {
}, },
{ {
...MANAGE_META, ...MANAGE_META,
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <Manage data={row.original} />,
},
{
...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, []) }, [])
@@ -1,12 +1,10 @@
import { Row } from '@tanstack/react-table' import { Row } from '@tanstack/react-table'
import { useCallback } from 'react' import { useCallback } from 'react'
import BorrowActionButtons from 'components/borrow/BorrowActionButtons'
import { NAME_META } from 'components/borrow/Table/Columns/Name' import { NAME_META } from 'components/borrow/Table/Columns/Name'
import useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns' import useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns'
import MarketDetails from 'components/common/MarketDetails' import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
type Props = { type Props = {
data: BorrowMarketTableData[] data: BorrowMarketTableData[]
@@ -17,15 +15,7 @@ export default function DepositedBorrowingsTable(props: Props) {
const columns = useDepositedColumns() const columns = useDepositedColumns()
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => { const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
const currentRow = row as Row<BorrowMarketTableData> return <MarketDetails row={row} type='borrow' />
return (
<>
<ActionButtonRow row={currentRow}>
<BorrowActionButtons data={row.original} />
</ActionButtonRow>
<MarketDetails row={row} type='borrow' />
</>
)
}, []) }, [])
if (!props.data.length) return null if (!props.data.length) return null
+42 -11
View File
@@ -1,12 +1,16 @@
import classNames from 'classnames'
import Button from 'components/common/Button/index' import Button from 'components/common/Button/index'
import { ChevronDown } from 'components/common/Icons' import { ChevronDown } from 'components/common/Icons'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip' import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
interface Props extends ButtonProps { interface Props extends ButtonProps {
items: DropDownItem[] items: DropDownItem[]
text: string text: string
showProgressIndicator?: boolean
} }
export default function DropDownButton(props: Props) { export default function DropDownButton(props: Props) {
@@ -16,16 +20,20 @@ export default function DropDownButton(props: Props) {
content={<DropDown closeMenu={() => toggleIsOpen(false)} {...props} />} content={<DropDown closeMenu={() => toggleIsOpen(false)} {...props} />}
type='info' type='info'
placement='bottom' placement='bottom'
contentClassName='!bg-white/10 backdrop-blur-xl !p-0' contentClassName='!bg-white/10 backdrop-blur-xl !p-0 w-full min-w-[140px]'
interactive interactive
hideArrow hideArrow
visible={isOpen} visible={isOpen}
onClickOutside={() => toggleIsOpen(false)} onClickOutside={() => toggleIsOpen(false)}
> >
<Button <Button
onClick={() => toggleIsOpen()} onClick={(e) => {
toggleIsOpen()
e.stopPropagation()
}}
rightIcon={<ChevronDown />} rightIcon={<ChevronDown />}
iconClassName='w-3 h-3' iconClassName='w-3 h-3'
showProgressIndicator={props.showProgressIndicator}
{...props} {...props}
/> />
</Tooltip> </Tooltip>
@@ -39,7 +47,7 @@ interface DropDownProps {
function DropDown(props: DropDownProps) { function DropDown(props: DropDownProps) {
return ( return (
<div> <div className='w-full'>
{props.items.map((item) => ( {props.items.map((item) => (
<DropDownItem key={item.text} item={item} closeMenu={props.closeMenu} /> <DropDownItem key={item.text} item={item} closeMenu={props.closeMenu} />
))} ))}
@@ -54,15 +62,38 @@ interface DropDownItemProps {
function DropDownItem(props: DropDownItemProps) { function DropDownItem(props: DropDownItemProps) {
return ( return (
<button <ConditionalWrapper
onClick={() => { condition={!!props.item.disabled}
props.item.onClick() wrapper={(children) => {
props.closeMenu() if (!props.item.disabledTooltip) return children
return (
<Tooltip
type='warning'
content={<Text size='sm'>{props.item.disabledTooltip}</Text>}
contentClassName='max-w-[200px]'
className='ml-auto'
>
{children}
</Tooltip>
)
}} }}
className=' px-4 py-3 flex gap-2 items-center hover:bg-white/5 w-full [&:not(:last-child)]:border-b border-white/10'
> >
<div className='flex justify-center w-5 h-5'>{props.item.icon}</div> <button
<Text size='sm'>{props.item.text}</Text> onClick={(e) => {
</button> e.preventDefault()
props.item.onClick()
props.closeMenu()
e.stopPropagation()
}}
className={classNames(
'z-1 px-4 py-3 flex gap-2 items-center w-full [&:not(:last-child)]:border-b border-white/10',
props.item.disabled ? 'bg-black/20 text-white/40 cursor-events-none' : 'hover:bg-white/5',
)}
disabled={props.item.disabled}
>
<div className='flex justify-center w-4 h-4'>{props.item.icon}</div>
<Text size='sm'>{props.item.text}</Text>
</button>
</ConditionalWrapper>
) )
} }
+5 -1
View File
@@ -18,7 +18,11 @@ export default function DepositCapMessage(props: Props) {
return ( return (
<div className={classNames('flex items-start', props.className)}> <div className={classNames('flex items-start', props.className)}>
{props.showIcon && <InfoCircle width={26} className='mr-5' />} {props.showIcon && (
<div className='w-6 mr-5'>
<InfoCircle />
</div>
)}
<div className='flex flex-col gap-2'> <div className='flex flex-col gap-2'>
<Text size='sm'>Deposit Cap Reached!</Text> <Text size='sm'>Deposit Cap Reached!</Text>
<Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${ <Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${
+7 -2
View File
@@ -10,6 +10,7 @@ interface Props<T> {
className?: string className?: string
isSelectable?: boolean isSelectable?: boolean
type?: TableType type?: TableType
onClick?: (id: string) => void
} }
function getBorderColor( function getBorderColor(
@@ -36,7 +37,7 @@ export default function Row<T>(props: Props<T>) {
key={`${row.id}-row`} key={`${row.id}-row`}
className={classNames( className={classNames(
'group/row transition-bg', 'group/row transition-bg',
(renderExpanded || isSelectable) && 'hover:cursor-pointer', (renderExpanded || isSelectable || props.onClick) && 'hover:cursor-pointer',
canExpand && row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5', canExpand && row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5',
)} )}
onClick={(e) => { onClick={(e) => {
@@ -49,6 +50,10 @@ export default function Row<T>(props: Props<T>) {
table.resetExpanded() table.resetExpanded()
!isExpanded && row.toggleExpanded() !isExpanded && row.toggleExpanded()
} }
if (props.onClick) {
props.onClick((row.original as any).asset.denom)
}
}} }}
> >
{row.getVisibleCells().map((cell) => { {row.getVisibleCells().map((cell) => {
@@ -61,7 +66,7 @@ export default function Row<T>(props: Props<T>) {
spacingClassName ?? 'px-3 py-4', spacingClassName ?? 'px-3 py-4',
type && type !== 'strategies' && isSymbolOrName && 'border-l', type && type !== 'strategies' && isSymbolOrName && 'border-l',
type && type !== 'strategies' && getBorderColor(type, cell.row.original as any), type && type !== 'strategies' && getBorderColor(type, cell.row.original as any),
cell.column.columnDef.meta?.className, cell.column.columnDef.meta?.className ?? 'w-min',
)} )}
> >
{flexRender(cell.column.columnDef.cell, cell.getContext())} {flexRender(cell.column.columnDef.cell, cell.getContext())}
+3
View File
@@ -31,6 +31,7 @@ interface Props<T> {
hideCard?: boolean hideCard?: boolean
setRowSelection?: OnChangeFn<RowSelectionState> setRowSelection?: OnChangeFn<RowSelectionState>
selectedRows?: RowSelectionState selectedRows?: RowSelectionState
onClickRow?: (id: string) => void
} }
export default function Table<T>(props: Props<T>) { export default function Table<T>(props: Props<T>) {
@@ -75,6 +76,7 @@ export default function Table<T>(props: Props<T>) {
props.spacingClassName ?? 'px-4 py-3', props.spacingClassName ?? 'px-4 py-3',
header.column.getCanSort() && 'hover:cursor-pointer', header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right', header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right',
'w-min',
header.column.columnDef.meta?.className, header.column.columnDef.meta?.className,
)} )}
> >
@@ -122,6 +124,7 @@ export default function Table<T>(props: Props<T>) {
spacingClassName={props.spacingClassName} spacingClassName={props.spacingClassName}
isSelectable={!!props.setRowSelection} isSelectable={!!props.setRowSelection}
type={props.type} type={props.type}
onClick={props.onClickRow}
/> />
))} ))}
</tbody> </tbody>
@@ -16,9 +16,9 @@ export default function TooltipContent(props: Props) {
<div> <div>
<div <div
className={classNames( className={classNames(
'flex max-w-[320px] flex-1 gap-2 rounded-lg p-3 text-sm shadow-tooltip backdrop-blur-[100px]', 'flex max-w-[320px] flex-1 gap-2 rounded-base p-3 text-sm shadow-tooltip backdrop-blur-[100px]',
'relative isolate max-w-full overflow-hidden', 'relative isolate max-w-full overflow-hidden',
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-lg before:p-[1px] before:border-glas', 'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
props.type === 'info' && 'bg-white/10', props.type === 'info' && 'bg-white/10',
props.type === 'warning' && 'bg-warning', props.type === 'warning' && 'bg-warning',
props.type === 'error' && 'bg-error', props.type === 'error' && 'bg-error',
+2 -2
View File
@@ -48,7 +48,7 @@ export const Tooltip = (props: Props) => {
visible={props.visible} visible={props.visible}
> >
{props.children ? ( {props.children ? (
<span <div
className={classNames( className={classNames(
props.underline && props.underline &&
'border-b hover:cursor-help border-dashed border-white/20 pb-1 hover:border-transparent', 'border-b hover:cursor-help border-dashed border-white/20 pb-1 hover:border-transparent',
@@ -57,7 +57,7 @@ export const Tooltip = (props: Props) => {
)} )}
> >
{props.children} {props.children}
</span> </div>
) : ( ) : (
<span <span
className={classNames( className={classNames(
@@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import ActionButton from 'components/common/Button/ActionButton' import ActionButton from 'components/common/Button/ActionButton'
import { Plus } from 'components/common/Icons'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import useStore from 'store' import useStore from 'store'
@@ -9,6 +10,8 @@ interface Props {
isLoading: boolean isLoading: boolean
} }
export const DEPOSIT_META = { accessorKey: 'deposit', enableSorting: false, header: '' }
export const Deposit = (props: Props) => { export const Deposit = (props: Props) => {
const { vault } = props const { vault } = props
@@ -26,7 +29,12 @@ export const Deposit = (props: Props) => {
return ( return (
<div className='flex items-center justify-end'> <div className='flex items-center justify-end'>
<ActionButton onClick={enterVaultHandler} color='tertiary' text='Deposit' /> <ActionButton
onClick={enterVaultHandler}
color='tertiary'
text='Deposit'
leftIcon={<Plus />}
/>
</div> </div>
) )
} }
@@ -1,24 +0,0 @@
import classNames from 'classnames'
import React from 'react'
import { ChevronDown } from 'components/common/Icons'
import Loading from 'components/common/Loading'
export const DETAILS_META = { accessorKey: 'details', enableSorting: false, header: 'Deposit' }
interface Props {
isLoading: boolean
isExpanded: boolean
}
export default function Details(props: Props) {
if (props.isLoading) return <Loading />
return (
<div className='flex items-center justify-end'>
<div className={classNames('w-4', props.isExpanded && 'rotate-180')}>
<ChevronDown />
</div>
</div>
)
}
@@ -0,0 +1,116 @@
import moment from 'moment/moment'
import React, { useCallback, useMemo, useState } from 'react'
import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons'
import Loading from 'components/common/Loading'
import { VaultStatus } from 'types/enums/vault'
import { DEFAULT_SETTINGS } from '../../../../../constants/defaultSettings'
import { LocalStorageKeys } from '../../../../../constants/localStorageKeys'
import useLocalStorage from '../../../../../hooks/localStorage/useLocalStorage'
import useAccountId from '../../../../../hooks/useAccountId'
import useStore from '../../../../../store'
import DropDownButton from '../../../../common/Button/DropDownButton'
export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' }
interface Props {
vault: DepositedVault
isLoading: boolean
isExpanded: boolean
}
export default function Manage(props: Props) {
const accountId = useAccountId()
const address = useStore((s) => s.address)
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
const [isConfirming, setIsConfirming] = useState(false)
const depositMoreHandler = useCallback(() => {
useStore.setState({
vaultModal: {
vault: props.vault,
isDeposited: true,
selectedBorrowDenoms: [props.vault.denoms.secondary],
isCreate: false,
},
})
}, [props.vault])
const unlockHandler = useCallback(
() => useStore.setState({ unlockModal: { vault: props.vault } }),
[props.vault],
)
const withdrawHandler = useCallback(async () => {
if (!accountId) return
setIsConfirming(true)
await withdrawFromVaults({
accountId: accountId,
vaults: [props.vault],
slippage,
})
}, [accountId, props.vault, slippage, withdrawFromVaults])
const ITEMS: DropDownItem[] = useMemo(
() => [
{
icon: <Plus />,
text: 'Deposit more',
onClick: depositMoreHandler,
},
...(props.vault.status === VaultStatus.ACTIVE
? [
{
icon: <LockUnlocked />,
text: 'Unlock to withdraw',
onClick: unlockHandler,
},
]
: []),
...(props.vault.status === VaultStatus.UNLOCKING
? [
{
icon: <LockLocked />,
text: `Withdraw in ${moment(props.vault?.unlocksAt).fromNow(true)}`,
onClick: () => {},
disabled: true,
disabledTooltip: '',
},
]
: []),
...(props.vault.status === VaultStatus.UNLOCKED
? [
{
icon: <AccountArrowDown />,
text: 'Withdraw funds',
onClick: withdrawHandler,
},
]
: []),
],
[
depositMoreHandler,
props.vault.status,
props.vault?.unlocksAt,
unlockHandler,
withdrawHandler,
],
)
if (props.isLoading) return <Loading />
if (!address) return null
return (
<div className='flex justify-end z-10'>
<DropDownButton
items={ITEMS}
text='Manage'
color='tertiary'
showProgressIndicator={isConfirming}
/>
</div>
)
}
@@ -2,7 +2,6 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
import { Deposit } from 'components/earn/farm/Table/Columns/Deposit'
import DepositCap, { import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
depositCapSortingFn, depositCapSortingFn,
@@ -10,7 +9,8 @@ import DepositCap, {
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL' import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
import { DETAILS_META } from 'components/earn/farm/Table/Columns/Details'
import { Deposit, DEPOSIT_META } from './Deposit'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
@@ -41,7 +41,7 @@ export default function useAvailableColumns(props: Props) {
cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />, cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />,
}, },
{ {
...DETAILS_META, ...DEPOSIT_META,
cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />, cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />,
}, },
] ]
@@ -6,7 +6,7 @@ import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
depositCapSortingFn, depositCapSortingFn,
} from 'components/earn/farm/Table/Columns/DepositCap' } from 'components/earn/farm/Table/Columns/DepositCap'
import Details, { DETAILS_META } from 'components/earn/farm/Table/Columns/Details' import Manage, { MANAGE_META } from 'components/earn/farm/Table/Columns/Manage'
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import PositionValue, { import PositionValue, {
@@ -55,8 +55,14 @@ export default function useDepositedColumns(props: Props) {
), ),
}, },
{ {
...DETAILS_META, ...MANAGE_META,
cell: ({ row }) => <Details isLoading={props.isLoading} isExpanded={row.getIsExpanded()} />, cell: ({ row }) => (
<Manage
vault={row.original}
isLoading={props.isLoading}
isExpanded={row.getIsExpanded()}
/>
),
}, },
] ]
}, [props.isLoading]) }, [props.isLoading])
@@ -1,10 +1,7 @@
import { Row } from '@tanstack/react-table' import React from 'react'
import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
import React, { useCallback } from 'react'
import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
import VaultExpanded from 'components/earn/farm/VaultExpanded'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
type Props = { type Props = {
data: DepositedVault[] data: DepositedVault[]
@@ -14,20 +11,12 @@ type Props = {
export default function DepositedVaultsTable(props: Props) { export default function DepositedVaultsTable(props: Props) {
const columns = useDepositedColumns({ isLoading: props.isLoading }) const columns = useDepositedColumns({ isLoading: props.isLoading })
const renderExpanded = useCallback(
(row: Row<DepositedVault>, table: TanStackTable<DepositedVault>) => (
<VaultExpanded row={row} resetExpanded={table.resetExpanded} />
),
[],
)
return ( return (
<Table <Table
title='Deposited Vaults' title='Deposited Vaults'
columns={columns} columns={columns}
data={props.data} data={props.data}
initialSorting={[{ id: 'name', desc: true }]} initialSorting={[{ id: 'name', desc: true }]}
renderExpanded={renderExpanded}
/> />
) )
} }
@@ -1,98 +0,0 @@
import { useCallback } from 'react'
import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent'
import Button from 'components/common/Button'
import ActionButton from 'components/common/Button/ActionButton'
import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useAccountId from 'hooks/useAccountId'
import useAlertDialog from 'hooks/useAlertDialog'
import useAutoLend from 'hooks/useAutoLend'
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import useStore from 'store'
import { byDenom } from 'utils/array'
interface Props {
data: LendingMarketTableData
}
const buttonClassnames = 'm-0 flex w-40'
const iconClassnames = 'ml-0 mr-1 w-4 h-4'
export default function LendingActionButtons(props: Props) {
const { asset, accountLentValue: accountLendValue } = props.data
const accountDeposits = useCurrentAccountDeposits()
const { openLend, openReclaim } = useLendAndReclaimModal()
const { open: showAlertDialog } = useAlertDialog()
const { isAutoLendEnabledForCurrentAccount } = useAutoLend()
const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount
const address = useStore((s) => s.address)
const accountId = useAccountId()
const hasNoDeposit = !!(!assetDepositAmount && address && accountId)
const handleUnlend = useCallback(() => {
if (isAutoLendEnabledForCurrentAccount) {
showAlertDialog({
icon: <ExclamationMarkCircled width={18} />,
title: 'Disable Automatically Lend Assets',
content:
"Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.",
positiveButton: {
onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(),
text: 'Continue to Account Settings',
icon: <Enter />,
},
negativeButton: {
text: 'Cancel',
},
})
return
}
openReclaim(props.data)
}, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog])
return (
<div className='flex flex-row space-x-2'>
{accountLendValue && accountLendValue.isGreaterThan(0) && (
<Button
leftIcon={<ArrowDownLine />}
iconClassName={iconClassnames}
color='secondary'
onClick={handleUnlend}
className={buttonClassnames}
>
Unlend
</Button>
)}
<ConditionalWrapper
condition={hasNoDeposit}
wrapper={(children) => (
<Tooltip
type='warning'
content={
<Text size='sm'>{`You dont have any ${asset.symbol}. Please first deposit ${asset.symbol} into your Credit Account before lending.`}</Text>
}
>
{children}
</Tooltip>
)}
>
<ActionButton
leftIcon={<ArrowUpLine />}
iconClassName={iconClassnames}
disabled={hasNoDeposit}
color='secondary'
onClick={() => openLend(props.data)}
className={buttonClassnames}
text='Lend'
/>
</ConditionalWrapper>
</div>
)
}
@@ -1,12 +1,10 @@
import { Row } from '@tanstack/react-table' import { Row } from '@tanstack/react-table'
import { useCallback } from 'react' import { useCallback } from 'react'
import LendingActionButtons from 'components/earn/lend/LendingActionButtons'
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
import MarketDetails from 'components/common/MarketDetails' import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import ActionButtonRow from 'components/common/Table/ActionButtonRow' import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
type Props = { type Props = {
data: LendingMarketTableData[] data: LendingMarketTableData[]
@@ -19,9 +17,6 @@ export default function AvailableLendsTable(props: Props) {
const renderExpanded = useCallback( const renderExpanded = useCallback(
(row: Row<LendingMarketTableData>) => ( (row: Row<LendingMarketTableData>) => (
<> <>
<ActionButtonRow row={row}>
<LendingActionButtons data={row.original} />
</ActionButtonRow>
<MarketDetails row={row} type='lend' /> <MarketDetails row={row} type='lend' />
</> </>
), ),
@@ -0,0 +1,21 @@
import { ChevronDown, ChevronUp } from 'components/common/Icons'
export const CHEVRON_META = {
id: 'chevron',
enableSorting: false,
header: '',
meta: {
className: 'w-5',
},
}
interface Props {
isExpanded: boolean
}
export default function Chevron(props: Props) {
return (
<div className='flex items-center justify-end'>
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
</div>
)
}
@@ -10,7 +10,6 @@ export const DEPOSIT_CAP_META = {
accessorKey: 'marketDepositCap', accessorKey: 'marketDepositCap',
header: 'Deposit Cap', header: 'Deposit Cap',
id: 'marketDepositCap', id: 'marketDepositCap',
meta: { className: 'w-40' },
} }
export const marketDepositCapSortingFn = ( export const marketDepositCapSortingFn = (
@@ -0,0 +1,60 @@
import ActionButton from 'components/common/Button/ActionButton'
import { ArrowUpLine } from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useAccountId from 'hooks/useAccountId'
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import useStore from 'store'
import { byDenom } from 'utils/array'
export const LEND_BUTTON_META = {
accessorKey: 'lend',
enableSorting: false,
header: '',
}
interface Props {
data: LendingMarketTableData
}
export default function LendButton(props: Props) {
const { openLend } = useLendAndReclaimModal()
const accountDeposits = useCurrentAccountDeposits()
const assetDepositAmount = accountDeposits.find(byDenom(props.data.asset.denom))?.amount
const address = useStore((s) => s.address)
const accountId = useAccountId()
const hasNoDeposit = !!(!assetDepositAmount && address && accountId)
return (
<div className='flex justify-end'>
<ConditionalWrapper
condition={hasNoDeposit}
wrapper={(children) => (
<Tooltip
type='warning'
content={
<Text size='sm'>{`You dont have any ${props.data.asset.symbol}.
Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`}</Text>
}
contentClassName='max-w-[200px]'
className='ml-auto'
>
{children}
</Tooltip>
)}
>
<ActionButton
leftIcon={<ArrowUpLine />}
disabled={hasNoDeposit}
color='tertiary'
onClick={(e) => {
openLend(props.data)
e.stopPropagation()
}}
text='Lend'
/>
</ConditionalWrapper>
</div>
)
}
@@ -1,21 +1,82 @@
import { ChevronDown, ChevronUp } from 'components/common/Icons' import { useCallback, useMemo } from 'react'
import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent'
import DropDownButton from 'components/common/Button/DropDownButton'
import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAlertDialog from 'hooks/useAlertDialog'
import useAutoLend from 'hooks/useAutoLend'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import useStore from 'store'
export const MANAGE_META = { export const MANAGE_META = {
accessorKey: 'manage', accessorKey: 'manage',
enableSorting: false, enableSorting: false,
header: 'Manage', header: '',
meta: {
className: 'w-30',
},
} }
interface Props { interface Props {
isExpanded: boolean data: LendingMarketTableData
} }
export default function Manage(props: Props) { export default function Manage(props: Props) {
const { openLend, openReclaim } = useLendAndReclaimModal()
const { isAutoLendEnabledForCurrentAccount } = useAutoLend()
const { open: showAlertDialog } = useAlertDialog()
const address = useStore((s) => s.address)
const account = useCurrentAccount()
const hasAssetInDeposits = useMemo(
() => !!account?.deposits?.find((deposit) => deposit.denom === props.data.asset.denom),
[account?.deposits, props.data.asset.denom],
)
const handleUnlend = useCallback(() => {
if (isAutoLendEnabledForCurrentAccount) {
showAlertDialog({
icon: <ExclamationMarkCircled width={18} />,
title: 'Disable Automatically Lend Assets',
content:
"Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.",
positiveButton: {
onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(),
text: 'Continue to Account Settings',
icon: <Enter />,
},
negativeButton: {
text: 'Cancel',
},
})
return
}
openReclaim(props.data)
}, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog])
const ITEMS: DropDownItem[] = useMemo(
() => [
{
icon: <ArrowUpLine />,
text: 'Lend more',
onClick: () => openLend(props.data),
disabled: !hasAssetInDeposits,
disabledTooltip: `You dont have any ${props.data.asset.symbol}.
Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`,
},
{
icon: <ArrowDownLine />,
text: 'Unlend',
onClick: handleUnlend,
},
],
[handleUnlend, hasAssetInDeposits, openLend, props.data],
)
if (!address) return null
return ( return (
<div className='flex items-center justify-end'> <div className='flex justify-end z-10'>
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div> <DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div> </div>
) )
} }
@@ -2,11 +2,12 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
import DepositCap, { import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
marketDepositCapSortingFn, marketDepositCapSortingFn,
} from 'components/earn/lend/Table/Columns/DepositCap' } from 'components/earn/lend/Table/Columns/DepositCap'
import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage' import LendButton, { LEND_BUTTON_META } from 'components/earn/lend/Table/Columns/LendButton'
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
interface Props { interface Props {
@@ -36,8 +37,12 @@ export default function useAvailableColumns(props: Props) {
sortingFn: marketDepositCapSortingFn, sortingFn: marketDepositCapSortingFn,
}, },
{ {
...MANAGE_META, ...LEND_BUTTON_META,
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <LendButton data={row.original} />,
},
{
...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, [props.isLoading]) }, [props.isLoading])
@@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
import DepositCap, { import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
marketDepositCapSortingFn, marketDepositCapSortingFn,
@@ -48,7 +49,11 @@ export default function useDepositedColumns(props: Props) {
}, },
{ {
...MANAGE_META, ...MANAGE_META,
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <Manage data={row.original} />,
},
{
...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, [props.isLoading]) }, [props.isLoading])
@@ -1,12 +1,10 @@
import { Row } from '@tanstack/react-table' import { Row } from '@tanstack/react-table'
import { useCallback } from 'react' import { useCallback } from 'react'
import LendingActionButtons from 'components/earn/lend/LendingActionButtons'
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
import MarketDetails from 'components/common/MarketDetails' import MarketDetails from 'components/common/MarketDetails'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import ActionButtonRow from 'components/common/Table/ActionButtonRow' import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
type Props = { type Props = {
data: LendingMarketTableData[] data: LendingMarketTableData[]
@@ -17,14 +15,7 @@ export default function DepositedLendsTable(props: Props) {
const columns = useDepositedColumns({ isLoading: props.isLoading }) const columns = useDepositedColumns({ isLoading: props.isLoading })
const renderExpanded = useCallback( const renderExpanded = useCallback(
(row: Row<LendingMarketTableData>) => ( (row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
<>
<ActionButtonRow row={row}>
<LendingActionButtons data={row.original} />
</ActionButtonRow>
<MarketDetails row={row} type='lend' />
</>
),
[], [],
) )
@@ -14,7 +14,7 @@ type Props = {
export default function PnL(props: Props) { export default function PnL(props: Props) {
return ( return (
<Tooltip content={<PnLTooltip {...props} />} type='info' underline> <Tooltip content={<PnLTooltip {...props} />} type='info' underline className='w-min ml-auto'>
<DisplayCurrency <DisplayCurrency
className='inline text-xs' className='inline text-xs'
coin={props.pnl.net} coin={props.pnl.net}
+27 -2
View File
@@ -1,10 +1,35 @@
import { useCallback } from 'react'
import { useSearchParams } from 'react-router-dom'
import Table from 'components/common/Table'
import usePerpsBalancesColumns from 'components/perps/BalancesTable/Columns/usePerpsBalancesColumns' import usePerpsBalancesColumns from 'components/perps/BalancesTable/Columns/usePerpsBalancesColumns'
import usePerpsBalancesData from 'components/perps/BalancesTable/usePerpsBalancesData' import usePerpsBalancesData from 'components/perps/BalancesTable/usePerpsBalancesData'
import Table from 'components/common/Table' import { SearchParams } from 'types/enums/searchParams'
import { getSearchParamsObject } from 'utils/route'
export default function PerpsBalancesTable() { export default function PerpsBalancesTable() {
const data = usePerpsBalancesData() const data = usePerpsBalancesData()
const columns = usePerpsBalancesColumns() const columns = usePerpsBalancesColumns()
const [searchParams, setSearchParams] = useSearchParams()
return <Table title='Perp Positions' columns={columns} data={data} initialSorting={[]} /> const onClickRow = useCallback(
(denom: string) => {
const params = getSearchParamsObject(searchParams)
setSearchParams({
...params,
[SearchParams.PERPS_MARKET]: denom,
})
},
[searchParams, setSearchParams],
)
return (
<Table
title='Perp Positions'
columns={columns}
data={data}
initialSorting={[]}
onClickRow={onClickRow}
/>
)
} }
+1 -1
View File
@@ -104,7 +104,7 @@ export function PerpsModule() {
/> />
<AssetAmountInput <AssetAmountInput
label='Amount' label='Amount'
max={BN(100000000)} // TODO: Implement max calculation max={BN(10000000000)} // TODO: Implement max calculation
amount={amount.abs()} amount={amount.abs()}
setAmount={onChangeAmount} setAmount={onChangeAmount}
asset={perpsAsset} asset={perpsAsset}
+9 -1
View File
@@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'
import { CircularProgress } from 'components/common/CircularProgress' import { CircularProgress } from 'components/common/CircularProgress'
import DisplayCurrency from 'components/common/DisplayCurrency' import DisplayCurrency from 'components/common/DisplayCurrency'
import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice' import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice'
import { BNCoin } from 'types/classes/BNCoin'
type Props = { type Props = {
denom: string denom: string
@@ -20,5 +21,12 @@ export default function TradingFee(props: Props) {
if (isLoading) return <CircularProgress className='h-full' size={12} /> if (isLoading) return <CircularProgress className='h-full' size={12} />
if (props.newAmount.isEqualTo(props.previousAmount) || !tradingFeeAndPrice?.fee) return '-' if (props.newAmount.isEqualTo(props.previousAmount) || !tradingFeeAndPrice?.fee) return '-'
return <DisplayCurrency coin={tradingFeeAndPrice.fee} /> return (
<DisplayCurrency
coin={BNCoin.fromDenomAndBigNumber(
tradingFeeAndPrice.baseDenom,
tradingFeeAndPrice.fee.opening.plus(tradingFeeAndPrice.fee.closing),
)}
/>
)
} }
@@ -19,7 +19,9 @@ export default function PortfolioAccountPageHeader(props: Props) {
<NavLink to={getRoute('portfolio', searchParams, address, selectedAccountId)}> <NavLink to={getRoute('portfolio', searchParams, address, selectedAccountId)}>
<Text className='text-white/40'>Portfolio</Text> <Text className='text-white/40'>Portfolio</Text>
</NavLink> </NavLink>
<ArrowRight className='h-3 text-white/60 ' /> <div className='h-3'>
<ArrowRight className='h-3 text-white/60 ' />
</div>
<Text tag='span'>Credit Account {props.accountId}</Text> <Text tag='span'>Credit Account {props.accountId}</Text>
</div> </div>
) )
+2 -2
View File
@@ -2,9 +2,9 @@ import React from 'react'
import HealthBar from 'components/account/Health/HealthBar' import HealthBar from 'components/account/Health/HealthBar'
import Card from 'components/common/Card' import Card from 'components/common/Card'
import HLSTag from 'components/hls/HLSTag'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import TitleAndSubCell from 'components/common/TitleAndSubCell' import TitleAndSubCell from 'components/common/TitleAndSubCell'
import HLSTag from 'components/hls/HLSTag'
interface Props { interface Props {
stats: { title: React.ReactNode; sub: string }[] stats: { title: React.ReactNode; sub: string }[]
@@ -33,7 +33,7 @@ export default function Skeleton(props: Props) {
<TitleAndSubCell key={`${accountId}-${sub}`} title={title} sub={sub} /> <TitleAndSubCell key={`${accountId}-${sub}`} title={title} sub={sub} />
))} ))}
</div> </div>
<div className='flex gap-1 mt-6'> <div className='flex mt-6'>
<HealthBar health={health} healthFactor={healthFactor} showIcon /> <HealthBar health={health} healthFactor={healthFactor} showIcon />
</div> </div>
</Card> </Card>
+6 -4
View File
@@ -3,10 +3,10 @@ import React from 'react'
import HealthBar from 'components/account/Health/HealthBar' import HealthBar from 'components/account/Health/HealthBar'
import HealthIcon from 'components/account/Health/HealthIcon' import HealthIcon from 'components/account/Health/HealthIcon'
import Card from 'components/common/Card' import Card from 'components/common/Card'
import HLSTag from 'components/hls/HLSTag'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import TitleAndSubCell from 'components/common/TitleAndSubCell' import TitleAndSubCell from 'components/common/TitleAndSubCell'
import HLSTag from 'components/hls/HLSTag'
import useAccount from 'hooks/accounts/useAccount' import useAccount from 'hooks/accounts/useAccount'
import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants' import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'
@@ -31,9 +31,11 @@ export default function SummarySkeleton(props: Props) {
{account?.kind === 'high_levered_strategy' && <HLSTag />} {account?.kind === 'high_levered_strategy' && <HLSTag />}
</div> </div>
{health !== undefined && healthFactor !== undefined && ( {health !== undefined && healthFactor !== undefined && (
<div className='flex gap-1 max-w-[300px] flex-grow'> <div className='flex items-center justify-end flex-grow gap-2'>
<HealthIcon isLoading={healthFactor === 0} health={health} className='w-5' /> <HealthIcon isLoading={healthFactor === 0} health={health} />
<HealthBar health={health} healthFactor={healthFactor} className='h-full' /> <div className='w-[260px]'>
<HealthBar health={health} healthFactor={healthFactor} className='h-3' />
</div>
</div> </div>
)} )}
</div> </div>
+15
View File
@@ -0,0 +1,15 @@
const stDYDX: AssetMetaData = {
symbol: 'stDYDX',
id: 'stDYDX',
name: 'Stride dYdX',
color: '#e50571',
logo: '/images/tokens/stdydx.svg',
decimals: 18,
hasOraclePrice: true,
isEnabled: true,
isMarket: true,
isDisplayCurrency: true,
isAutoLendEnabled: false,
isStaking: true,
}
export default stDYDX
+18 -12
View File
@@ -5,23 +5,24 @@ import ATOM from 'configs/assets/ATOM'
import AXL from 'configs/assets/AXL' import AXL from 'configs/assets/AXL'
import DYDX from 'configs/assets/DYDX' import DYDX from 'configs/assets/DYDX'
import INJ from 'configs/assets/INJ' import INJ from 'configs/assets/INJ'
import MARS from 'configs/assets/MARS'
import OSMO from 'configs/assets/OSMO'
import TIA from 'configs/assets/TIA'
import USDC from 'configs/assets/USDC'
import USDCaxl from 'configs/assets/USDC.axl'
import USDT from 'configs/assets/USDT'
import USDollar from 'configs/assets/USDollar'
import WBTCaxl from 'configs/assets/WBTC.axl'
import WETHaxl from 'configs/assets/WETH.xal'
import OSMO_ATOM from 'configs/assets/lp/OSMO-ATOM' import OSMO_ATOM from 'configs/assets/lp/OSMO-ATOM'
import OSMO_USDC from 'configs/assets/lp/OSMO_USDC' import OSMO_USDC from 'configs/assets/lp/OSMO_USDC'
import OSMO_WBTC from 'configs/assets/lp/OSMO_WBTC' import OSMO_WBTC from 'configs/assets/lp/OSMO_WBTC'
import OSMO_WETH from 'configs/assets/lp/OSMO_WETH' import OSMO_WETH from 'configs/assets/lp/OSMO_WETH'
import stATOM_ATOM from 'configs/assets/lp/stATOM_ATOM' import stATOM_ATOM from 'configs/assets/lp/stATOM_ATOM'
import MARS from 'configs/assets/MARS'
import milkTIA from 'configs/assets/milkTIA' import milkTIA from 'configs/assets/milkTIA'
import OSMO from 'configs/assets/OSMO'
import stATOM from 'configs/assets/stATOM' import stATOM from 'configs/assets/stATOM'
import stDYDX from 'configs/assets/stDYDX'
import stOSMO from 'configs/assets/stOSMO' import stOSMO from 'configs/assets/stOSMO'
import TIA from 'configs/assets/TIA'
import USDC from 'configs/assets/USDC'
import USDCaxl from 'configs/assets/USDC.axl'
import USDollar from 'configs/assets/USDollar'
import USDT from 'configs/assets/USDT'
import WBTCaxl from 'configs/assets/WBTC.axl'
import WETHaxl from 'configs/assets/WETH.xal'
import { VAULTS_META_DATA } from 'constants/vaults' import { VAULTS_META_DATA } from 'constants/vaults'
import { NETWORK } from 'types/enums/network' import { NETWORK } from 'types/enums/network'
import { ChainInfoID } from 'types/enums/wallet' import { ChainInfoID } from 'types/enums/wallet'
@@ -45,15 +46,20 @@ const ASSETS = [
poolId: 712, poolId: 712,
denom: 'ibc/D1542AA8762DB13087D8364F3EA6509FD6F009A34F00426AF9E4F9FA85CBBF1F', denom: 'ibc/D1542AA8762DB13087D8364F3EA6509FD6F009A34F00426AF9E4F9FA85CBBF1F',
}, },
{
...stATOM,
poolId: 803,
denom: 'ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901',
},
{ {
...stOSMO, ...stOSMO,
poolId: 833, poolId: 833,
denom: 'ibc/D176154B0C63D1F9C6DCFB4F70349EBF2E2B5A87A05902F57A6AE92B863E9AEC', denom: 'ibc/D176154B0C63D1F9C6DCFB4F70349EBF2E2B5A87A05902F57A6AE92B863E9AEC',
}, },
{ {
...stATOM, ...stDYDX,
poolId: 803, poolId: 1423,
denom: 'ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901', denom: 'ibc/980E82A9F8E7CA8CD480F4577E73682A6D3855A267D1831485D7EBEF0E7A6C2C',
}, },
{ {
...USDCaxl, ...USDCaxl,
+12 -14
View File
@@ -6,7 +6,6 @@ import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients' import useClients from 'hooks/useClients'
import useDebounce from 'hooks/useDebounce' import useDebounce from 'hooks/useDebounce'
import { BNCoin } from 'types/classes/BNCoin'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
export default function useTradingFeeAndPrice( export default function useTradingFeeAndPrice(
@@ -34,14 +33,15 @@ export default function useTradingFeeAndPrice(
}) })
return { return {
baseDenom: positionFees.base_denom,
price: positionFees.opening_exec_price price: positionFees.opening_exec_price
? BN(positionFees.opening_exec_price) ? BN(positionFees.opening_exec_price)
: BN(positionFees.closing_exec_price ?? BN_ZERO), : BN(positionFees.closing_exec_price ?? BN_ZERO),
fee: BNCoin.fromDenomAndBigNumber( fee: {
positionFees.base_denom, opening: BN(positionFees.opening_fee),
BN(positionFees.opening_fee).plus(positionFees.closing_fee), closing: BN(positionFees.closing_fee),
), },
rate: BN(0.005), rate: BN(0.0005),
} }
} }
@@ -61,15 +61,13 @@ export default function useTradingFeeAndPrice(
return await Promise.all([closingPositionFees$, openingPositionFees$]).then( return await Promise.all([closingPositionFees$, openingPositionFees$]).then(
([closingPositionFees, openingPositionFees]) => ({ ([closingPositionFees, openingPositionFees]) => ({
baseDenom: openingPositionFees.base_denom,
price: BN(openingPositionFees.opening_exec_price ?? 0), price: BN(openingPositionFees.opening_exec_price ?? 0),
fee: BNCoin.fromDenomAndBigNumber( fee: {
closingPositionFees.base_denom, opening: BN(closingPositionFees.opening_fee).plus(openingPositionFees.opening_fee),
BN(closingPositionFees.opening_fee) closing: BN(closingPositionFees.closing_fee).plus(openingPositionFees.closing_fee),
.plus(closingPositionFees.closing_fee) },
.plus(openingPositionFees.opening_fee) rate: BN(0.0005), // TODO: Make this rate the actula rate again!
.plus(openingPositionFees.closing_fee),
),
rate: BN(0.005),
}), }),
) )
}, },
+7 -4
View File
@@ -14,6 +14,7 @@ import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams
import { import {
AssetParamsBaseForAddr, AssetParamsBaseForAddr,
HealthComputer, HealthComputer,
Positions,
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types' } from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
import { convertAccountToPositions } from 'utils/accounts' import { convertAccountToPositions } from 'utils/accounts'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
@@ -32,7 +33,8 @@ import { BN } from 'utils/helpers'
// Pyth returns prices with up to 32 decimals. Javascript only supports 18 decimals. So we need to scale by 14 t // Pyth returns prices with up to 32 decimals. Javascript only supports 18 decimals. So we need to scale by 14 t
// avoid "too many decimals" errors. // avoid "too many decimals" errors.
const VALUE_SCALE_FACTOR = 14 // TODO: Remove adjustment properly (after testing). We will just ignore the last 14 decimals.
const VALUE_SCALE_FACTOR = 0
export default function useHealthComputer(account?: Account) { export default function useHealthComputer(account?: Account) {
const assets = useAllAssets() const assets = useAllAssets()
@@ -42,10 +44,10 @@ export default function useHealthComputer(account?: Account) {
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage) const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
const [healthFactor, setHealthFactor] = useState(0) const [healthFactor, setHealthFactor] = useState(0)
const positions: PositionsWithoutPerps | null = useMemo(() => { const positions: Positions | null = useMemo(() => {
if (!account) return null if (!account) return null
return convertAccountToPositions(account) return convertAccountToPositions(account, prices)
}, [account]) }, [account, prices])
const vaultPositionValues = useMemo(() => { const vaultPositionValues = useMemo(() => {
if (!account?.vaults) return null if (!account?.vaults) return null
@@ -87,6 +89,7 @@ export default function useHealthComputer(account?: Account) {
prev[curr.denom] = curr.amount prev[curr.denom] = curr.amount
.shiftedBy(VALUE_SCALE_FACTOR) .shiftedBy(VALUE_SCALE_FACTOR)
.shiftedBy(-decimals + 6) .shiftedBy(-decimals + 6)
.decimalPlaces(18)
.toString() .toString()
return prev return prev
}, },
+20 -4
View File
@@ -1,4 +1,4 @@
import { ActionCoin } from 'types/generated/mars-credit-manager/MarsCreditManager.types' import { ActionCoin, PnL } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
export class BNCoin { export class BNCoin {
@@ -23,7 +23,7 @@ export class BNCoin {
toCoin(): Coin { toCoin(): Coin {
return { return {
denom: this.denom, denom: this.denom,
amount: this.amount.toString(), amount: this.amount.integerValue().toString(),
} }
} }
@@ -33,7 +33,7 @@ export class BNCoin {
amount: max amount: max
? 'account_balance' ? 'account_balance'
: { : {
exact: this.amount.toString(), exact: this.amount.integerValue().toString(),
}, },
} }
} }
@@ -41,7 +41,23 @@ export class BNCoin {
toSignedCoin(): any { toSignedCoin(): any {
return { return {
denom: this.denom, denom: this.denom,
size: this.amount.toString(), size: this.amount.integerValue().toString(),
}
}
toPnLCoin(): PnL {
if (this.amount.isZero()) {
return 'break_even'
}
if (this.amount.isPositive()) {
return {
profit: this.toCoin(),
}
}
return {
loss: this.abs().toCoin(),
} }
} }
@@ -69,6 +69,7 @@ import {
Positions, Positions,
DebtAmount, DebtAmount,
PerpPosition, PerpPosition,
PnlAmounts,
PositionPnl, PositionPnl,
PnlCoins, PnlCoins,
PnlValues, PnlValues,
@@ -28,387 +28,387 @@ export interface InstantiateMsg {
} }
export type ExecuteMsg = export type ExecuteMsg =
| { | {
create_credit_account: AccountKind create_credit_account: AccountKind
} }
| { | {
update_credit_account: { update_credit_account: {
account_id: string account_id: string
actions: Action[] actions: Action[]
} }
} }
| { | {
repay_from_wallet: { repay_from_wallet: {
account_id: string account_id: string
} }
} }
| { | {
update_config: { update_config: {
updates: ConfigUpdates updates: ConfigUpdates
} }
} }
| { | {
update_owner: OwnerUpdate update_owner: OwnerUpdate
} }
| { | {
update_nft_config: { update_nft_config: {
config?: NftConfigUpdates | null config?: NftConfigUpdates | null
ownership?: Action2 | null ownership?: Action2 | null
} }
} }
| { | {
callback: CallbackMsg callback: CallbackMsg
} }
export type AccountKind = 'default' | 'high_levered_strategy' export type AccountKind = 'default' | 'high_levered_strategy'
export type Action = export type Action =
| { | {
deposit: Coin deposit: Coin
} }
| { | {
withdraw: ActionCoin withdraw: ActionCoin
} }
| { | {
borrow: Coin borrow: Coin
} }
| { | {
lend: ActionCoin lend: ActionCoin
} }
| { | {
reclaim: ActionCoin reclaim: ActionCoin
} }
| { | {
claim_rewards: {} claim_rewards: {}
} }
| { | {
repay: { repay: {
coin: ActionCoin coin: ActionCoin
recipient_account_id?: string | null recipient_account_id?: string | null
} }
} }
| { | {
open_perp: { open_perp: {
denom: string denom: string
size: SignedDecimal size: SignedDecimal
} }
} }
| { | {
close_perp: { close_perp: {
denom: string denom: string
} }
} }
| { | {
modify_perp: { modify_perp: {
denom: string denom: string
new_size: SignedDecimal new_size: SignedDecimal
} }
} }
| { | {
enter_vault: { enter_vault: {
coin: ActionCoin coin: ActionCoin
vault: VaultBaseForString vault: VaultBaseForString
} }
} }
| { | {
exit_vault: { exit_vault: {
amount: Uint128 amount: Uint128
vault: VaultBaseForString vault: VaultBaseForString
} }
} }
| { | {
request_vault_unlock: { request_vault_unlock: {
amount: Uint128 amount: Uint128
vault: VaultBaseForString vault: VaultBaseForString
} }
} }
| { | {
exit_vault_unlocked: { exit_vault_unlocked: {
id: number id: number
vault: VaultBaseForString vault: VaultBaseForString
} }
} }
| { | {
liquidate: { liquidate: {
debt_coin: Coin debt_coin: Coin
liquidatee_account_id: string liquidatee_account_id: string
request: LiquidateRequestForVaultBaseForString request: LiquidateRequestForVaultBaseForString
} }
} }
| { | {
swap_exact_in: { swap_exact_in: {
coin_in: ActionCoin coin_in: ActionCoin
denom_out: string denom_out: string
slippage: Decimal slippage: Decimal
} }
} }
| { | {
provide_liquidity: { provide_liquidity: {
coins_in: ActionCoin[] coins_in: ActionCoin[]
lp_token_out: string lp_token_out: string
slippage: Decimal slippage: Decimal
} }
} }
| { | {
withdraw_liquidity: { withdraw_liquidity: {
lp_token: ActionCoin lp_token: ActionCoin
slippage: Decimal slippage: Decimal
} }
} }
| { | {
refund_all_coin_balances: {} refund_all_coin_balances: {}
} }
export type ActionAmount = export type ActionAmount =
| 'account_balance' | 'account_balance'
| { | {
exact: Uint128 exact: Uint128
} }
export type LiquidateRequestForVaultBaseForString = export type LiquidateRequestForVaultBaseForString =
| { | {
deposit: string deposit: string
} }
| { | {
lend: string lend: string
} }
| { | {
vault: { vault: {
position_type: VaultPositionType position_type: VaultPositionType
request_vault: VaultBaseForString request_vault: VaultBaseForString
} }
} }
export type VaultPositionType = 'u_n_l_o_c_k_e_d' | 'l_o_c_k_e_d' | 'u_n_l_o_c_k_i_n_g' export type VaultPositionType = 'u_n_l_o_c_k_e_d' | 'l_o_c_k_e_d' | 'u_n_l_o_c_k_i_n_g'
export type AccountNftBaseForString = string export type AccountNftBaseForString = string
export type PerpsBaseForString = string export type PerpsBaseForString = string
export type OwnerUpdate = export type OwnerUpdate =
| { | {
propose_new_owner: { propose_new_owner: {
proposed: string proposed: string
} }
} }
| 'clear_proposed' | 'clear_proposed'
| 'accept_proposed' | 'accept_proposed'
| 'abolish_owner_role' | 'abolish_owner_role'
| { | {
set_emergency_owner: { set_emergency_owner: {
emergency_owner: string emergency_owner: string
} }
} }
| 'clear_emergency_owner' | 'clear_emergency_owner'
export type Action2 = export type Action2 =
| { | {
transfer_ownership: { transfer_ownership: {
expiry?: Expiration | null expiry?: Expiration | null
new_owner: string new_owner: string
} }
} }
| 'accept_ownership' | 'accept_ownership'
| 'renounce_ownership' | 'renounce_ownership'
export type Expiration = export type Expiration =
| { | {
at_height: number at_height: number
} }
| { | {
at_time: Timestamp at_time: Timestamp
} }
| { | {
never: {} never: {}
} }
export type Timestamp = Uint64 export type Timestamp = Uint64
export type Uint64 = string export type Uint64 = string
export type CallbackMsg = export type CallbackMsg =
| { | {
withdraw: { withdraw: {
account_id: string account_id: string
coin: ActionCoin coin: ActionCoin
recipient: Addr recipient: Addr
} }
} }
| { | {
borrow: { borrow: {
account_id: string account_id: string
coin: Coin coin: Coin
} }
} }
| { | {
repay: { repay: {
account_id: string account_id: string
coin: ActionCoin coin: ActionCoin
} }
} }
| { | {
repay_for_recipient: { repay_for_recipient: {
benefactor_account_id: string benefactor_account_id: string
coin: ActionCoin coin: ActionCoin
recipient_account_id: string recipient_account_id: string
} }
} }
| { | {
lend: { lend: {
account_id: string account_id: string
coin: ActionCoin coin: ActionCoin
} }
} }
| { | {
reclaim: { reclaim: {
account_id: string account_id: string
coin: ActionCoin coin: ActionCoin
} }
} }
| { | {
claim_rewards: { claim_rewards: {
account_id: string account_id: string
recipient: Addr recipient: Addr
} }
} }
| { | {
assert_max_ltv: { assert_max_ltv: {
account_id: string account_id: string
prev_health_state: HealthState prev_health_state: HealthState
} }
} }
| { | {
assert_deposit_caps: { assert_deposit_caps: {
denoms: string[] denoms: string[]
} }
} }
| { | {
open_perp: { open_perp: {
account_id: string account_id: string
denom: string denom: string
size: SignedDecimal size: SignedDecimal
} }
} }
| { | {
close_perp: { close_perp: {
account_id: string account_id: string
denom: string denom: string
} }
} }
| { | {
modify_perp: { modify_perp: {
account_id: string account_id: string
denom: string denom: string
new_size: SignedDecimal new_size: SignedDecimal
} }
} }
| { | {
enter_vault: { enter_vault: {
account_id: string account_id: string
coin: ActionCoin coin: ActionCoin
vault: VaultBaseForAddr vault: VaultBaseForAddr
} }
} }
| { | {
exit_vault: { exit_vault: {
account_id: string account_id: string
amount: Uint128 amount: Uint128
vault: VaultBaseForAddr vault: VaultBaseForAddr
} }
} }
| { | {
update_vault_coin_balance: { update_vault_coin_balance: {
account_id: string account_id: string
previous_total_balance: Uint128 previous_total_balance: Uint128
vault: VaultBaseForAddr vault: VaultBaseForAddr
} }
} }
| { | {
request_vault_unlock: { request_vault_unlock: {
account_id: string account_id: string
amount: Uint128 amount: Uint128
vault: VaultBaseForAddr vault: VaultBaseForAddr
} }
} }
| { | {
exit_vault_unlocked: { exit_vault_unlocked: {
account_id: string account_id: string
position_id: number position_id: number
vault: VaultBaseForAddr vault: VaultBaseForAddr
} }
} }
| { | {
liquidate: { liquidate: {
debt_coin: Coin debt_coin: Coin
liquidatee_account_id: string liquidatee_account_id: string
liquidator_account_id: string liquidator_account_id: string
request: LiquidateRequestForVaultBaseForAddr request: LiquidateRequestForVaultBaseForAddr
} }
} }
| { | {
swap_exact_in: { swap_exact_in: {
account_id: string account_id: string
coin_in: ActionCoin coin_in: ActionCoin
denom_out: string denom_out: string
slippage: Decimal slippage: Decimal
} }
} }
| { | {
update_coin_balance: { update_coin_balance: {
account_id: string account_id: string
change: ChangeExpected change: ChangeExpected
previous_balance: Coin previous_balance: Coin
} }
} }
| { | {
update_coin_balance_after_vault_liquidation: { update_coin_balance_after_vault_liquidation: {
account_id: string account_id: string
previous_balance: Coin previous_balance: Coin
protocol_fee: Decimal protocol_fee: Decimal
} }
} }
| { | {
provide_liquidity: { provide_liquidity: {
account_id: string account_id: string
coins_in: ActionCoin[] coins_in: ActionCoin[]
lp_token_out: string lp_token_out: string
slippage: Decimal slippage: Decimal
} }
} }
| { | {
withdraw_liquidity: { withdraw_liquidity: {
account_id: string account_id: string
lp_token: ActionCoin lp_token: ActionCoin
slippage: Decimal slippage: Decimal
} }
} }
| { | {
refund_all_coin_balances: { refund_all_coin_balances: {
account_id: string account_id: string
} }
} }
| { | {
assert_hls_rules: { assert_hls_rules: {
account_id: string account_id: string
} }
} }
| { | {
remove_reentrancy_guard: {} remove_reentrancy_guard: {}
} }
| { | {
send_rewards_to_addr: { send_rewards_to_addr: {
account_id: string account_id: string
previous_balances: Coin[] previous_balances: Coin[]
recipient: Addr recipient: Addr
} }
} }
export type Addr = string export type Addr = string
export type HealthState = export type HealthState =
| 'healthy' | 'healthy'
| { | {
unhealthy: { unhealthy: {
max_ltv_health_factor: Decimal max_ltv_health_factor: Decimal
} }
} }
export type LiquidateRequestForVaultBaseForAddr = export type LiquidateRequestForVaultBaseForAddr =
| { | {
deposit: string deposit: string
} }
| { | {
lend: string lend: string
} }
| { | {
vault: { vault: {
position_type: VaultPositionType position_type: VaultPositionType
request_vault: VaultBaseForAddr request_vault: VaultBaseForAddr
} }
} }
export type ChangeExpected = 'increase' | 'decrease' export type ChangeExpected = 'increase' | 'decrease'
export interface Coin { export interface Coin {
amount: Uint128 amount: Uint128
@@ -451,80 +451,80 @@ export interface VaultBaseForAddr {
} }
export type QueryMsg = export type QueryMsg =
| { | {
account_kind: { account_kind: {
account_id: string account_id: string
} }
} }
| { | {
accounts: { accounts: {
limit?: number | null limit?: number | null
owner: string owner: string
start_after?: string | null start_after?: string | null
} }
} }
| { | {
config: {} config: {}
} }
| { | {
vault_utilization: { vault_utilization: {
vault: VaultBaseForString vault: VaultBaseForString
} }
} }
| { | {
positions: { positions: {
account_id: string account_id: string
} }
} }
| { | {
all_coin_balances: { all_coin_balances: {
limit?: number | null limit?: number | null
start_after?: [string, string] | null start_after?: [string, string] | null
} }
} }
| { | {
all_debt_shares: { all_debt_shares: {
limit?: number | null limit?: number | null
start_after?: [string, string] | null start_after?: [string, string] | null
} }
} }
| { | {
total_debt_shares: string total_debt_shares: string
} }
| { | {
all_total_debt_shares: { all_total_debt_shares: {
limit?: number | null limit?: number | null
start_after?: string | null start_after?: string | null
} }
} }
| { | {
all_vault_positions: { all_vault_positions: {
limit?: number | null limit?: number | null
start_after?: [string, string] | null start_after?: [string, string] | null
} }
} }
| { | {
estimate_provide_liquidity: { estimate_provide_liquidity: {
coins_in: Coin[] coins_in: Coin[]
lp_token_out: string lp_token_out: string
} }
} }
| { | {
estimate_withdraw_liquidity: { estimate_withdraw_liquidity: {
lp_token: Coin lp_token: Coin
} }
} }
| { | {
vault_position_value: { vault_position_value: {
vault_position: VaultPosition vault_position: VaultPosition
} }
} }
export type VaultPositionAmount = export type VaultPositionAmount =
| { | {
unlocked: VaultAmount unlocked: VaultAmount
} }
| { | {
locking: LockingVaultAmount locking: LockingVaultAmount
} }
export type VaultAmount = string export type VaultAmount = string
export type VaultAmount1 = string export type VaultAmount1 = string
export type UnlockingPositions = VaultUnlockingPosition[] export type UnlockingPositions = VaultUnlockingPosition[]
@@ -597,11 +597,11 @@ export type ArrayOfCoin = Coin[]
export type PnL = export type PnL =
| 'break_even' | 'break_even'
| { | {
profit: Coin profit: Coin
} }
| { | {
loss: Coin loss: Coin
} }
export interface Positions { export interface Positions {
account_id: string account_id: string
debts: DebtAmount[] debts: DebtAmount[]
@@ -623,11 +623,11 @@ export interface PerpPosition {
denom: string denom: string
entry_exec_price: Decimal entry_exec_price: Decimal
entry_price: Decimal entry_price: Decimal
realised_pnl: RealizedPnlAmounts realised_pnl: PnlAmounts
size: SignedDecimal size: SignedDecimal
unrealised_pnl: PositionPnl unrealised_pnl: PositionPnl
} }
export interface RealizedPnlAmounts { export interface PnlAmounts {
accrued_funding: SignedDecimal accrued_funding: SignedDecimal
closing_fee: SignedDecimal closing_fee: SignedDecimal
opening_fee: SignedDecimal opening_fee: SignedDecimal
@@ -635,6 +635,7 @@ export interface RealizedPnlAmounts {
price_pnl: SignedDecimal price_pnl: SignedDecimal
} }
export interface PositionPnl { export interface PositionPnl {
amounts: PnlAmounts
coins: PnlCoins coins: PnlCoins
values: PnlValues values: PnlValues
} }
@@ -27,10 +27,11 @@ import {
DebtAmount, DebtAmount,
Coin, Coin,
PerpPosition, PerpPosition,
PnlAmounts,
SignedDecimal,
PositionPnl, PositionPnl,
PnlCoins, PnlCoins,
PnlValues, PnlValues,
SignedDecimal,
VaultPosition, VaultPosition,
LockingVaultAmount, LockingVaultAmount,
VaultUnlockingPosition, VaultUnlockingPosition,
@@ -27,10 +27,11 @@ import {
DebtAmount, DebtAmount,
Coin, Coin,
PerpPosition, PerpPosition,
PnlAmounts,
SignedDecimal,
PositionPnl, PositionPnl,
PnlCoins, PnlCoins,
PnlValues, PnlValues,
SignedDecimal,
VaultPosition, VaultPosition,
LockingVaultAmount, LockingVaultAmount,
VaultUnlockingPosition, VaultUnlockingPosition,
@@ -41,7 +41,7 @@ export type UnlockingPositions = VaultUnlockingPosition[]
export interface HealthComputer { export interface HealthComputer {
denoms_data: DenomsData denoms_data: DenomsData
kind: AccountKind kind: AccountKind
positions: PositionsWithoutPerps positions: Positions
vaults_data: VaultsData vaults_data: VaultsData
} }
export interface DenomsData { export interface DenomsData {
@@ -102,13 +102,29 @@ export interface Coin {
export interface PerpPosition { export interface PerpPosition {
base_denom: string base_denom: string
closing_fee_rate: Decimal closing_fee_rate: Decimal
current_exec_price: Decimal
current_price: Decimal current_price: Decimal
denom: string denom: string
entry_exec_price: Decimal
entry_price: Decimal entry_price: Decimal
pnl: PositionPnl realised_pnl: PnlAmounts
size: SignedDecimal size: SignedDecimal
unrealised_pnl: PositionPnl
}
export interface PnlAmounts {
accrued_funding: SignedDecimal
closing_fee: SignedDecimal
opening_fee: SignedDecimal
pnl: SignedDecimal
price_pnl: SignedDecimal
}
export interface SignedDecimal {
abs: Decimal
negative: boolean
[k: string]: unknown
} }
export interface PositionPnl { export interface PositionPnl {
amounts: PnlAmounts
coins: PnlCoins coins: PnlCoins
values: PnlValues values: PnlValues
} }
@@ -122,11 +138,6 @@ export interface PnlValues {
pnl: SignedDecimal pnl: SignedDecimal
price_pnl: SignedDecimal price_pnl: SignedDecimal
} }
export interface SignedDecimal {
abs: Decimal
negative: boolean
[k: string]: unknown
}
export interface VaultPosition { export interface VaultPosition {
amount: VaultPositionAmount amount: VaultPositionAmount
vault: VaultBaseForAddr vault: VaultBaseForAddr
+2
View File
@@ -2,4 +2,6 @@ interface DropDownItem {
icon: import('react').ReactNode icon: import('react').ReactNode
onClick: () => void onClick: () => void
text: string text: string
disabled?: boolean
disabledTooltip?: string
} }
+1 -6
View File
@@ -1,11 +1,5 @@
type TradeDirection = 'long' | 'short' type TradeDirection = 'long' | 'short'
// TODO: 📈Remove this type when healthcomputer is implemented
type PositionsWithoutPerps = Omit<
import('types/generated/mars-credit-manager/MarsCreditManager.types').Positions,
'perps'
>
interface PerpsPosition { interface PerpsPosition {
denom: string denom: string
baseDenom: string baseDenom: string
@@ -13,6 +7,7 @@ interface PerpsPosition {
amount: BigNumber amount: BigNumber
pnl: PerpsPnL pnl: PerpsPnL
entryPrice: BigNumber entryPrice: BigNumber
closingFeeRate: BigNumber
} }
interface PerpPositionRow extends PerpsPosition { interface PerpPositionRow extends PerpsPosition {
+62 -1
View File
@@ -4,6 +4,7 @@ import { BN_ZERO } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle' import { ORACLE_DENOM } from 'constants/oracle'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { VaultPosition } from 'types/generated/mars-credit-manager/MarsCreditManager.types' import { VaultPosition } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { Positions } from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import { convertApyToApr } from 'utils/parsers' import { convertApyToApr } from 'utils/parsers'
@@ -174,7 +175,7 @@ export function accumulateAmounts(denom: string, coins: BNCoin[]): BigNumber {
} }
// TODO: 📈 Add correct type mapping // TODO: 📈 Add correct type mapping
export function convertAccountToPositions(account: Account): PositionsWithoutPerps { export function convertAccountToPositions(account: Account, prices: BNCoin[]): Positions {
return { return {
account_id: account.id, account_id: account.id,
debts: account.debts.map((debt) => ({ debts: account.debts.map((debt) => ({
@@ -188,6 +189,66 @@ export function convertAccountToPositions(account: Account): PositionsWithoutPer
amount: lend.amount.toString(), amount: lend.amount.toString(),
denom: lend.denom, denom: lend.denom,
})), })),
perps: account.perps.map((perpPosition) => {
// TODO: Check if this needs to be converted (in regards to HC decimal scaling)
const currentPrice = prices.find(byDenom(perpPosition.denom))?.amount ?? BN_ZERO
return {
// Used
base_denom: perpPosition.baseDenom,
// Used
closing_fee_rate: perpPosition.closingFeeRate.toString(),
// Used
current_price: currentPrice.toString(), // Check what prices we should pass to current and entry prices. Entry price will change when modifying positionl
current_exec_price: currentPrice.toString(), // TODO: 📈 This needs to be queried
denom: perpPosition.denom,
// Used (for now, this might be changed)
entry_price: currentPrice.toString(),
// Used (not actually used, but it's in todo)
entry_exec_price: currentPrice.toString(), // TODO: 📈 Check if this matters (currently just using entry price)
// Used
size: perpPosition.amount.toString() as any,
unrealised_pnl: {
coins: {
closing_fee: perpPosition.pnl.unrealized.fees.abs().toCoin(),
// Used
pnl: perpPosition.pnl.unrealized.net.toPnLCoin(), // Used
},
amounts: {
// CHeck if these are correct
accrued_funding: perpPosition.pnl.unrealized.funding.amount
.integerValue()
.toString() as any,
opening_fee: perpPosition.pnl.unrealized.fees.amount
.abs()
.integerValue()
.toString() as any, // Add openning fee for modifying position
closing_fee: perpPosition.pnl.unrealized.fees.amount
.abs()
.integerValue()
.toString() as any, // Add closing fee for modifying position
pnl: perpPosition.pnl.unrealized.net.amount.integerValue().toString() as any,
price_pnl: perpPosition.pnl.unrealized.price.amount.integerValue().toString() as any,
},
values: {
// This does not matter for health calculation
accrued_funding: perpPosition.pnl.unrealized.funding.amount
.integerValue()
.toString() as any,
closing_fee: perpPosition.pnl.unrealized.fees.amount.integerValue().toString() as any,
pnl: perpPosition.pnl.unrealized.net.amount.integerValue().toString() as any,
price_pnl: perpPosition.pnl.unrealized.price.amount.integerValue().toString() as any,
},
},
realised_pnl: {
// This does not matter for the health calculation
accrued_funding: perpPosition.pnl.realized.funding.amount.toString() as any,
closing_fee: perpPosition.pnl.realized.fees.amount.toString() as any,
opening_fee: perpPosition.pnl.realized.fees.amount.toString() as any,
pnl: perpPosition.pnl.realized.net.amount.toString() as any,
price_pnl: perpPosition.pnl.realized.price.amount.toString() as any,
},
}
}),
vaults: account.vaults.map( vaults: account.vaults.map(
(vault) => (vault) =>
({ ({
+3 -2
View File
@@ -2,16 +2,17 @@ import BigNumber from 'bignumber.js'
import { BN_ONE, BN_ZERO } from 'constants/math' import { BN_ONE, BN_ZERO } from 'constants/math'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { BN } from 'utils/helpers'
export default function getPerpsPosition( export default function getPerpsPosition(
asset: Asset, asset: Asset,
amount: BigNumber, amount: BigNumber,
tradeDirection: TradeDirection, tradeDirection: TradeDirection,
) { ): PerpsPosition {
const perpsBaseDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3' const perpsBaseDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3'
return { return {
amount, amount,
closingFee: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE), closingFeeRate: BN(0.0005), // TODO: Pass the actual rate
pnl: { pnl: {
net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE), net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE),
realized: { realized: {
+1 -1
View File
@@ -96,10 +96,10 @@ export interface InitOutput {
h: number, h: number,
) => void ) => void
readonly liquidation_price_js: (a: number, b: number, c: number, d: number, e: number) => void readonly liquidation_price_js: (a: number, b: number, c: number, d: number, e: number) => void
readonly interface_version_8: () => void
readonly allocate: (a: number) => number readonly allocate: (a: number) => number
readonly deallocate: (a: number) => void readonly deallocate: (a: number) => void
readonly requires_iterator: () => void readonly requires_iterator: () => void
readonly interface_version_8: () => void
readonly __wbindgen_malloc: (a: number, b: number) => number readonly __wbindgen_malloc: (a: number, b: number) => number
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number
readonly __wbindgen_add_to_stack_pointer: (a: number) => number readonly __wbindgen_add_to_stack_pointer: (a: number) => number
+1
View File
@@ -296,6 +296,7 @@ async function __wbg_load(module, imports) {
function __wbg_get_imports() { function __wbg_get_imports() {
const imports = {} const imports = {}
imports.wbg = {} imports.wbg = {}
imports.wbg.__wbg_log_117d9799fa4f6287 = function (arg0, arg1, arg2, arg3) {}
imports.wbg.__wbindgen_object_clone_ref = function (arg0) { imports.wbg.__wbindgen_object_clone_ref = function (arg0) {
const ret = getObject(arg0) const ret = getObject(arg0)
return addHeapObject(ret) return addHeapObject(ret)
Binary file not shown.
+1 -1
View File
@@ -15,10 +15,10 @@ export function max_swap_estimate_js(
h: number, h: number,
): void ): void
export function liquidation_price_js(a: number, b: number, c: number, d: number, e: number): void export function liquidation_price_js(a: number, b: number, c: number, d: number, e: number): void
export function interface_version_8(): void
export function allocate(a: number): number export function allocate(a: number): number
export function deallocate(a: number): void export function deallocate(a: number): void
export function requires_iterator(): void export function requires_iterator(): void
export function interface_version_8(): void
export function __wbindgen_malloc(a: number, b: number): number export function __wbindgen_malloc(a: number, b: number): number
export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number
export function __wbindgen_add_to_stack_pointer(a: number): number export function __wbindgen_add_to_stack_pointer(a: number): number
+1 -1
View File
@@ -118,7 +118,7 @@ export function resolvePerpsPositions(
baseDenom: position.base_denom, baseDenom: position.base_denom,
amount: BN(position.size as any), // Amount is negative for SHORT positions amount: BN(position.size as any), // Amount is negative for SHORT positions
tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long', tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long',
// closingFee: BNCoin.fromCoin(position.pnl.coins.closing_fee), closingFeeRate: BN(position.closing_fee_rate),
pnl: { pnl: {
net: BNCoin.fromDenomAndBigNumber( net: BNCoin.fromDenomAndBigNumber(
position.base_denom, position.base_denom,
+4
View File
@@ -1,4 +1,8 @@
export const getUrl = (baseUrl: string, path: string): string => { export const getUrl = (baseUrl: string, path: string): string => {
const isPlaceholder = baseUrl.split('APP_').length > 1
if (isPlaceholder) return baseUrl + '/' + path
const url = new URL(baseUrl) const url = new URL(baseUrl)
if (process.env.NEXT_PUBLIC_API_KEY) if (process.env.NEXT_PUBLIC_API_KEY)