Mp 3360 create vault position (#607)
* 🔧 Small fixes * ✨ Deposit into HLS Vault + Groudnwork for HLS Staking * Adjusted according to feedback * Adjusted according to feedback
This commit is contained in:
parent
f38399606b
commit
0325e311cb
@ -1,7 +1,7 @@
|
|||||||
import { Suspense, useMemo } from 'react'
|
import { Suspense, useMemo } from 'react'
|
||||||
|
|
||||||
import { NAME_META } from 'components/Earn/Farm/Table/Columns/Name'
|
import { NAME_META } from 'components/HLS/Farm/Table/Columns/Name'
|
||||||
import useAvailableColumns from 'components/Earn/Farm/Table/Columns/useAvailableColumns'
|
import useAvailableColumns from 'components/HLS/Farm/Table/Columns/useAvailableColumns'
|
||||||
import Table from 'components/Table'
|
import Table from 'components/Table'
|
||||||
import { ENV } from 'constants/env'
|
import { ENV } from 'constants/env'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
@ -38,20 +38,22 @@ function Fallback() {
|
|||||||
const columns = useAvailableColumns({ isLoading: true })
|
const columns = useAvailableColumns({ isLoading: true })
|
||||||
|
|
||||||
const vaults = ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
const vaults = ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
||||||
const mockVaults: Vault[] = vaults.map((vault) => ({
|
const mockVaults: Vault[] = vaults
|
||||||
...vault,
|
.filter((v) => v.isHls)
|
||||||
apy: null,
|
.map((vault) => ({
|
||||||
apr: null,
|
...vault,
|
||||||
ltv: {
|
apy: null,
|
||||||
max: 0,
|
apr: null,
|
||||||
liq: 0,
|
ltv: {
|
||||||
},
|
max: 0,
|
||||||
cap: {
|
liq: 0,
|
||||||
denom: 'denom',
|
},
|
||||||
used: BN_ZERO,
|
cap: {
|
||||||
max: BN_ZERO,
|
denom: 'denom',
|
||||||
},
|
used: BN_ZERO,
|
||||||
}))
|
max: BN_ZERO,
|
||||||
|
},
|
||||||
|
}))
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
title={title}
|
title={title}
|
||||||
|
@ -13,12 +13,13 @@ import useStore from 'store'
|
|||||||
export const DEPOSIT_META = { accessorKey: 'deposit', header: 'Deposit' }
|
export const DEPOSIT_META = { accessorKey: 'deposit', header: 'Deposit' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault
|
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
strategy?: HLSStrategy
|
||||||
|
vault?: Vault
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Deposit(props: Props) {
|
export default function Deposit(props: Props) {
|
||||||
const { vault } = props
|
const { strategy, vault } = props
|
||||||
|
|
||||||
const [showHlsInfo, setShowHlsInfo] = useLocalStorage<boolean>(
|
const [showHlsInfo, setShowHlsInfo] = useLocalStorage<boolean>(
|
||||||
LocalStorageKeys.HLS_INFORMATION,
|
LocalStorageKeys.HLS_INFORMATION,
|
||||||
@ -27,7 +28,12 @@ export default function Deposit(props: Props) {
|
|||||||
|
|
||||||
const { open: openAlertDialog, close } = useAlertDialog()
|
const { open: openAlertDialog, close } = useAlertDialog()
|
||||||
|
|
||||||
const enterVaultHandler = useCallback(() => {
|
const openHlsModal = useCallback(
|
||||||
|
() => useStore.setState({ hlsModal: { strategy, vault } }),
|
||||||
|
[strategy, vault],
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleOnClick = useCallback(() => {
|
||||||
if (!showHlsInfo) {
|
if (!showHlsInfo) {
|
||||||
openHlsModal()
|
openHlsModal()
|
||||||
return
|
return
|
||||||
@ -72,17 +78,13 @@ export default function Deposit(props: Props) {
|
|||||||
onClick: (isChecked: boolean) => setShowHlsInfo(!isChecked),
|
onClick: (isChecked: boolean) => setShowHlsInfo(!isChecked),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, [close, openAlertDialog, setShowHlsInfo, showHlsInfo])
|
}, [close, openAlertDialog, openHlsModal, setShowHlsInfo, showHlsInfo])
|
||||||
|
|
||||||
function openHlsModal() {
|
|
||||||
useStore.setState({ hlsModal: { vault } })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.isLoading) return <Loading />
|
if (props.isLoading) return <Loading />
|
||||||
|
|
||||||
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={handleOnClick} color='tertiary' text='Deposit' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ import React from 'react'
|
|||||||
|
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
|
||||||
|
export const NAME_META = { id: 'name', accessorKey: 'denoms.primary', header: 'Name' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
strategy: HLSStrategy
|
strategy: HLSStrategy
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,45 @@
|
|||||||
export default function AvailableHlsStakingAssets() {
|
import { Suspense } from 'react'
|
||||||
return null
|
|
||||||
|
import { NAME_META } from 'components/HLS/Farm/Table/Columns/Name'
|
||||||
|
import useAvailableColumns from 'components/HLS/Staking/Table/Columns/useAvailableColumns'
|
||||||
|
import Table from 'components/Table'
|
||||||
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
|
import { getEnabledMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
|
const title = 'Available HLS Staking'
|
||||||
|
|
||||||
|
function Content() {
|
||||||
|
const assets = getEnabledMarketAssets()
|
||||||
|
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||||
|
const columns = useAvailableColumns({ isLoading: false })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
title={title}
|
||||||
|
columns={columns}
|
||||||
|
data={hlsStrategies}
|
||||||
|
initialSorting={[{ id: NAME_META.id, desc: true }]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AvailableHlsVaults() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<Fallback />}>
|
||||||
|
<Content />
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Fallback() {
|
||||||
|
const columns = useAvailableColumns({ isLoading: true })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
title={title}
|
||||||
|
columns={columns}
|
||||||
|
data={[]}
|
||||||
|
initialSorting={[{ id: NAME_META.id, desc: true }]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
23
src/components/HLS/Staking/Table/Columns/MaxLTV.tsx
Normal file
23
src/components/HLS/Staking/Table/Columns/MaxLTV.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
|
||||||
|
export const LTV_MAX_META = { accessorKey: 'maxLTV', header: 'Max LTV' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
strategy: HLSStrategy
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
export default function MaxLtv(props: Props) {
|
||||||
|
const { strategy } = props
|
||||||
|
if (props.isLoading) return <Loading />
|
||||||
|
return (
|
||||||
|
<FormattedNumber
|
||||||
|
amount={strategy.maxLTV * 100}
|
||||||
|
options={{ minDecimals: 0, maxDecimals: 0, suffix: '%' }}
|
||||||
|
className='text-xs'
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
20
src/components/HLS/Staking/Table/Columns/MaxLeverage.tsx
Normal file
20
src/components/HLS/Staking/Table/Columns/MaxLeverage.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
|
||||||
|
export const MAX_LEV_META = { accessorKey: 'maxLeverage', header: 'Max Leverage' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
strategy: HLSStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MaxLeverage(props: Props) {
|
||||||
|
return (
|
||||||
|
<FormattedNumber
|
||||||
|
amount={props.strategy.maxLeverage}
|
||||||
|
options={{ minDecimals: 2, maxDecimals: 2, suffix: 'x' }}
|
||||||
|
className='text-xs'
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
32
src/components/HLS/Staking/Table/Columns/Name.tsx
Normal file
32
src/components/HLS/Staking/Table/Columns/Name.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import DoubleLogo from 'components/DoubleLogo'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
|
||||||
|
export const NAME_META = { id: 'name', header: 'Vault', accessorKey: 'denoms.deposit' }
|
||||||
|
interface Props {
|
||||||
|
strategy: HLSStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Name(props: Props) {
|
||||||
|
const { strategy } = props
|
||||||
|
const depositAsset = getAssetByDenom(props.strategy.denoms.deposit)
|
||||||
|
const borrowAsset = getAssetByDenom(props.strategy.denoms.borrow)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex'>
|
||||||
|
<DoubleLogo primaryDenom={strategy.denoms.deposit} secondaryDenom={strategy.denoms.borrow} />
|
||||||
|
{depositAsset && borrowAsset ? (
|
||||||
|
<TitleAndSubCell
|
||||||
|
className='ml-2 mr-2 text-left'
|
||||||
|
title={`${depositAsset.symbol}/${borrowAsset.symbol}`}
|
||||||
|
sub='Staking'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Loading />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
|
import Deposit, { DEPOSIT_META } from 'components/HLS/Farm/Table/Columns/Deposit'
|
||||||
|
import MaxLeverage, { MAX_LEV_META } from 'components/HLS/Staking/Table/Columns/MaxLeverage'
|
||||||
|
import MaxLTV, { LTV_MAX_META } from 'components/HLS/Staking/Table/Columns/MaxLTV'
|
||||||
|
import Name, { NAME_META } from 'components/HLS/Staking/Table/Columns/Name'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAvailableColumns(props: Props) {
|
||||||
|
return useMemo<ColumnDef<HLSStrategy>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
...NAME_META,
|
||||||
|
cell: ({ row }) => <Name strategy={row.original as HLSStrategy} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MAX_LEV_META,
|
||||||
|
cell: ({ row }) => <MaxLeverage strategy={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...LTV_MAX_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<MaxLTV strategy={row.original as HLSStrategy} isLoading={props.isLoading} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...DEPOSIT_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Deposit strategy={row.original as HLSStrategy} isLoading={props.isLoading} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[props.isLoading],
|
||||||
|
)
|
||||||
|
}
|
@ -1,142 +0,0 @@
|
|||||||
import React, { useMemo, useState } from 'react'
|
|
||||||
|
|
||||||
import Accordion from 'components/Accordion'
|
|
||||||
import { Item } from 'components/AccordionContent'
|
|
||||||
import CreateAccount from 'components/Modals/HLS/CreateAccount'
|
|
||||||
import Leverage from 'components/Modals/HLS/Leverage'
|
|
||||||
import ProvideCollateral from 'components/Modals/HLS/ProvideCollateral'
|
|
||||||
import SelectAccount from 'components/Modals/HLS/SelectAccount'
|
|
||||||
import { CollateralSubTitle, LeverageSubTitle, SubTitle } from 'components/Modals/HLS/SubTitles'
|
|
||||||
import Summary from 'components/Modals/HLS/Summary'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
import useAccounts from 'hooks/useAccounts'
|
|
||||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
|
||||||
import useDepositHlsVault from 'hooks/useDepositHlsVault'
|
|
||||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
vault: Vault
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Content(props: Props) {
|
|
||||||
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null)
|
|
||||||
const [isOpen, toggleIsOpen] = useIsOpenArray(4, false)
|
|
||||||
const address = useStore((s) => s.address)
|
|
||||||
const { data: hlsAccounts } = useAccounts('high_levered_strategy', address)
|
|
||||||
const collateralAsset = getAssetByDenom(props.vault.denoms.primary)
|
|
||||||
const borrowAsset = getAssetByDenom(props.vault.denoms.secondary)
|
|
||||||
const walletCollateralAsset = useCurrentWalletBalance(props.vault.denoms.primary)
|
|
||||||
const { setDepositAmount, depositAmount, setBorrowAmount, borrowAmount, positionValue } =
|
|
||||||
useDepositHlsVault({
|
|
||||||
vault: props.vault,
|
|
||||||
})
|
|
||||||
|
|
||||||
const items: Item[] = useMemo(() => {
|
|
||||||
if (!collateralAsset || !borrowAsset) return []
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: 'Provide Collateral',
|
|
||||||
renderContent: () => (
|
|
||||||
<ProvideCollateral
|
|
||||||
amount={depositAmount}
|
|
||||||
onChangeAmount={setDepositAmount}
|
|
||||||
asset={collateralAsset}
|
|
||||||
onClickBtn={() => toggleIsOpen(1)}
|
|
||||||
max={BN(walletCollateralAsset?.amount || 0)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
renderSubTitle: () => (
|
|
||||||
<CollateralSubTitle
|
|
||||||
isOpen={isOpen[0]}
|
|
||||||
amount={depositAmount}
|
|
||||||
denom={collateralAsset.denom}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
isOpen: isOpen[0],
|
|
||||||
|
|
||||||
toggleOpen: toggleIsOpen,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Leverage',
|
|
||||||
renderContent: () => (
|
|
||||||
<Leverage
|
|
||||||
amount={depositAmount}
|
|
||||||
asset={borrowAsset}
|
|
||||||
// TODO: Get max borrow amount
|
|
||||||
max={BN_ZERO}
|
|
||||||
onChangeAmount={setDepositAmount}
|
|
||||||
onClickBtn={() => toggleIsOpen(2)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
renderSubTitle: () => (
|
|
||||||
// TODO: Add leverage
|
|
||||||
<LeverageSubTitle leverage={1.1} isOpen={isOpen[1]} positionValue={positionValue} />
|
|
||||||
),
|
|
||||||
isOpen: isOpen[1],
|
|
||||||
toggleOpen: toggleIsOpen,
|
|
||||||
},
|
|
||||||
...[
|
|
||||||
hlsAccounts.length > 2
|
|
||||||
? {
|
|
||||||
title: 'Select HLS Account',
|
|
||||||
renderContent: () => (
|
|
||||||
<SelectAccount
|
|
||||||
selectedAccount={selectedAccount}
|
|
||||||
onChangeSelected={setSelectedAccount}
|
|
||||||
hlsAccounts={hlsAccounts}
|
|
||||||
onClickBtn={() => toggleIsOpen(3)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
renderSubTitle: () =>
|
|
||||||
selectedAccount && !isOpen[2] ? (
|
|
||||||
<SubTitle text={`Account ${selectedAccount.id}`} />
|
|
||||||
) : null,
|
|
||||||
isOpen: isOpen[2],
|
|
||||||
toggleOpen: toggleIsOpen,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
title: 'Create HLS Account',
|
|
||||||
renderContent: () => <CreateAccount />,
|
|
||||||
renderSubTitle: () => null,
|
|
||||||
isOpen: isOpen[2],
|
|
||||||
toggleOpen: toggleIsOpen,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
title: 'Summary',
|
|
||||||
renderContent: () => (
|
|
||||||
<Summary
|
|
||||||
depositAmount={depositAmount}
|
|
||||||
borrowAmount={borrowAmount}
|
|
||||||
positionValue={positionValue}
|
|
||||||
vault={props.vault}
|
|
||||||
onClickBtn={() => {
|
|
||||||
// TODO: Implement tx execution
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
renderSubTitle: () => null,
|
|
||||||
isOpen: isOpen[3],
|
|
||||||
toggleOpen: toggleIsOpen,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}, [
|
|
||||||
collateralAsset,
|
|
||||||
borrowAsset,
|
|
||||||
isOpen,
|
|
||||||
toggleIsOpen,
|
|
||||||
hlsAccounts,
|
|
||||||
depositAmount,
|
|
||||||
setDepositAmount,
|
|
||||||
walletCollateralAsset?.amount,
|
|
||||||
selectedAccount,
|
|
||||||
borrowAmount,
|
|
||||||
positionValue,
|
|
||||||
props.vault,
|
|
||||||
])
|
|
||||||
|
|
||||||
return <Accordion items={items} />
|
|
||||||
}
|
|
168
src/components/Modals/HLS/Content/index.tsx
Normal file
168
src/components/Modals/HLS/Content/index.tsx
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import React, { useMemo, useState } from 'react'
|
||||||
|
|
||||||
|
import Accordion from 'components/Accordion'
|
||||||
|
import useStakingController from 'components/Modals/HLS/Content//useStakingController'
|
||||||
|
import useVaultController from 'components/Modals/HLS/Content//useVaultController'
|
||||||
|
import useAccordionItems from 'components/Modals/HLS/Content/useAccordionItems'
|
||||||
|
import { EMPTY_ACCOUNT_HLS } from 'constants/accounts'
|
||||||
|
import useAccounts from 'hooks/useAccounts'
|
||||||
|
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||||
|
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||||
|
import useVault from 'hooks/useVault'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { isAccountEmpty } from 'utils/accounts'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
borrowDenom: string
|
||||||
|
collateralDenom: string
|
||||||
|
vaultAddress: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Controller(props: Props) {
|
||||||
|
const collateralAsset = getAssetByDenom(props.collateralDenom)
|
||||||
|
const borrowAsset = getAssetByDenom(props.borrowDenom)
|
||||||
|
const [selectedAccount, setSelectedAccount] = useState<Account>(EMPTY_ACCOUNT_HLS)
|
||||||
|
const [isOpen, toggleIsOpen] = useIsOpenArray(4, false)
|
||||||
|
const address = useStore((s) => s.address)
|
||||||
|
const { data: hlsAccounts } = useAccounts('high_levered_strategy', address)
|
||||||
|
const emptyHlsAccounts = useMemo(
|
||||||
|
() => hlsAccounts.filter((account) => isAccountEmpty(account)),
|
||||||
|
[hlsAccounts],
|
||||||
|
)
|
||||||
|
const walletCollateralAsset = useCurrentWalletBalance(props.collateralDenom)
|
||||||
|
const vault = useVault(props.vaultAddress || '')
|
||||||
|
|
||||||
|
if (!collateralAsset || !borrowAsset) return null
|
||||||
|
|
||||||
|
if (vault)
|
||||||
|
return (
|
||||||
|
<Vault
|
||||||
|
walletCollateralAsset={walletCollateralAsset}
|
||||||
|
vault={vault}
|
||||||
|
collateralAsset={collateralAsset}
|
||||||
|
borrowAsset={borrowAsset}
|
||||||
|
emptyHlsAccounts={emptyHlsAccounts}
|
||||||
|
hlsAccounts={hlsAccounts}
|
||||||
|
isOpen={isOpen}
|
||||||
|
selectedAccount={selectedAccount}
|
||||||
|
setSelectedAccount={setSelectedAccount}
|
||||||
|
toggleIsOpen={toggleIsOpen}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StakingContent
|
||||||
|
walletCollateralAsset={walletCollateralAsset}
|
||||||
|
collateralAsset={collateralAsset}
|
||||||
|
borrowAsset={borrowAsset}
|
||||||
|
emptyHlsAccounts={emptyHlsAccounts}
|
||||||
|
hlsAccounts={hlsAccounts}
|
||||||
|
isOpen={isOpen}
|
||||||
|
selectedAccount={selectedAccount}
|
||||||
|
setSelectedAccount={setSelectedAccount}
|
||||||
|
toggleIsOpen={toggleIsOpen}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ContentProps {
|
||||||
|
borrowAsset: Asset
|
||||||
|
collateralAsset: Asset
|
||||||
|
emptyHlsAccounts: Account[]
|
||||||
|
hlsAccounts: Account[]
|
||||||
|
isOpen: boolean[]
|
||||||
|
selectedAccount: Account
|
||||||
|
setSelectedAccount: (account: Account) => void
|
||||||
|
toggleIsOpen: (index: number) => void
|
||||||
|
walletCollateralAsset: Coin | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VaultContentProps extends ContentProps {
|
||||||
|
vault: Vault
|
||||||
|
}
|
||||||
|
|
||||||
|
function Vault(props: VaultContentProps) {
|
||||||
|
const {
|
||||||
|
borrowAmount,
|
||||||
|
depositAmount,
|
||||||
|
execute,
|
||||||
|
leverage,
|
||||||
|
maxBorrowAmount,
|
||||||
|
onChangeCollateral,
|
||||||
|
onChangeDebt,
|
||||||
|
positionValue,
|
||||||
|
updatedAccount,
|
||||||
|
} = useVaultController({
|
||||||
|
vault: props.vault,
|
||||||
|
collateralAsset: props.collateralAsset,
|
||||||
|
borrowAsset: props.borrowAsset,
|
||||||
|
selectedAccount: props.selectedAccount,
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = useAccordionItems({
|
||||||
|
apy: props.vault.apy || 0,
|
||||||
|
borrowAmount,
|
||||||
|
borrowAsset: props.borrowAsset,
|
||||||
|
collateralAsset: props.collateralAsset,
|
||||||
|
depositAmount,
|
||||||
|
emptyHlsAccounts: props.emptyHlsAccounts,
|
||||||
|
execute,
|
||||||
|
hlsAccounts: props.hlsAccounts,
|
||||||
|
isOpen: props.isOpen,
|
||||||
|
leverage,
|
||||||
|
maxBorrowAmount,
|
||||||
|
onChangeCollateral,
|
||||||
|
onChangeDebt,
|
||||||
|
positionValue,
|
||||||
|
selectedAccount: props.selectedAccount,
|
||||||
|
setSelectedAccount: props.setSelectedAccount,
|
||||||
|
toggleIsOpen: props.toggleIsOpen,
|
||||||
|
updatedAccount,
|
||||||
|
walletCollateralAsset: props.walletCollateralAsset,
|
||||||
|
})
|
||||||
|
|
||||||
|
return <Accordion className='h-[546px] overflow-y-scroll scrollbar-hide' items={items} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function StakingContent(props: ContentProps) {
|
||||||
|
const {
|
||||||
|
depositAmount,
|
||||||
|
onChangeCollateral,
|
||||||
|
updatedAccount,
|
||||||
|
borrowAmount,
|
||||||
|
onChangeDebt,
|
||||||
|
leverage,
|
||||||
|
maxBorrowAmount,
|
||||||
|
positionValue,
|
||||||
|
execute,
|
||||||
|
} = useStakingController({
|
||||||
|
collateralAsset: props.collateralAsset,
|
||||||
|
borrowAsset: props.borrowAsset,
|
||||||
|
selectedAccount: props.selectedAccount,
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = useAccordionItems({
|
||||||
|
borrowAmount,
|
||||||
|
borrowAsset: props.borrowAsset,
|
||||||
|
collateralAsset: props.collateralAsset,
|
||||||
|
depositAmount,
|
||||||
|
emptyHlsAccounts: props.emptyHlsAccounts,
|
||||||
|
execute,
|
||||||
|
hlsAccounts: props.hlsAccounts,
|
||||||
|
isOpen: props.isOpen,
|
||||||
|
leverage,
|
||||||
|
onChangeCollateral,
|
||||||
|
onChangeDebt,
|
||||||
|
positionValue,
|
||||||
|
selectedAccount: props.selectedAccount,
|
||||||
|
setSelectedAccount: props.setSelectedAccount,
|
||||||
|
toggleIsOpen: props.toggleIsOpen,
|
||||||
|
updatedAccount,
|
||||||
|
maxBorrowAmount,
|
||||||
|
apy: 0, // TODO: Implement APY
|
||||||
|
walletCollateralAsset: props.walletCollateralAsset,
|
||||||
|
})
|
||||||
|
|
||||||
|
return <Accordion className='h-[546px] overflow-y-scroll scrollbar-hide' items={items} />
|
||||||
|
}
|
127
src/components/Modals/HLS/Content/useAccordionItems.tsx
Normal file
127
src/components/Modals/HLS/Content/useAccordionItems.tsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
|
import CreateAccount from 'components/Modals/HLS/CreateAccount'
|
||||||
|
import Leverage from 'components/Modals/HLS/Leverage'
|
||||||
|
import ProvideCollateral from 'components/Modals/HLS/ProvideCollateral'
|
||||||
|
import SelectAccount from 'components/Modals/HLS/SelectAccount'
|
||||||
|
import { CollateralSubTitle, LeverageSubTitle, SubTitle } from 'components/Modals/HLS/SubTitles'
|
||||||
|
import Summary from 'components/Modals/HLS/Summary'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
apy: number
|
||||||
|
borrowAmount: BigNumber
|
||||||
|
borrowAsset: Asset
|
||||||
|
collateralAsset: Asset
|
||||||
|
depositAmount: BigNumber
|
||||||
|
emptyHlsAccounts: Account[]
|
||||||
|
execute: () => void
|
||||||
|
hlsAccounts: Account[]
|
||||||
|
isOpen: boolean[]
|
||||||
|
leverage: number
|
||||||
|
maxBorrowAmount: BigNumber
|
||||||
|
onChangeCollateral: (amount: BigNumber) => void
|
||||||
|
onChangeDebt: (amount: BigNumber) => void
|
||||||
|
positionValue: BigNumber
|
||||||
|
selectedAccount: Account | null
|
||||||
|
setSelectedAccount: (account: Account) => void
|
||||||
|
toggleIsOpen: (index: number) => void
|
||||||
|
updatedAccount: Account | undefined
|
||||||
|
walletCollateralAsset: Coin | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAccordionItems(props: Props) {
|
||||||
|
return useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Provide Collateral',
|
||||||
|
renderContent: () => (
|
||||||
|
<ProvideCollateral
|
||||||
|
amount={props.depositAmount}
|
||||||
|
onChangeAmount={props.onChangeCollateral}
|
||||||
|
asset={props.collateralAsset}
|
||||||
|
onClickBtn={() => props.toggleIsOpen(1)}
|
||||||
|
// TODO: Add check for deposit cap
|
||||||
|
max={BN(props.walletCollateralAsset?.amount || 0)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
renderSubTitle: () => (
|
||||||
|
<CollateralSubTitle
|
||||||
|
isOpen={props.isOpen[0]}
|
||||||
|
amount={props.depositAmount}
|
||||||
|
denom={props.collateralAsset.denom}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
isOpen: props.isOpen[0],
|
||||||
|
|
||||||
|
toggleOpen: props.toggleIsOpen,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Leverage',
|
||||||
|
renderContent: () => (
|
||||||
|
<Leverage
|
||||||
|
amount={props.borrowAmount}
|
||||||
|
asset={props.borrowAsset}
|
||||||
|
onChangeAmount={props.onChangeDebt}
|
||||||
|
onClickBtn={() => props.toggleIsOpen(2)}
|
||||||
|
max={props.maxBorrowAmount}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
renderSubTitle: () => (
|
||||||
|
<LeverageSubTitle
|
||||||
|
leverage={props.leverage}
|
||||||
|
isOpen={props.isOpen[1]}
|
||||||
|
positionValue={props.positionValue}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
isOpen: props.isOpen[1],
|
||||||
|
toggleOpen: props.toggleIsOpen,
|
||||||
|
},
|
||||||
|
...[
|
||||||
|
props.hlsAccounts.length > 2
|
||||||
|
? {
|
||||||
|
title: 'Select HLS Account',
|
||||||
|
renderContent: () => (
|
||||||
|
<SelectAccount
|
||||||
|
selectedAccount={props.selectedAccount}
|
||||||
|
onChangeSelected={props.setSelectedAccount}
|
||||||
|
hlsAccounts={props.emptyHlsAccounts}
|
||||||
|
onClickBtn={() => props.toggleIsOpen(3)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
renderSubTitle: () =>
|
||||||
|
props.selectedAccount && !props.isOpen[2] ? (
|
||||||
|
<SubTitle text={`Account ${props.selectedAccount.id}`} />
|
||||||
|
) : null,
|
||||||
|
isOpen: props.isOpen[2],
|
||||||
|
toggleOpen: props.toggleIsOpen,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
title: 'Create HLS Account',
|
||||||
|
renderContent: () => <CreateAccount />,
|
||||||
|
renderSubTitle: () => null,
|
||||||
|
isOpen: props.isOpen[2],
|
||||||
|
toggleOpen: props.toggleIsOpen,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
title: 'Summary',
|
||||||
|
renderContent: () => (
|
||||||
|
<Summary
|
||||||
|
depositAmount={props.depositAmount}
|
||||||
|
borrowAmount={props.borrowAmount}
|
||||||
|
leverage={props.leverage}
|
||||||
|
positionValue={props.positionValue}
|
||||||
|
collateralAsset={props.collateralAsset}
|
||||||
|
borrowAsset={props.borrowAsset}
|
||||||
|
apy={props.apy}
|
||||||
|
onClickBtn={props.execute}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
renderSubTitle: () => null,
|
||||||
|
isOpen: props.isOpen[3],
|
||||||
|
toggleOpen: props.toggleIsOpen,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [props])
|
||||||
|
}
|
59
src/components/Modals/HLS/Content/useStakingController.tsx
Normal file
59
src/components/Modals/HLS/Content/useStakingController.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
|
import useDepositHlsVault from 'hooks/useDepositHlsVault'
|
||||||
|
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
borrowAsset: Asset
|
||||||
|
collateralAsset: Asset
|
||||||
|
selectedAccount: Account
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useVaultController(props: Props) {
|
||||||
|
const { collateralAsset, borrowAsset, selectedAccount } = props
|
||||||
|
|
||||||
|
const {
|
||||||
|
leverage,
|
||||||
|
setDepositAmount,
|
||||||
|
depositAmount,
|
||||||
|
setBorrowAmount,
|
||||||
|
borrowAmount,
|
||||||
|
positionValue,
|
||||||
|
} = useDepositHlsVault({
|
||||||
|
collateralDenom: collateralAsset.denom,
|
||||||
|
borrowDenom: borrowAsset.denom,
|
||||||
|
})
|
||||||
|
|
||||||
|
const actions = []
|
||||||
|
|
||||||
|
const { updatedAccount, simulateVaultDeposit } = useUpdatedAccount(selectedAccount)
|
||||||
|
|
||||||
|
const execute = () => null
|
||||||
|
|
||||||
|
const onChangeCollateral = useCallback(
|
||||||
|
(amount: BigNumber) => {
|
||||||
|
setDepositAmount(amount)
|
||||||
|
},
|
||||||
|
[setDepositAmount],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onChangeDebt = useCallback(
|
||||||
|
(amount: BigNumber) => {
|
||||||
|
setBorrowAmount(amount)
|
||||||
|
},
|
||||||
|
[setBorrowAmount],
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
borrowAmount,
|
||||||
|
depositAmount,
|
||||||
|
execute,
|
||||||
|
leverage,
|
||||||
|
maxBorrowAmount: BN(0),
|
||||||
|
onChangeCollateral,
|
||||||
|
onChangeDebt,
|
||||||
|
positionValue,
|
||||||
|
updatedAccount,
|
||||||
|
}
|
||||||
|
}
|
128
src/components/Modals/HLS/Content/useVaultController.tsx
Normal file
128
src/components/Modals/HLS/Content/useVaultController.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
|
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||||
|
import useDepositHlsVault from 'hooks/useDepositHlsVault'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
|
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
borrowAsset: Asset
|
||||||
|
collateralAsset: Asset
|
||||||
|
selectedAccount: Account
|
||||||
|
vault: Vault
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useVaultController(props: Props) {
|
||||||
|
const { vault, collateralAsset, borrowAsset, selectedAccount } = props
|
||||||
|
|
||||||
|
const depositIntoVault = useStore((s) => s.depositIntoVault)
|
||||||
|
|
||||||
|
const {
|
||||||
|
leverage,
|
||||||
|
setDepositAmount,
|
||||||
|
depositAmount,
|
||||||
|
setBorrowAmount,
|
||||||
|
borrowAmount,
|
||||||
|
positionValue,
|
||||||
|
} = useDepositHlsVault({
|
||||||
|
collateralDenom: collateralAsset.denom,
|
||||||
|
borrowDenom: borrowAsset.denom,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { actions } = useDepositVault({
|
||||||
|
vault,
|
||||||
|
reclaims: [],
|
||||||
|
deposits: [BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
|
||||||
|
borrowings: [BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
|
||||||
|
kind: 'high_levered_strategy',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { updatedAccount, simulateVaultDeposit } = useUpdatedAccount(selectedAccount)
|
||||||
|
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
|
||||||
|
|
||||||
|
const maxBorrowAmount = useMemo(
|
||||||
|
// TODO: Check that the amount is actually the HLS amount
|
||||||
|
// TODO: Add check for market liquidity
|
||||||
|
// TODO: Add check for deposit cap
|
||||||
|
() => {
|
||||||
|
return computeMaxBorrowAmount(props.borrowAsset.denom, {
|
||||||
|
vault: { address: props.vault?.address },
|
||||||
|
}).plus(borrowAmount)
|
||||||
|
},
|
||||||
|
[borrowAmount, computeMaxBorrowAmount, props.borrowAsset.denom, props.vault?.address],
|
||||||
|
)
|
||||||
|
|
||||||
|
const execute = useCallback(() => {
|
||||||
|
depositIntoVault({
|
||||||
|
accountId: selectedAccount.id,
|
||||||
|
actions,
|
||||||
|
deposits: [BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
|
||||||
|
borrowings: [BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
|
||||||
|
isCreate: true,
|
||||||
|
kind: 'high_levered_strategy',
|
||||||
|
})
|
||||||
|
useStore.setState({ hlsModal: null })
|
||||||
|
}, [
|
||||||
|
actions,
|
||||||
|
borrowAmount,
|
||||||
|
depositAmount,
|
||||||
|
depositIntoVault,
|
||||||
|
borrowAsset.denom,
|
||||||
|
collateralAsset.denom,
|
||||||
|
selectedAccount.id,
|
||||||
|
])
|
||||||
|
|
||||||
|
const onChangeCollateral = useCallback(
|
||||||
|
(amount: BigNumber) => {
|
||||||
|
setDepositAmount(amount)
|
||||||
|
|
||||||
|
simulateVaultDeposit(
|
||||||
|
vault.address,
|
||||||
|
[BNCoin.fromDenomAndBigNumber(collateralAsset.denom, amount)],
|
||||||
|
[BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[
|
||||||
|
borrowAmount,
|
||||||
|
borrowAsset,
|
||||||
|
collateralAsset,
|
||||||
|
vault.address,
|
||||||
|
setDepositAmount,
|
||||||
|
simulateVaultDeposit,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onChangeDebt = useCallback(
|
||||||
|
(amount: BigNumber) => {
|
||||||
|
setBorrowAmount(amount)
|
||||||
|
|
||||||
|
simulateVaultDeposit(
|
||||||
|
vault.address,
|
||||||
|
[BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
|
||||||
|
[BNCoin.fromDenomAndBigNumber(borrowAsset.denom, amount)],
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[
|
||||||
|
borrowAsset,
|
||||||
|
collateralAsset,
|
||||||
|
depositAmount,
|
||||||
|
vault.address,
|
||||||
|
setBorrowAmount,
|
||||||
|
simulateVaultDeposit,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
borrowAmount,
|
||||||
|
depositAmount,
|
||||||
|
execute,
|
||||||
|
leverage,
|
||||||
|
maxBorrowAmount,
|
||||||
|
onChangeCollateral,
|
||||||
|
onChangeDebt,
|
||||||
|
positionValue,
|
||||||
|
updatedAccount,
|
||||||
|
}
|
||||||
|
}
|
@ -16,12 +16,12 @@ export default function Header(props: Props) {
|
|||||||
if (!primaryAsset || !secondaryAsset) return null
|
if (!primaryAsset || !secondaryAsset) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<DoubleLogo primaryDenom={props.primaryDenom} secondaryDenom={props.secondaryDenom} />
|
<DoubleLogo primaryDenom={props.primaryDenom} secondaryDenom={props.secondaryDenom} />
|
||||||
<Text>{`${primaryAsset.symbol} - ${secondaryAsset.symbol}`}</Text>
|
<Text>{`${primaryAsset.symbol} - ${secondaryAsset.symbol}`}</Text>
|
||||||
<Text className='rounded-sm gradient-hls px-2 font-bold py-0.5' size='xs'>
|
<Text className='rounded-sm gradient-hls px-2 font-bold py-0.5' size='xs'>
|
||||||
HLS
|
HLS
|
||||||
</Text>
|
</Text>
|
||||||
</span>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ export default function Leverage(props: Props) {
|
|||||||
asset={props.asset}
|
asset={props.asset}
|
||||||
max={props.max}
|
max={props.max}
|
||||||
onChange={props.onChangeAmount}
|
onChange={props.onChangeAmount}
|
||||||
|
maxText='Max borrow'
|
||||||
/>
|
/>
|
||||||
<LeverageSummary asset={props.asset} />
|
<LeverageSummary asset={props.asset} />
|
||||||
<Button onClick={props.onClickBtn} text='Continue' rightIcon={<ArrowRight />} />
|
<Button onClick={props.onClickBtn} text='Continue' rightIcon={<ArrowRight />} />
|
||||||
|
@ -29,11 +29,15 @@ export default function LeverageSummary(props: Props) {
|
|||||||
}, [props.asset.symbol])
|
}, [props.asset.symbol])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-2'>
|
<div className='grid grid-cols-2 gap-2'>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<React.Fragment key={item.title}>
|
<React.Fragment key={item.title}>
|
||||||
<Text className='text-white/60'>{item.title}</Text>
|
<Text className='text-white/60 text-xs'>{item.title}</Text>
|
||||||
<FormattedNumber className='place-self-end' amount={item.amount} options={item.options} />
|
<FormattedNumber
|
||||||
|
className='place-self-end text-xs'
|
||||||
|
amount={item.amount}
|
||||||
|
options={item.options}
|
||||||
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@ import React from 'react'
|
|||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
import { formatAmountWithSymbol, formatLeverage } from 'utils/formatters'
|
||||||
|
|
||||||
interface SubTitleProps {
|
interface SubTitleProps {
|
||||||
text: string
|
text: string
|
||||||
@ -46,7 +46,7 @@ export function LeverageSubTitle(props: LeveragedSubTitleProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SubTitle text={`${props.leverage}x • Total Position Value `} />
|
<SubTitle text={`${formatLeverage(props.leverage)} • Total Position Value `} />
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={BNCoin.fromDenomAndBigNumber('usd', props.positionValue)}
|
coin={BNCoin.fromDenomAndBigNumber('usd', props.positionValue)}
|
||||||
className='text-white/60 text-xs inline'
|
className='text-white/60 text-xs inline'
|
||||||
|
@ -16,7 +16,7 @@ export default function AprBreakdown(props: Props) {
|
|||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={item.amount}
|
amount={item.amount}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
options={{ suffix: '%', maxDecimals: 2, minDecimals: 0 }}
|
options={{ suffix: '%', maxDecimals: 2, minDecimals: 2 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -6,31 +6,32 @@ import AssetSummary from 'components/Modals/HLS/Summary/AssetSummary'
|
|||||||
import YourPosition from 'components/Modals/HLS/Summary/YourPosition'
|
import YourPosition from 'components/Modals/HLS/Summary/YourPosition'
|
||||||
import useBorrowAsset from 'hooks/useBorrowAsset'
|
import useBorrowAsset from 'hooks/useBorrowAsset'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
apy: number
|
||||||
borrowAmount: BigNumber
|
borrowAmount: BigNumber
|
||||||
|
borrowAsset: Asset
|
||||||
|
collateralAsset: Asset
|
||||||
depositAmount: BigNumber
|
depositAmount: BigNumber
|
||||||
|
leverage: number
|
||||||
onClickBtn: () => void
|
onClickBtn: () => void
|
||||||
positionValue: BigNumber
|
positionValue: BigNumber
|
||||||
vault: Vault
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Summary(props: Props) {
|
export default function Summary(props: Props) {
|
||||||
const collateralAsset = getAssetByDenom(props.vault.denoms.primary)
|
const borrowAsset = useBorrowAsset(props.borrowAsset.denom)
|
||||||
const borrowAsset = useBorrowAsset(props.vault.denoms.secondary)
|
|
||||||
|
|
||||||
if (!collateralAsset || !borrowAsset) return null
|
if (!borrowAsset) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='p-4 flex flex-col gap-4'>
|
<div className='p-4 flex flex-col gap-4'>
|
||||||
<AssetSummary asset={collateralAsset} amount={props.depositAmount} />
|
<AssetSummary asset={props.collateralAsset} amount={props.depositAmount} />
|
||||||
<AssetSummary asset={borrowAsset} amount={props.borrowAmount} isBorrow />
|
<AssetSummary asset={borrowAsset} amount={props.borrowAmount} isBorrow />
|
||||||
<YourPosition
|
<YourPosition
|
||||||
positionValue={BNCoin.fromDenomAndBigNumber('usd', props.positionValue)}
|
positionValue={BNCoin.fromDenomAndBigNumber('usd', props.positionValue)}
|
||||||
baseApy={props.vault.apy || 0}
|
baseApy={props.apy || 0}
|
||||||
borrowRate={borrowAsset.borrowRate || 0}
|
borrowRate={borrowAsset.borrowRate || 0}
|
||||||
leverage={3.5}
|
leverage={props.leverage}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={props.onClickBtn}
|
onClick={props.onClickBtn}
|
||||||
|
@ -8,13 +8,30 @@ import useStore from 'store'
|
|||||||
export default function HlsModalController() {
|
export default function HlsModalController() {
|
||||||
const modal = useStore((s) => s.hlsModal)
|
const modal = useStore((s) => s.hlsModal)
|
||||||
|
|
||||||
if (!modal?.vault) return null
|
if (modal?.vault)
|
||||||
|
return (
|
||||||
|
<HlsModal
|
||||||
|
collateralDenom={modal.vault.denoms.primary}
|
||||||
|
borrowDenom={modal.vault.denoms.secondary}
|
||||||
|
vaultAddress={modal.vault.address}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
if (modal?.strategy)
|
||||||
|
return (
|
||||||
|
<HlsModal
|
||||||
|
collateralDenom={modal.strategy.denoms.deposit}
|
||||||
|
borrowDenom={modal.strategy.denoms.borrow}
|
||||||
|
vaultAddress={null}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
return <HlsModal vault={modal.vault} />
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault
|
borrowDenom: string
|
||||||
|
collateralDenom: string
|
||||||
|
vaultAddress: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
function HlsModal(props: Props) {
|
function HlsModal(props: Props) {
|
||||||
@ -24,18 +41,17 @@ function HlsModal(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header={
|
header={<Header primaryDenom={props.collateralDenom} secondaryDenom={props.borrowDenom} />}
|
||||||
<Header
|
|
||||||
primaryDenom={props.vault.denoms.primary}
|
|
||||||
secondaryDenom={props.vault.denoms.secondary}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
headerClassName='gradient-header pl-2 pr-2.5 py-3 border-b-white/5 border-b'
|
headerClassName='gradient-header pl-2 pr-2.5 py-3 border-b-white/5 border-b'
|
||||||
contentClassName='flex flex-col p-6 h-full overflow-y-scroll scrollbar-hide'
|
contentClassName='flex flex-col p-6'
|
||||||
modalClassName='max-w-modal-md h-[min(80%,600px)]'
|
modalClassName='max-w-modal-md'
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
<Content vault={props.vault} />
|
<Content
|
||||||
|
collateralDenom={props.collateralDenom}
|
||||||
|
borrowDenom={props.borrowDenom}
|
||||||
|
vaultAddress={props.vaultAddress}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
|||||||
deposits: props.deposits,
|
deposits: props.deposits,
|
||||||
borrowings: props.borrowings,
|
borrowings: props.borrowings,
|
||||||
isCreate: vaultModal.isCreate,
|
isCreate: vaultModal.isCreate,
|
||||||
|
kind: 'default',
|
||||||
})
|
})
|
||||||
useStore.setState({ vaultModal: null })
|
useStore.setState({ vaultModal: null })
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ export default function VaultModalContent(props: Props) {
|
|||||||
reclaims: removedLends,
|
reclaims: removedLends,
|
||||||
deposits: removedDeposits,
|
deposits: removedDeposits,
|
||||||
borrowings: addedDebts,
|
borrowings: addedDebts,
|
||||||
|
kind: 'default',
|
||||||
})
|
})
|
||||||
|
|
||||||
const depositCapReachedCoins = useMemo(() => {
|
const depositCapReachedCoins = useMemo(() => {
|
||||||
|
13
src/constants/accounts.ts
Normal file
13
src/constants/accounts.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export const EMPTY_ACCOUNT: Account = {
|
||||||
|
id: '',
|
||||||
|
kind: 'default',
|
||||||
|
debts: [],
|
||||||
|
deposits: [],
|
||||||
|
lends: [],
|
||||||
|
vaults: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EMPTY_ACCOUNT_HLS: Account = {
|
||||||
|
...EMPTY_ACCOUNT,
|
||||||
|
kind: 'high_levered_strategy',
|
||||||
|
}
|
@ -87,6 +87,7 @@ export const VAULTS_META_DATA: VaultMetaData[] = [
|
|||||||
secondary: 'ATOM',
|
secondary: 'ATOM',
|
||||||
},
|
},
|
||||||
isFeatured: false,
|
isFeatured: false,
|
||||||
|
isHls: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
address: 'osmo185gqewrlde8vrqw7j8lpad67v8jfrx9u7770k9q87tqqecctp5tq50wt2c',
|
address: 'osmo185gqewrlde8vrqw7j8lpad67v8jfrx9u7770k9q87tqqecctp5tq50wt2c',
|
||||||
|
@ -6,7 +6,7 @@ import useAutoLend from 'hooks/useAutoLend'
|
|||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
import { AccountKind, Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
import { getLendEnabledAssets } from 'utils/assets'
|
import { getLendEnabledAssets } from 'utils/assets'
|
||||||
import {
|
import {
|
||||||
getEnterVaultActions,
|
getEnterVaultActions,
|
||||||
@ -19,6 +19,7 @@ interface Props {
|
|||||||
reclaims: BNCoin[]
|
reclaims: BNCoin[]
|
||||||
deposits: BNCoin[]
|
deposits: BNCoin[]
|
||||||
borrowings: BNCoin[]
|
borrowings: BNCoin[]
|
||||||
|
kind: AccountKind
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useDepositVault(props: Props): {
|
export default function useDepositVault(props: Props): {
|
||||||
@ -47,6 +48,14 @@ export default function useDepositVault(props: Props): {
|
|||||||
[props.vault, deposits, borrowings, reclaims, prices, slippage],
|
[props.vault, deposits, borrowings, reclaims, prices, slippage],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const depositActions: Action[] = useMemo(() => {
|
||||||
|
if (props.kind === 'default') return []
|
||||||
|
|
||||||
|
return deposits.map((bnCoin) => ({
|
||||||
|
deposit: bnCoin.toCoin(),
|
||||||
|
}))
|
||||||
|
}, [deposits, props.kind])
|
||||||
|
|
||||||
const reclaimActions: Action[] = useMemo(() => {
|
const reclaimActions: Action[] = useMemo(() => {
|
||||||
return reclaims.map((bnCoin) => ({
|
return reclaims.map((bnCoin) => ({
|
||||||
reclaim: bnCoin.toActionCoin(),
|
reclaim: bnCoin.toActionCoin(),
|
||||||
@ -71,7 +80,7 @@ export default function useDepositVault(props: Props): {
|
|||||||
}, [props.vault, primaryCoin, secondaryCoin, slippage])
|
}, [props.vault, primaryCoin, secondaryCoin, slippage])
|
||||||
|
|
||||||
const lendActions: Action[] = useMemo(() => {
|
const lendActions: Action[] = useMemo(() => {
|
||||||
if (!isAutoLend) return []
|
if (!isAutoLend || props.kind === 'high_levered_strategy') return []
|
||||||
|
|
||||||
const denoms = [props.vault.denoms.primary, props.vault.denoms.secondary]
|
const denoms = [props.vault.denoms.primary, props.vault.denoms.secondary]
|
||||||
const denomsForLend = getLendEnabledAssets()
|
const denomsForLend = getLendEnabledAssets()
|
||||||
@ -84,17 +93,37 @@ export default function useDepositVault(props: Props): {
|
|||||||
amount: 'account_balance',
|
amount: 'account_balance',
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}, [isAutoLend, props.vault.denoms.primary, props.vault.denoms.secondary])
|
}, [isAutoLend, props.kind, props.vault.denoms.primary, props.vault.denoms.secondary])
|
||||||
|
|
||||||
|
const refundActions: Action[] = useMemo(() => {
|
||||||
|
if (props.kind === 'default') return []
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
refund_all_coin_balances: {},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [props.kind])
|
||||||
|
|
||||||
const actions = useMemo(() => {
|
const actions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
|
...depositActions,
|
||||||
...reclaimActions,
|
...reclaimActions,
|
||||||
...borrowActions,
|
...borrowActions,
|
||||||
...swapActions,
|
...swapActions,
|
||||||
...enterVaultActions,
|
...enterVaultActions,
|
||||||
...lendActions,
|
...lendActions,
|
||||||
|
...refundActions,
|
||||||
]
|
]
|
||||||
}, [reclaimActions, borrowActions, swapActions, enterVaultActions, lendActions])
|
}, [
|
||||||
|
depositActions,
|
||||||
|
reclaimActions,
|
||||||
|
borrowActions,
|
||||||
|
swapActions,
|
||||||
|
enterVaultActions,
|
||||||
|
lendActions,
|
||||||
|
refundActions,
|
||||||
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
actions,
|
actions,
|
||||||
|
@ -3,10 +3,11 @@ import { useMemo, useState } from 'react'
|
|||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getValueFromBNCoins } from 'utils/helpers'
|
import { getCoinValue } from 'utils/formatters'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault
|
borrowDenom: string
|
||||||
|
collateralDenom: string
|
||||||
}
|
}
|
||||||
export default function useDepositHlsVault(props: Props) {
|
export default function useDepositHlsVault(props: Props) {
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
@ -14,17 +15,21 @@ export default function useDepositHlsVault(props: Props) {
|
|||||||
const [depositAmount, setDepositAmount] = useState<BigNumber>(BN_ZERO)
|
const [depositAmount, setDepositAmount] = useState<BigNumber>(BN_ZERO)
|
||||||
const [borrowAmount, setBorrowAmount] = useState<BigNumber>(BN_ZERO)
|
const [borrowAmount, setBorrowAmount] = useState<BigNumber>(BN_ZERO)
|
||||||
|
|
||||||
const positionValue = useMemo(() => {
|
const { positionValue, leverage } = useMemo(() => {
|
||||||
if (!prices.length) return BN_ZERO
|
const collateralValue = getCoinValue(
|
||||||
|
BNCoin.fromDenomAndBigNumber(props.collateralDenom, depositAmount),
|
||||||
return getValueFromBNCoins(
|
|
||||||
[
|
|
||||||
BNCoin.fromDenomAndBigNumber(props.vault.denoms.primary, depositAmount),
|
|
||||||
BNCoin.fromDenomAndBigNumber(props.vault.denoms.secondary, borrowAmount),
|
|
||||||
],
|
|
||||||
prices,
|
prices,
|
||||||
)
|
)
|
||||||
}, [prices, depositAmount, borrowAmount])
|
const borrowValue = getCoinValue(
|
||||||
|
BNCoin.fromDenomAndBigNumber(props.borrowDenom, borrowAmount),
|
||||||
|
prices,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
positionValue: collateralValue.plus(borrowValue),
|
||||||
|
leverage: borrowValue.dividedBy(collateralValue).plus(1).toNumber() || 1,
|
||||||
|
}
|
||||||
|
}, [borrowAmount, depositAmount, prices, props.collateralDenom, props.borrowDenom])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setDepositAmount,
|
setDepositAmount,
|
||||||
@ -32,5 +37,6 @@ export default function useDepositHlsVault(props: Props) {
|
|||||||
setBorrowAmount,
|
setBorrowAmount,
|
||||||
borrowAmount,
|
borrowAmount,
|
||||||
positionValue,
|
positionValue,
|
||||||
|
leverage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
||||||
import {
|
import {
|
||||||
AccountKind,
|
|
||||||
AssetParamsBaseForAddr,
|
AssetParamsBaseForAddr,
|
||||||
HealthComputer,
|
HealthComputer,
|
||||||
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||||
@ -114,6 +113,7 @@ export default function useHealthComputer(account?: Account) {
|
|||||||
|
|
||||||
const healthComputer: HealthComputer | null = useMemo(() => {
|
const healthComputer: HealthComputer | null = useMemo(() => {
|
||||||
if (
|
if (
|
||||||
|
!account ||
|
||||||
!positions ||
|
!positions ||
|
||||||
!vaultPositionValues ||
|
!vaultPositionValues ||
|
||||||
!vaultConfigsData ||
|
!vaultConfigsData ||
|
||||||
@ -130,9 +130,9 @@ export default function useHealthComputer(account?: Account) {
|
|||||||
vault_values: vaultPositionValues,
|
vault_values: vaultPositionValues,
|
||||||
},
|
},
|
||||||
positions: positions,
|
positions: positions,
|
||||||
kind: 'default' as AccountKind,
|
kind: account.kind,
|
||||||
}
|
}
|
||||||
}, [priceData, denomsData, vaultConfigsData, vaultPositionValues, positions])
|
}, [account, positions, vaultPositionValues, vaultConfigsData, denomsData, priceData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!healthComputer) return
|
if (!healthComputer) return
|
||||||
|
9
src/hooks/useVault.tsx
Normal file
9
src/hooks/useVault.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import useVaults from 'hooks/useVaults'
|
||||||
|
|
||||||
|
export default function useVault(address: string) {
|
||||||
|
const { data: vaults } = useVaults(false)
|
||||||
|
|
||||||
|
if (!vaults?.length) return null
|
||||||
|
|
||||||
|
return vaults.find((v) => v.address === address) ?? null
|
||||||
|
}
|
@ -423,6 +423,7 @@ export default function createBroadcastSlice(
|
|||||||
deposits: BNCoin[]
|
deposits: BNCoin[]
|
||||||
borrowings: BNCoin[]
|
borrowings: BNCoin[]
|
||||||
isCreate: boolean
|
isCreate: boolean
|
||||||
|
kind: AccountKind
|
||||||
}) => {
|
}) => {
|
||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
update_credit_account: {
|
update_credit_account: {
|
||||||
@ -432,7 +433,14 @@ export default function createBroadcastSlice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = get().executeMsg({
|
const response = get().executeMsg({
|
||||||
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
messages: [
|
||||||
|
generateExecutionMessage(
|
||||||
|
get().address,
|
||||||
|
ENV.ADDRESS_CREDIT_MANAGER,
|
||||||
|
msg,
|
||||||
|
options.kind === 'default' ? [] : options.deposits.map((coin) => coin.toCoin()),
|
||||||
|
),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const depositedCoins = getVaultDepositCoinsFromActions(options.actions)
|
const depositedCoins = getVaultDepositCoinsFromActions(options.actions)
|
||||||
|
1
src/types/interfaces/store/broadcast.d.ts
vendored
1
src/types/interfaces/store/broadcast.d.ts
vendored
@ -96,6 +96,7 @@ interface BroadcastSlice {
|
|||||||
deposits: BNCoin[]
|
deposits: BNCoin[]
|
||||||
borrowings: BNCoin[]
|
borrowings: BNCoin[]
|
||||||
isCreate: boolean
|
isCreate: boolean
|
||||||
|
kind: import('types/generated/mars-rover-health-types/MarsRoverHealthTypes.types').AccountKind
|
||||||
}) => Promise<boolean>
|
}) => Promise<boolean>
|
||||||
executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise<BroadcastResult>
|
executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise<BroadcastResult>
|
||||||
lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
|
lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
|
||||||
|
3
src/types/interfaces/store/modals.d.ts
vendored
3
src/types/interfaces/store/modals.d.ts
vendored
@ -70,5 +70,6 @@ interface WalletAssetModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface HlsModal {
|
interface HlsModal {
|
||||||
vault: Vault
|
strategy?: HLSStrategy
|
||||||
|
vault?: Vault
|
||||||
}
|
}
|
||||||
|
1
src/types/interfaces/vaults.d.ts
vendored
1
src/types/interfaces/vaults.d.ts
vendored
@ -19,6 +19,7 @@ interface VaultMetaData {
|
|||||||
secondary: string
|
secondary: string
|
||||||
}
|
}
|
||||||
isFeatured?: boolean
|
isFeatured?: boolean
|
||||||
|
isHls?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VaultInfo {
|
interface VaultInfo {
|
||||||
|
@ -272,3 +272,12 @@ export function getAccountSummaryStats(
|
|||||||
leverage,
|
leverage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAccountEmpty(account: Account) {
|
||||||
|
return (
|
||||||
|
account.vaults.length === 0 &&
|
||||||
|
account.lends.length === 0 &&
|
||||||
|
account.debts.length === 0 &&
|
||||||
|
account.deposits.length === 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user