Compare commits

..
2 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
130 changed files with 880 additions and 2011 deletions
+1 -8
View File
@@ -10,12 +10,7 @@ import {
TotalDepositResponse, TotalDepositResponse,
VaultConfigBaseForAddr, VaultConfigBaseForAddr,
} from 'types/generated/mars-params/MarsParams.types' } from 'types/generated/mars-params/MarsParams.types'
import { import { ArrayOfMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
ArrayOfMarket,
ArrayOfUserCollateralResponse,
ArrayOfUserDebtResponse,
UserCollateralResponse,
} from 'types/generated/mars-red-bank/MarsRedBank.types'
interface Cache<T> extends Map<string, { data: T | null; timestamp: number }> {} interface Cache<T> extends Map<string, { data: T | null; timestamp: number }> {}
@@ -67,5 +62,3 @@ export const underlyingDebtCache: Cache<string> = new Map()
export const previewDepositCache: Cache<{ vaultAddress: string; amount: string }> = new Map() export const previewDepositCache: Cache<{ vaultAddress: string; amount: string }> = new Map()
export const stakingAprCache: Cache<StakingApr[]> = new Map() export const stakingAprCache: Cache<StakingApr[]> = new Map()
export const assetParamsCache: Cache<AssetParamsBaseForAddr[]> = new Map() export const assetParamsCache: Cache<AssetParamsBaseForAddr[]> = new Map()
export const userCollateralCache: Cache<ArrayOfUserCollateralResponse> = new Map()
export const userDebtCache: Cache<ArrayOfUserDebtResponse> = new Map()
+8 -29
View File
@@ -6,9 +6,7 @@ import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMo
import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client' import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client'
import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client' import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client'
import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client' import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client'
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client' import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
import { getUrl } from 'utils/url'
let _cosmWasmClient: Map<string, CosmWasmClient> = new Map() let _cosmWasmClient: Map<string, CosmWasmClient> = new Map()
let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map() let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map()
@@ -17,7 +15,6 @@ let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map()
let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map() let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map()
let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map() let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map()
let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map() let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map()
let _redBankQueryClient: Map<string, MarsRedBankQueryClient> = new Map()
const getClient = async (rpc: string) => { const getClient = async (rpc: string) => {
try { try {
@@ -35,7 +32,7 @@ const getClient = async (rpc: string) => {
const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => { const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.creditManager const contract = chainConfig.contracts.creditManager
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_creditManagerQueryClient.get(key)) { if (!_creditManagerQueryClient.get(key)) {
@@ -52,7 +49,7 @@ const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
const getParamsQueryClient = async (chainConfig: ChainConfig) => { const getParamsQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.params const contract = chainConfig.contracts.params
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_paramsQueryClient.get(key)) { if (!_paramsQueryClient.get(key)) {
@@ -69,7 +66,7 @@ const getParamsQueryClient = async (chainConfig: ChainConfig) => {
const getOracleQueryClient = async (chainConfig: ChainConfig) => { const getOracleQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.oracle const contract = chainConfig.contracts.oracle
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_oracleQueryClient.get(key)) { if (!_oracleQueryClient.get(key)) {
@@ -85,7 +82,7 @@ const getOracleQueryClient = async (chainConfig: ChainConfig) => {
const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => { const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => {
try { try {
const client = await getClient(getUrl(chainConfig.endpoints.rpc)) const client = await getClient(chainConfig.endpoints.rpc)
return new MarsMockVaultQueryClient(client, address) return new MarsMockVaultQueryClient(client, address)
} catch (error) { } catch (error) {
throw error throw error
@@ -95,7 +92,7 @@ const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) =>
const getIncentivesQueryClient = async (chainConfig: ChainConfig) => { const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.incentives const contract = chainConfig.contracts.incentives
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_incentivesQueryClient.get(key)) { if (!_incentivesQueryClient.get(key)) {
const client = await getClient(rpc) const client = await getClient(rpc)
@@ -111,7 +108,7 @@ const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
const getSwapperQueryClient = async (chainConfig: ChainConfig) => { const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.swapper const contract = chainConfig.contracts.swapper
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_swapperOsmosisClient.get(key)) { if (!_swapperOsmosisClient.get(key)) {
const client = await getClient(rpc) const client = await getClient(rpc)
@@ -127,7 +124,7 @@ const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
const getPerpsQueryClient = async (chainConfig: ChainConfig) => { const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.perps const contract = chainConfig.contracts.perps
const rpc = getUrl(chainConfig.endpoints.rpc) const rpc = chainConfig.endpoints.rpc
const key = rpc + contract const key = rpc + contract
if (!_perpsClient.get(key)) { if (!_perpsClient.get(key)) {
const client = await getClient(rpc) const client = await getClient(rpc)
@@ -140,31 +137,13 @@ const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
} }
} }
const getRedBankQueryClient = async (chainConfig: ChainConfig) => {
try {
const contract = chainConfig.contracts.redBank
const rpc = getUrl(chainConfig.endpoints.rpc)
const key = rpc + contract
if (!_redBankQueryClient.get(key)) {
const client = await getClient(rpc)
_redBankQueryClient.set(key, new MarsRedBankQueryClient(client, contract))
}
return _redBankQueryClient.get(key)!
} catch (error) {
throw error
}
}
export { export {
getClient, getClient,
getCreditManagerQueryClient, getCreditManagerQueryClient,
getIncentivesQueryClient, getIncentivesQueryClient,
getOracleQueryClient, getOracleQueryClient,
getParamsQueryClient, getParamsQueryClient,
getPerpsQueryClient,
getRedBankQueryClient,
getSwapperQueryClient, getSwapperQueryClient,
getVaultQueryClient, getVaultQueryClient,
getPerpsQueryClient,
} }
-41
View File
@@ -1,41 +0,0 @@
import { cacheFn, userCollateralCache, userDebtCache } from 'api/cache'
import { getRedBankQueryClient } from 'api/cosmwasm-client'
import { BNCoin } from 'types/classes/BNCoin'
import {
ArrayOfUserCollateralResponse,
ArrayOfUserDebtResponse,
} from 'types/generated/mars-red-bank/MarsRedBank.types'
export default async function getV1Positions(
chainConfig: ChainConfig,
user?: string,
): Promise<Account> {
if (!user) return new Promise((_, reject) => reject('No account Wallet ID found'))
const redBankQueryClient = await getRedBankQueryClient(chainConfig)
const userCollateral: ArrayOfUserCollateralResponse = await cacheFn(
() => redBankQueryClient.userCollaterals({ user: user, limit: 100 }),
userCollateralCache,
`${chainConfig.id}/v1/deposits/${user}`,
)
const userDebt: ArrayOfUserDebtResponse = await cacheFn(
() => redBankQueryClient.userDebts({ user: user, limit: 100 }),
userDebtCache,
`${chainConfig.id}/v1/debts/${user}`,
)
if (userCollateral && userDebt) {
return {
id: user,
debts: userDebt.map((debt) => new BNCoin(debt)),
lends: userCollateral.map((lend) => new BNCoin(lend)),
deposits: [],
vaults: [],
perps: [],
kind: 'default',
}
}
return new Promise((_, reject) => reject('No account found'))
}
@@ -10,12 +10,12 @@ import Text from 'components/common/Text'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider' import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import AssetImage from 'components/common/assets/AssetImage' import AssetImage from 'components/common/assets/AssetImage'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
interface Props { interface Props {
account: Account
asset: Asset asset: Asset
title: string title: string
coinBalances: BNCoin[] coinBalances: BNCoin[]
@@ -29,7 +29,6 @@ interface Props {
export default function AssetAmountSelectActionModal(props: Props) { export default function AssetAmountSelectActionModal(props: Props) {
const { const {
account,
asset, asset,
title, title,
coinBalances, coinBalances,
@@ -42,6 +41,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
} = props } = props
const [amount, setAmount] = useState(BN_ZERO) const [amount, setAmount] = useState(BN_ZERO)
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0) const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
const account = useCurrentAccount()
const handleAmountChange = useCallback( const handleAmountChange = useCallback(
(value: BigNumber) => { (value: BigNumber) => {
setAmount(value) setAmount(value)
@@ -54,6 +54,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
onAction(amount, amount.isEqualTo(maxAmount)) onAction(amount, amount.isEqualTo(maxAmount))
}, [amount, maxAmount, onAction]) }, [amount, maxAmount, onAction])
if (!account) return
return ( return (
<Modal <Modal
onClose={onClose} onClose={onClose}
+55 -43
View File
@@ -35,9 +35,18 @@ interface Props {
modal: BorrowModal modal: BorrowModal
} }
function getDebtAmount(modal: BorrowModal) {
return BN((modal.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
}
function getAssetLogo(modal: BorrowModal) {
if (!modal.asset) return null
return <AssetImage asset={modal.asset} size={24} />
}
function RepayNotAvailable(props: { asset: Asset; repayFromWallet: boolean }) { function RepayNotAvailable(props: { asset: Asset; repayFromWallet: boolean }) {
return ( return (
<Card className='w-full'> <Card className='mt-6'>
<div className='flex items-start p-4'> <div className='flex items-start p-4'>
<InfoCircle className='w-6 mr-2 flex-0' /> <InfoCircle className='w-6 mr-2 flex-0' />
<div className='flex flex-col flex-1 gap-1'> <div className='flex flex-col flex-1 gap-1'>
@@ -81,6 +90,7 @@ function BorrowModal(props: Props) {
const apy = modal.marketData.apy.borrow const apy = modal.marketData.apy.borrow
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id) const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
const { computeMaxBorrowAmount } = useHealthComputer(account) const { computeMaxBorrowAmount } = useHealthComputer(account)
const totalDebt = BN(getDebtAmount(modal))
const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO
const markets = useMarkets() const markets = useMarkets()
@@ -227,7 +237,7 @@ function BorrowModal(props: Props) {
onClose={onClose} onClose={onClose}
header={ header={
<span className='flex items-center gap-4 px-4'> <span className='flex items-center gap-4 px-4'>
<AssetImage asset={asset} size={24} /> {getAssetLogo(modal)}
<Text> <Text>
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol} {isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
</Text> </Text>
@@ -241,14 +251,14 @@ function BorrowModal(props: Props) {
title={formatPercent(modal.marketData.apy.borrow)} title={formatPercent(modal.marketData.apy.borrow)}
sub={'Borrow Rate APY'} sub={'Borrow Rate APY'}
/> />
{accountDebt.isGreaterThan(0) && ( {totalDebt.isGreaterThan(0) && (
<> <>
<div className='h-100 w-[1px] bg-white/10' /> <div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'> <div className='flex flex-col gap-0.5'>
<div className='flex gap-2'> <div className='flex gap-2'>
<FormattedNumber <FormattedNumber
className='text-xs' className='text-xs'
amount={accountDebt.toNumber()} amount={totalDebt.toNumber()}
options={{ options={{
decimals: asset.decimals, decimals: asset.decimals,
abbreviated: false, abbreviated: false,
@@ -257,7 +267,7 @@ function BorrowModal(props: Props) {
/> />
<DisplayCurrency <DisplayCurrency
className='text-xs' className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)} coin={BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)}
parentheses parentheses
/> />
</div> </div>
@@ -293,57 +303,59 @@ function BorrowModal(props: Props) {
<div className='flex items-start flex-1 gap-6 p-6'> <div className='flex items-start flex-1 gap-6 p-6'>
<Card <Card
className='flex flex-1 p-4 bg-white/5' className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full' contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
> >
<TokenInputWithSlider <div className='flex flex-wrap w-full'>
asset={asset} <TokenInputWithSlider
onChange={handleChange} asset={asset}
onDebounce={onDebounce} onChange={handleChange}
amount={amount} onDebounce={onDebounce}
max={max} amount={amount}
disabled={max.isZero()} max={max}
className='w-full' disabled={max.isZero()}
maxText='Max' className='w-full'
warningMessages={[]} maxText='Max'
/> warningMessages={[]}
{isRepay && maxRepayAmount.isZero() && ( />
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} /> {isRepay && maxRepayAmount.isZero() && (
)} <RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
{isRepay ? ( )}
<> {isRepay ? (
<Divider /> <>
<div className='flex items-center w-full'> <Divider className='my-6' />
<div className='flex flex-wrap flex-1'> <div className='flex flex-wrap flex-1'>
<Text className='w-full mb-1'>Repay from Wallet</Text> <Text className='w-full mb-1'>Repay from Wallet</Text>
<Text size='xs' className='text-white/50'> <Text size='xs' className='text-white/50'>
Repay your debt directly from your wallet Repay your debt directly from your wallet
</Text> </Text>
</div> </div>
<Switch <div className='flex flex-wrap items-center justify-end'>
name='borrow-to-wallet' <Switch
checked={repayFromWallet} name='borrow-to-wallet'
onChange={setRepayFromWallet} checked={repayFromWallet}
/> onChange={setRepayFromWallet}
</div> />
</> </div>
) : ( </>
<> ) : (
<Divider /> <>
<div className='flex items-center w-full'> <Divider className='my-6' />
<div className='flex flex-wrap flex-1'> <div className='flex flex-wrap flex-1'>
<Text className='w-full mb-1'>Receive funds to Wallet</Text> <Text className='w-full mb-1'>Receive funds to Wallet</Text>
<Text size='xs' className='text-white/50'> <Text size='xs' className='text-white/50'>
Your borrowed funds will directly go to your wallet Your borrowed funds will directly go to your wallet
</Text> </Text>
</div> </div>
<Switch <div className='flex flex-wrap items-center justify-end'>
name='borrow-to-wallet' <Switch
checked={borrowToWallet} name='borrow-to-wallet'
onChange={setBorrowToWallet} checked={borrowToWallet}
/> onChange={setBorrowToWallet}
</div> />
</> </div>
)} </>
)}
</div>
<Button <Button
onClick={onConfirmClick} onClick={onConfirmClick}
className='w-full' className='w-full'
@@ -23,7 +23,6 @@ interface Props {
} }
function LendAndReclaimModal({ currentAccount, config }: Props) { function LendAndReclaimModal({ currentAccount, config }: Props) {
const account = useCurrentAccount()
const lend = useStore((s) => s.lend) const lend = useStore((s) => s.lend)
const reclaim = useStore((s) => s.reclaim) const reclaim = useStore((s) => s.reclaim)
const { close } = useLendAndReclaimModal() const { close } = useLendAndReclaimModal()
@@ -66,11 +65,8 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
}, },
[asset.denom, close, currentAccount.id, isLendAction, lend, reclaim], [asset.denom, close, currentAccount.id, isLendAction, lend, reclaim],
) )
if (!account) return null
return ( return (
<AssetAmountSelectActionModal <AssetAmountSelectActionModal
account={account}
asset={asset} asset={asset}
contentHeader={<DetailsHeader data={data} />} contentHeader={<DetailsHeader data={data} />}
coinBalances={coinBalances} coinBalances={coinBalances}
@@ -10,8 +10,6 @@ import {
LendAndReclaimModalController, LendAndReclaimModalController,
SettingsModal, SettingsModal,
UnlockModal, UnlockModal,
V1BorrowAndRepay,
V1DepositAndWithdraw,
VaultModal, VaultModal,
WalletAssets, WalletAssets,
WithdrawFromVaultsModal, WithdrawFromVaultsModal,
@@ -34,8 +32,6 @@ export default function ModalsContainer() {
<AlertDialogController /> <AlertDialogController />
<HlsModal /> <HlsModal />
<HlsManageModal /> <HlsManageModal />
<V1DepositAndWithdraw />
<V1BorrowAndRepay />
</> </>
) )
} }
+2 -4
View File
@@ -4,13 +4,11 @@ export { default as AlertDialogController } from 'components/Modals/AlertDialog'
export { default as BorrowModal } from 'components/Modals/BorrowModal' export { default as BorrowModal } from 'components/Modals/BorrowModal'
export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw' export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw'
export { default as GetStartedModal } from 'components/Modals/GetStartedModal' export { default as GetStartedModal } from 'components/Modals/GetStartedModal'
export { default as HlsModal } from 'components/Modals/HLS'
export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
export { default as LendAndReclaimModalController } from 'components/Modals/LendAndReclaim' export { default as LendAndReclaimModalController } from 'components/Modals/LendAndReclaim'
export { default as SettingsModal } from 'components/Modals/Settings' export { default as SettingsModal } from 'components/Modals/Settings'
export { default as UnlockModal } from 'components/Modals/Unlock' export { default as UnlockModal } from 'components/Modals/Unlock'
export { default as VaultModal } from 'components/Modals/Vault' export { default as VaultModal } from 'components/Modals/Vault'
export { default as WalletAssets } from 'components/Modals/WalletAssets' export { default as WalletAssets } from 'components/Modals/WalletAssets'
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal' export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
export { default as V1BorrowAndRepay } from 'components/Modals/v1/V1BorrowAndRepay' export { default as HlsModal } from 'components/Modals/HLS'
export { default as V1DepositAndWithdraw } from 'components/Modals/v1/V1DepositAndWithdraw' export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
-179
View File
@@ -1,179 +0,0 @@
import BigNumber from 'bignumber.js'
import { useCallback, useEffect, useMemo, useState } from 'react'
import Modal from 'components/Modals/Modal'
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
import Button from 'components/common/Button'
import Card from 'components/common/Card'
import DisplayCurrency from 'components/common/DisplayCurrency'
import Divider from 'components/common/Divider'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight } from 'components/common/Icons'
import Text from 'components/common/Text'
import TitleAndSubCell from 'components/common/TitleAndSubCell'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import AssetImage from 'components/common/assets/AssetImage'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useHealthComputer from 'hooks/useHealthComputer'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { formatPercent } from 'utils/formatters'
import { getDebtAmountWithInterest } from 'utils/tokens'
interface Props {
account: Account
}
export default function Borrow(props: Props) {
const { account } = props
const modal = useStore((s) => s.v1BorrowAndRepayModal)
const baseAsset = useBaseAsset()
const [amount, setAmount] = useState(BN_ZERO)
const v1Action = useStore((s) => s.v1Action)
const asset = modal?.data.asset ?? baseAsset
const [max, setMax] = useState(BN_ZERO)
const { simulateBorrow } = useUpdatedAccount(account)
const apy = modal?.data.apy.borrow ?? 0
const { computeMaxBorrowAmount } = useHealthComputer(account)
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
const accountDebtWithInterest = useMemo(
() => getDebtAmountWithInterest(accountDebt, apy),
[accountDebt, apy],
)
const close = useCallback(() => {
setAmount(BN_ZERO)
useStore.setState({ v1BorrowAndRepayModal: null })
}, [setAmount])
const onConfirmClick = useCallback(() => {
v1Action('borrow', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
close()
}, [v1Action, asset, amount, close])
const handleChange = useCallback(
(newAmount: BigNumber) => {
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
},
[amount, setAmount],
)
const onDebounce = useCallback(() => {
const borrowCoin = BNCoin.fromDenomAndBigNumber(
asset.denom,
amount.isGreaterThan(max) ? max : amount,
)
simulateBorrow('wallet', borrowCoin)
}, [amount, max, asset, simulateBorrow])
const maxBorrow = useMemo(() => {
const maxBorrowAmount = computeMaxBorrowAmount(asset.denom, 'wallet')
return BigNumber.min(maxBorrowAmount, modal?.data.liquidity || 0)
}, [asset.denom, computeMaxBorrowAmount, modal?.data.liquidity])
useEffect(() => {
if (maxBorrow.isEqualTo(max)) return
setMax(maxBorrow)
}, [account, maxBorrow, max])
useEffect(() => {
if (amount.isLessThanOrEqualTo(max)) return
handleChange(max)
setAmount(max)
}, [amount, max, handleChange])
if (!modal) return null
return (
<Modal
onClose={close}
header={
<span className='flex items-center gap-4 px-4'>
<AssetImage asset={modal.data.asset} size={24} />
<Text>{`Borrow ${asset.symbol} from the Red Bank`}</Text>
</span>
}
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
contentClassName='flex flex-col'
>
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
{accountDebt.isGreaterThan(0) && (
<>
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={accountDebt.toNumber()}
options={{
decimals: asset.decimals,
abbreviated: false,
suffix: ` ${asset.symbol}`,
}}
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Total Borrowed
</Text>
</div>
</>
)}
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={modal.data.liquidity.toNumber() ?? 0}
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
animate
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data.liquidity ?? BN_ZERO)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Liquidity available
</Text>
</div>
</div>
<div className='flex items-start flex-1 gap-6 p-6'>
<Card
className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full'
>
<TokenInputWithSlider
asset={asset}
onChange={handleChange}
onDebounce={onDebounce}
amount={amount}
max={max}
disabled={max.isZero()}
className='w-full'
maxText='Max'
warningMessages={[]}
/>
<Divider />
<Button
onClick={onConfirmClick}
className='w-full'
disabled={amount.isZero()}
text={`Borrow ${asset.symbol}`}
rightIcon={<ArrowRight />}
/>
</Card>
<AccountSummaryInModal account={account} />
</div>
</Modal>
)
}
-82
View File
@@ -1,82 +0,0 @@
import { useCallback, useEffect, useMemo, useState } from 'react'
import WalletBridges from 'components/Wallet/WalletBridges'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array'
import { defaultFee } from 'utils/constants'
import { BN } from 'utils/helpers'
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
interface Props {
account: Account
}
export default function Deposit(props: Props) {
const { account } = props
const baseAsset = useBaseAsset()
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
const address = useStore((s) => s.address)
const asset = modal?.data.asset ?? baseAsset
const [fundingAsset, setFundingAsset] = useState<BNCoin>(
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
)
const { data: walletBalances } = useWalletBalances(address)
const { simulateDeposits } = useUpdatedAccount(account)
const balance = useCurrentWalletBalance(asset.denom)
const v1Action = useStore((s) => s.v1Action)
const baseBalance = useMemo(
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
[walletBalances, baseAsset],
)
const close = useCallback(() => {
useStore.setState({ v1DepositAndWithdrawModal: null })
}, [])
const handleClick = useCallback(async () => {
v1Action('deposit', fundingAsset)
close()
}, [v1Action, fundingAsset, close])
useEffect(() => {
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
useStore.setState({ focusComponent: { component: <WalletBridges /> } })
}
}, [baseBalance])
const onDebounce = useCallback(() => {
simulateDeposits('lend', [fundingAsset])
}, [fundingAsset, simulateDeposits])
const handleAmountChange = useCallback(
(value: BigNumber) => {
setFundingAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
},
[asset.denom],
)
if (!modal) return
return (
<AssetAmountSelectActionModal
account={account}
asset={asset}
contentHeader={<DetailsHeader data={modal.data} />}
coinBalances={balance ? [BNCoin.fromCoin(balance)] : []}
actionButtonText={`Deposit ${asset.symbol}`}
title={`Deposit ${asset.symbol} into the Red Bank`}
onClose={close}
onAction={handleClick}
onChange={handleAmountChange}
onDebounce={onDebounce}
/>
)
}
-208
View File
@@ -1,208 +0,0 @@
import BigNumber from 'bignumber.js'
import { useCallback, useEffect, useMemo, useState } from 'react'
import Modal from 'components/Modals/Modal'
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
import Button from 'components/common/Button'
import Card from 'components/common/Card'
import DisplayCurrency from 'components/common/DisplayCurrency'
import Divider from 'components/common/Divider'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight, InfoCircle } from 'components/common/Icons'
import Text from 'components/common/Text'
import TitleAndSubCell from 'components/common/TitleAndSubCell'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import AssetImage from 'components/common/assets/AssetImage'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useMarkets from 'hooks/markets/useMarkets'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { formatPercent } from 'utils/formatters'
import { BN } from 'utils/helpers'
import { getDebtAmountWithInterest } from 'utils/tokens'
interface Props {
account: Account
}
function RepayNotAvailable(props: { asset: Asset }) {
return (
<Card className='w-full'>
<div className='flex items-start p-4'>
<InfoCircle className='w-6 mr-2 flex-0' />
<div className='flex flex-col flex-1 gap-1'>
<Text size='sm'>No funds for repay</Text>
<Text
size='xs'
className='text-white/40'
>{`Unfortunately you don't have any ${props.asset.symbol} in your Wallet to repay the debt.`}</Text>
</div>
</div>
</Card>
)
}
export default function Repay(props: Props) {
const { account } = props
const modal = useStore((s) => s.v1BorrowAndRepayModal)
const baseAsset = useBaseAsset()
const asset = modal?.data.asset ?? baseAsset
const [amount, setAmount] = useState(BN_ZERO)
const balance = useCurrentWalletBalance(asset.denom)
const v1Action = useStore((s) => s.v1Action)
const [max, setMax] = useState(BN_ZERO)
const { simulateRepay } = useUpdatedAccount(account)
const apy = modal?.data.apy.borrow ?? 0
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
const markets = useMarkets()
const accountDebtWithInterest = useMemo(
() => getDebtAmountWithInterest(accountDebt, apy),
[accountDebt, apy],
)
const overpayExeedsCap = useMemo(() => {
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
if (!marketAsset) return
const overpayAmount = accountDebtWithInterest.minus(accountDebt)
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
}, [markets, asset.denom, accountDebt, accountDebtWithInterest])
const maxRepayAmount = useMemo(() => {
const maxBalance = BN(balance?.amount ?? 0)
return BigNumber.min(maxBalance, overpayExeedsCap ? accountDebt : accountDebtWithInterest)
}, [accountDebtWithInterest, overpayExeedsCap, accountDebt, balance?.amount])
const close = useCallback(() => {
setAmount(BN_ZERO)
useStore.setState({ v1BorrowAndRepayModal: null })
}, [setAmount])
const onConfirmClick = useCallback(() => {
v1Action('repay', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
close()
}, [v1Action, asset, amount, close])
const handleChange = useCallback(
(newAmount: BigNumber) => {
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
},
[amount, setAmount],
)
const onDebounce = useCallback(() => {
const repayCoin = BNCoin.fromDenomAndBigNumber(
asset.denom,
amount.isGreaterThan(accountDebt) ? accountDebt : amount,
)
simulateRepay(repayCoin, true)
}, [amount, accountDebt, asset, simulateRepay])
useEffect(() => {
if (maxRepayAmount.isEqualTo(max)) return
setMax(maxRepayAmount)
}, [max, maxRepayAmount])
useEffect(() => {
if (amount.isLessThanOrEqualTo(max)) return
handleChange(max)
setAmount(max)
}, [amount, max, handleChange])
if (!modal) return null
return (
<Modal
onClose={close}
header={
<span className='flex items-center gap-4 px-4'>
<AssetImage asset={modal.data.asset} size={24} />
<Text>
{'Repay'} {asset.symbol}
</Text>
</span>
}
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
contentClassName='flex flex-col'
>
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={accountDebt.toNumber()}
options={{
decimals: asset.decimals,
abbreviated: false,
suffix: ` ${asset.symbol}`,
}}
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Total Borrowed
</Text>
</div>
<div className='h-100 w-[1px] bg-white/10' />
<div className='flex flex-col gap-0.5'>
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={modal.data?.liquidity.toNumber() ?? 0}
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
animate
/>
<DisplayCurrency
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data?.liquidity ?? BN_ZERO)}
parentheses
/>
</div>
<Text size='xs' className='text-white/50' tag='span'>
Liquidity available
</Text>
</div>
</div>
<div className='flex items-start flex-1 gap-6 p-6'>
<Card
className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full'
>
<TokenInputWithSlider
asset={asset}
onChange={handleChange}
onDebounce={onDebounce}
amount={amount}
max={max}
disabled={max.isZero()}
className='w-full'
maxText='Max'
warningMessages={[]}
/>
<Divider />
{maxRepayAmount.isZero() && <RepayNotAvailable asset={asset} />}
<Button
onClick={onConfirmClick}
className='w-full'
disabled={amount.isZero()}
text={`Repay ${asset.symbol}`}
rightIcon={<ArrowRight />}
/>
</Card>
<AccountSummaryInModal account={account} />
</div>
</Modal>
)
}
@@ -1,15 +0,0 @@
import useAccount from 'hooks/accounts/useAccount'
import useStore from 'store'
import Borrow from 'components/Modals/v1/Borrow'
import Repay from 'components/Modals/v1/Repay'
export default function V1BorrowAndRepayModal() {
const address = useStore((s) => s.address)
const { data: account } = useAccount(address)
const modal = useStore<V1BorrowAndRepayModal | null>((s) => s.v1BorrowAndRepayModal)
const isBorrow = modal?.type === 'borrow'
if (!modal || !account) return null
if (isBorrow) return <Borrow account={account} />
return <Repay account={account} />
}
@@ -1,15 +0,0 @@
import useAccount from 'hooks/accounts/useAccount'
import useStore from 'store'
import Deposit from 'components/Modals/v1/Deposit'
import Withdraw from 'components/Modals/v1/Withdraw'
export default function V1DepositAndWithdraw() {
const address = useStore((s) => s.address)
const { data: account } = useAccount(address)
const modal = useStore<V1DepositAndWithdrawModal | null>((s) => s.v1DepositAndWithdrawModal)
const isDeposit = modal?.type === 'deposit'
if (!modal || !account) return null
if (isDeposit) return <Deposit account={account} />
return <Withdraw account={account} />
}
-66
View File
@@ -1,66 +0,0 @@
import { useCallback, useState } from 'react'
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useHealthComputer from 'hooks/useHealthComputer'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
account: Account
}
export default function Withdraw(props: Props) {
const { account } = props
const baseAsset = useBaseAsset()
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
const asset = modal?.data.asset ?? baseAsset
const [withdrawAsset, setWithdrawAsset] = useState<BNCoin>(
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
)
const { computeMaxWithdrawAmount } = useHealthComputer(account)
const maxWithdrawAmount = computeMaxWithdrawAmount(asset.denom)
const { simulateWithdraw } = useUpdatedAccount(account)
const balance = BNCoin.fromDenomAndBigNumber(asset.denom, maxWithdrawAmount)
const v1Action = useStore((s) => s.v1Action)
const close = useCallback(() => {
useStore.setState({ v1DepositAndWithdrawModal: null })
}, [])
const handleClick = useCallback(async () => {
v1Action('withdraw', withdrawAsset)
close()
}, [v1Action, withdrawAsset, close])
const onDebounce = useCallback(() => {
simulateWithdraw(false, withdrawAsset)
}, [withdrawAsset, simulateWithdraw])
const handleAmountChange = useCallback(
(value: BigNumber) => {
setWithdrawAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
},
[asset.denom],
)
if (!modal) return
return (
<AssetAmountSelectActionModal
account={account}
asset={asset}
contentHeader={<DetailsHeader data={modal.data} />}
coinBalances={[balance]}
actionButtonText={`Withdraw ${asset.symbol}`}
title={`Withdraw ${asset.symbol} from the Red Bank`}
onClose={close}
onAction={handleClick}
onChange={handleAmountChange}
onDebounce={onDebounce}
/>
)
}
+2 -4
View File
@@ -7,8 +7,8 @@ import Text from 'components/common/Text'
import { TextLink } from 'components/common/TextLink' import { TextLink } from 'components/common/TextLink'
import { generateToastContent } from 'components/common/Toaster' import { generateToastContent } from 'components/common/Toaster'
import useTransactions from 'hooks/localStorage/useTransactions' import useTransactions from 'hooks/localStorage/useTransactions'
import useChainConfig from 'hooks/useChainConfig'
import useStore from 'store' import useStore from 'store'
import useChainConfig from 'hooks/useChainConfig'
export default function RecentTransactions() { export default function RecentTransactions() {
const address = useStore((s) => s.address) const address = useStore((s) => s.address)
@@ -47,9 +47,7 @@ export default function RecentTransactions() {
key={hash} key={hash}
> >
<div className='flex items-start justify-between w-full pb-2'> <div className='flex items-start justify-between w-full pb-2'>
<Text className='flex font-bold'> <Text className='flex font-bold'>Credit Account {accountId}</Text>
{accountId === address ? 'Red Bank' : `Credit Account ${accountId}`}
</Text>
<Text size='sm' className='text-white/70'> <Text size='sm' className='text-white/70'>
{moment.unix(timestamp).format('lll')} {moment.unix(timestamp).format('lll')}
</Text> </Text>
+2 -3
View File
@@ -10,7 +10,6 @@ import useChainConfig from 'hooks/useChainConfig'
import useCurrentWallet from 'hooks/useCurrentWallet' import useCurrentWallet from 'hooks/useCurrentWallet'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
import useStore from 'store' import useStore from 'store'
import { getUrl } from 'utils/url'
interface Props { interface Props {
providerId?: string providerId?: string
@@ -54,7 +53,7 @@ export default function WalletConnecting(props: Props) {
setIsConnecting(true) setIsConnecting(true)
try { try {
const response = await connect({ extensionProviderId, chainId: chainConfig.id }) const response = await connect({ extensionProviderId, chainId: chainConfig.id })
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc)) const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
const walletClient: WalletClient = { const walletClient: WalletClient = {
broadcast, broadcast,
cosmWasmClient: cosmClient, cosmWasmClient: cosmClient,
@@ -138,7 +137,7 @@ export default function WalletConnecting(props: Props) {
setIsConnecting(true) setIsConnecting(true)
try { try {
await mobileConnect({ mobileProviderId, chainId: chainConfig.id }) await mobileConnect({ mobileProviderId, chainId: chainConfig.id })
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc)) const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
const walletClient: WalletClient = { const walletClient: WalletClient = {
broadcast, broadcast,
cosmWasmClient: cosmClient, cosmWasmClient: cosmClient,
+1 -1
View File
@@ -13,7 +13,7 @@ export default function Wallet() {
const address = useStore((s) => s.address) const address = useStore((s) => s.address)
useEffect(() => { useEffect(() => {
if (address && address === currentWallet?.account.address) return if (address) return
useStore.setState({ useStore.setState({
address: undefined, address: undefined,
userDomain: undefined, userDomain: undefined,
@@ -47,7 +47,7 @@ export default function AccountBalancesTable(props: Props) {
const columns = useAccountBalancesColumns(account, showLiquidationPrice) const columns = useAccountBalancesColumns(account, showLiquidationPrice)
if (accountBalanceData.length === 0 && account.id !== address) if (accountBalanceData.length === 0)
return ( return (
<ConditionalWrapper <ConditionalWrapper
condition={!hideCard} condition={!hideCard}
@@ -7,7 +7,7 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight } from 'components/common/Icons' import { ArrowRight } from 'components/common/Icons'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math' import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle' import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
+15 -20
View File
@@ -12,19 +12,18 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import { ThreeDots } from 'components/common/Icons' import { ThreeDots } from 'components/common/Icons'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings' import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys' import { LocalStorageKeys } from 'constants/localStorageKeys'
import { ORACLE_DENOM } from 'constants/oracle' import { ORACLE_DENOM } from 'constants/oracle'
import useAccount from 'hooks/accounts/useAccount'
import useAccountIds from 'hooks/accounts/useAccountIds' import useAccountIds from 'hooks/accounts/useAccountIds'
import useAccounts from 'hooks/accounts/useAccounts' import useAccounts from 'hooks/accounts/useAccounts'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount' import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage' import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId' import useAccountId from 'hooks/useAccountId'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs' import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
@@ -34,40 +33,33 @@ import {
calculateAccountBalanceValue, calculateAccountBalanceValue,
calculateAccountLeverage, calculateAccountLeverage,
} from 'utils/accounts' } from 'utils/accounts'
import { getPage } from 'utils/route'
export default function AccountDetailsController() { export default function AccountDetailsController() {
const address = useStore((s) => s.address) const address = useStore((s) => s.address)
const isHLS = useStore((s) => s.isHLS) const isHLS = useStore((s) => s.isHLS)
const isV1 = useStore((s) => s.isV1)
const { data: _, isLoading } = useAccounts('default', address) const { data: _, isLoading } = useAccounts('default', address)
const { data: accountIds } = useAccountIds(address, false, true) const { data: accountIds } = useAccountIds(address, false, true)
const accountId = useAccountId() const accountId = useAccountId()
const currentAccount = useCurrentAccount()
const { data: v1Account } = useAccount(address)
const { pathname } = useLocation()
const page = getPage(pathname)
const account = isV1 && page !== 'trade' ? v1Account : currentAccount const account = useCurrentAccount()
const focusComponent = useStore((s) => s.focusComponent) const focusComponent = useStore((s) => s.focusComponent)
const isOwnAccount = (accountId && accountIds?.includes(accountId)) || account?.id === address const isOwnAccount = accountId && accountIds?.includes(accountId)
const hideAccountDetails =
!address || focusComponent || !isOwnAccount || isHLS || page.includes('portfolio')
const isLoadingAccountDetails = (isLoading && accountId && !focusComponent) || !account
if (hideAccountDetails) return null if (!address || focusComponent || !isOwnAccount || isHLS) return null
if (isLoadingAccountDetails) return <Skeleton />
return <AccountDetails account={account} page={page} /> if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
return <AccountDetails account={account} />
} }
interface Props { interface Props {
account: Account account: Account
page: Page
} }
function AccountDetails(props: Props) { function AccountDetails(props: Props) {
const { account, page } = props const { account } = props
const location = useLocation()
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs() const { data: vaultAprs } = useVaultAprs()
const [reduceMotion] = useLocalStorage<boolean>( const [reduceMotion] = useLocalStorage<boolean>(
@@ -132,7 +124,10 @@ function AccountDetails(props: Props) {
vaultAprs, vaultAprs,
], ],
) )
const isFullWidth = page === 'trade' || page === 'perps' const isFullWidth =
location.pathname.includes('trade') ||
location.pathname === '/' ||
location.pathname.includes('perps')
return ( return (
<> <>
@@ -6,7 +6,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
import Button from 'components/common/Button' import Button from 'components/common/Button'
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/common/Icons' import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/common/Icons'
import SwitchAutoLend from 'components/common/Switch/SwitchAutoLend' import SwitchAutoLend from 'components/common/Switch/SwitchAutoLend'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount' import useAccount from 'hooks/accounts/useAccount'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
@@ -42,7 +42,6 @@ export default function AccountSummaryHeader(props: Props) {
updatedHealthFactor, updatedHealthFactor,
isAccountDetails, isAccountDetails,
} = props } = props
const address = useStore((s) => s.address)
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), []) const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
const accountBalance = useMemo( const accountBalance = useMemo(
() => (account ? calculateAccountBalanceValue(account, prices, assets) : BN_ZERO), () => (account ? calculateAccountBalanceValue(account, prices, assets) : BN_ZERO),
@@ -69,9 +68,10 @@ export default function AccountSummaryHeader(props: Props) {
/> />
)} )}
{isAccountDetails && ( {isAccountDetails && (
<Text size='sm' className='w-full pb-1 text-white/50'> <Text
{account.id === address ? 'Red Bank' : `Credit Account ${account.id}`} size='sm'
</Text> className='w-full pb-1 text-white/50'
>{`Credit Account ${account.id}`}</Text>
)} )}
<div className='flex items-end w-full gap-2 pb-2 border-b border-white/5'> <div className='flex items-end w-full gap-2 pb-2 border-b border-white/5'>
<DisplayCurrency <DisplayCurrency
@@ -7,7 +7,7 @@ import AccountStrategiesTable from 'components/account/AccountStrategiesTable'
import AccountSummaryHeader from 'components/account/AccountSummary/AccountSummaryHeader' import AccountSummaryHeader from 'components/account/AccountSummary/AccountSummaryHeader'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import Accordion from 'components/common/Accordion' import Accordion from 'components/common/Accordion'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings' import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys' import { LocalStorageKeys } from 'constants/localStorageKeys'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
+5 -5
View File
@@ -1,19 +1,19 @@
import ActiveBorrowingsTable from 'components/borrow/Table/ActiveBorrowingsTable'
import AvailableBorrowingsTable from 'components/borrow/Table/AvailableBorrowingsTable' import AvailableBorrowingsTable from 'components/borrow/Table/AvailableBorrowingsTable'
import DepositedBorrowingsTable from 'components/borrow/Table/DepositedBorrowingsTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets' import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
export default function Borrowings() { export default function Borrowings() {
const { accountBorrowedAssets, availableAssets, allAssets } = useBorrowMarketAssetsTableData() const data = useBorrowMarketAssetsTableData()
if (!allAssets?.length) { if (!data?.allAssets?.length) {
return <Fallback /> return <Fallback />
} }
return ( return (
<> <>
<ActiveBorrowingsTable data={accountBorrowedAssets} isLoading={false} /> <DepositedBorrowingsTable data={data.accountBorrowedAssets} isLoading={false} />
<AvailableBorrowingsTable data={availableAssets} isLoading={false} /> <AvailableBorrowingsTable data={data.availableAssets} isLoading={false} />
</> </>
) )
} }
@@ -0,0 +1,36 @@
import { Row } from '@tanstack/react-table'
import AmountAndValue from 'components/common/AmountAndValue'
import { BN_ZERO } from 'constants/math'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import { byDenom } from 'utils/array'
export const DEBT_META = {
accessorKey: 'debt',
header: 'Debt',
}
export const debtSortingFn = (
a: Row<BorrowMarketTableData>,
b: Row<BorrowMarketTableData>,
): number => {
const assetA = a.original.asset
const assetB = b.original.asset
if (!a.original.accountDebt || !b.original.accountDebt) return 0
const debtA = a.original.accountDebt.shiftedBy(-assetA.decimals)
const debtB = b.original.accountDebt.shiftedBy(-assetB.decimals)
return debtA.minus(debtB).toNumber()
}
interface Props {
data: BorrowMarketTableData
}
export default function Debt(props: Props) {
const marketAssets = useMarketEnabledAssets()
const asset = marketAssets.find(byDenom(props.data.asset.denom))
if (!asset) return null
return <AmountAndValue asset={asset} amount={props.data?.accountDebt ?? BN_ZERO} />
}
@@ -1,30 +0,0 @@
import { Row } from '@tanstack/react-table'
import AmountAndValue from 'components/common/AmountAndValue'
import { BN_ZERO } from 'constants/math'
import { BN } from 'utils/helpers'
export const DEBT_VALUE_META = {
id: 'accountDebtValue',
accessorKey: 'accountDebtValue',
header: 'Debt',
}
export const debtSortingFn = (
a: Row<BorrowMarketTableData>,
b: Row<BorrowMarketTableData>,
): number => {
const debtValueA = BN(a.original?.accountDebtValue ?? 0)
const debtValueB = BN(b.original?.accountDebtValue ?? 0)
return debtValueA.minus(debtValueB).toNumber()
}
interface Props {
asset: Asset
debtAmount?: BigNumber
}
export default function DebtValue(props: Props) {
return (
<AmountAndValue asset={props.asset} amount={props.debtAmount ? props.debtAmount : BN_ZERO} />
)
}
@@ -48,7 +48,7 @@ export default function Manage(props: Props) {
if (!address) return null if (!address) return null
return ( return (
<div className='z-10 flex justify-end'> <div className='flex justify-end z-10'>
<DropDownButton items={ITEMS} text='Manage' color='tertiary' /> <DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div> </div>
) )
@@ -3,23 +3,15 @@ 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 Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
import DebtValue, { import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt'
DEBT_VALUE_META,
debtSortingFn,
} from 'components/borrow/Table/Columns/DebtValue'
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 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'
import Action from 'components/v1/Table/borrowings/Columns/Action'
interface Props { export default function useDepositedColumns() {
v1?: boolean
}
export default function useActiveColumns(props: Props) {
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => { return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
return [ return [
{ {
@@ -27,10 +19,8 @@ export default function useActiveColumns(props: Props) {
cell: ({ row }) => <Name data={row.original} />, cell: ({ row }) => <Name data={row.original} />,
}, },
{ {
...DEBT_VALUE_META, ...DEBT_META,
cell: ({ row }) => ( cell: ({ row }) => <Debt data={row.original} />,
<DebtValue asset={row.original.asset} debtAmount={row.original.accountDebtAmount} />
),
sortingFn: debtSortingFn, sortingFn: debtSortingFn,
}, },
{ {
@@ -44,13 +34,12 @@ export default function useActiveColumns(props: Props) {
}, },
{ {
...MANAGE_META, ...MANAGE_META,
cell: ({ row }) => cell: ({ row }) => <Manage data={row.original} />,
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
}, },
{ {
...CHEVRON_META, ...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, [props.v1]) }, [])
} }
@@ -1,20 +1,18 @@
import { Row } from '@tanstack/react-table' import { Row } from '@tanstack/react-table'
import { useCallback } from 'react' import { useCallback } from 'react'
import { DEBT_VALUE_META } from 'components/borrow/Table/Columns/DebtValue'
import { NAME_META } from 'components/borrow/Table/Columns/Name' import { NAME_META } from 'components/borrow/Table/Columns/Name'
import useBorrowingsColumns from 'components/borrow/Table/Columns/useActiveColumns' 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'
type Props = { type Props = {
data: BorrowMarketTableData[] data: BorrowMarketTableData[]
isLoading: boolean isLoading: boolean
v1?: boolean
} }
export default function ActiveBorrowingsTable(props: Props) { export default function DepositedBorrowingsTable(props: Props) {
const columns = useBorrowingsColumns({ v1: props.v1 }) const columns = useDepositedColumns()
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => { const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
return <MarketDetails row={row} type='borrow' /> return <MarketDetails row={row} type='borrow' />
@@ -24,17 +22,10 @@ export default function ActiveBorrowingsTable(props: Props) {
return ( return (
<Table <Table
title={props.v1 ? 'Borrowings' : 'Borrowed Assets'} title='Borrowed Assets'
columns={columns} columns={columns}
data={props.data} data={props.data}
initialSorting={ initialSorting={[{ id: NAME_META.id, desc: false }]}
props.v1
? [
{ id: DEBT_VALUE_META.id, desc: true },
{ id: NAME_META.id, desc: false },
]
: [{ id: NAME_META.id, desc: false }]
}
renderExpanded={renderExpanded} renderExpanded={renderExpanded}
/> />
) )
@@ -1,14 +1,11 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount' import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useMarkets from 'hooks/markets/useMarkets' import useMarkets from 'hooks/markets/useMarkets'
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
export default function useBorrowMarketAssetsTableData() { export default function useBorrowMarketAssetsTableData() {
const account = useCurrentAccount() const account = useCurrentAccount()
const markets = useMarkets() const markets = useMarkets()
const { convertAmount } = useDisplayCurrencyPrice()
return useMemo((): { return useMemo((): {
accountBorrowedAssets: BorrowMarketTableData[] accountBorrowedAssets: BorrowMarketTableData[]
@@ -21,21 +18,15 @@ export default function useBorrowMarketAssetsTableData() {
markets markets
.filter((market) => market.borrowEnabled) .filter((market) => market.borrowEnabled)
.forEach((market) => { .forEach((market) => {
const amount = const debt = account?.debts?.find((debt) => debt.denom === market.asset.denom)
account?.debts?.find((debt) => debt.denom === market.asset.denom)?.amount ?? BN_ZERO
const value = amount ? convertAmount(market.asset, amount) : undefined
const borrowMarketAsset: BorrowMarketTableData = { const borrowMarketAsset: BorrowMarketTableData = {
...market, ...market,
accountDebtAmount: amount, accountDebt: debt?.amount,
accountDebtValue: value,
}
if (borrowMarketAsset.accountDebtAmount?.isZero()) {
availableAssets.push(borrowMarketAsset)
} else {
accountBorrowedAssets.push(borrowMarketAsset)
} }
;(borrowMarketAsset.accountDebt ? accountBorrowedAssets : availableAssets).push(
borrowMarketAsset,
)
}) })
return { return {
@@ -43,5 +34,5 @@ export default function useBorrowMarketAssetsTableData() {
availableAssets, availableAssets,
allAssets: [...accountBorrowedAssets, ...availableAssets], allAssets: [...accountBorrowedAssets, ...availableAssets],
} }
}, [account?.debts, markets, convertAmount]) }, [account?.debts, markets])
} }
+6 -15
View File
@@ -15,28 +15,19 @@ export default function Background() {
) )
const { pathname } = useLocation() const { pathname } = useLocation()
const page = getPage(pathname) const page = getPage(pathname)
const [isHLS] = useMemo(() => [page.split('-')[0] === 'hls'], [page]) const isHLS = useMemo(() => page.split('-')[0] === 'hls', [page])
useEffect(() => { useEffect(() => {
useStore.setState({ isHLS: isHLS }) useStore.setState({ isHLS })
}, [isHLS]) }, [isHLS])
const [primaryOrbClassName, secondaryOrbClassName, tertiaryOrbClassName, bodyClassName] =
useMemo(() => {
if (isHLS) {
return ['bg-orb-primary-hls', 'bg-orb-secondary-hls', 'bg-orb-tertiary-hls', 'bg-body-hls']
}
return ['bg-orb-primary', 'bg-orb-secondary', 'bg-orb-tertiary', 'bg-body']
}, [isHLS])
return ( return (
<div <div
className={classNames( className={classNames(
'fixed inset-0', 'fixed inset-0',
'w-full h-full', 'w-full h-full',
'overflow-hidden pointer-events-none background ', 'overflow-hidden pointer-events-none background ',
bodyClassName, isHLS ? 'bg-body-hls' : 'bg-body',
!reduceMotion && 'transition-bg duration-1000 delay-300', !reduceMotion && 'transition-bg duration-1000 delay-300',
)} )}
> >
@@ -48,7 +39,7 @@ export default function Background() {
'max-h-[500px] max-w-[500px]', 'max-h-[500px] max-w-[500px]',
'left-[-10vw] top-[-10vw]', 'left-[-10vw] top-[-10vw]',
'blur-orb-primary', 'blur-orb-primary',
primaryOrbClassName, isHLS ? ' bg-orb-primary-hls' : 'bg-orb-primary',
'translate-x-0 translate-y-0 rounded-full opacity-20', 'translate-x-0 translate-y-0 rounded-full opacity-20',
!reduceMotion && 'animate-[float_120s_ease-in-out_infinite_2s]', !reduceMotion && 'animate-[float_120s_ease-in-out_infinite_2s]',
!reduceMotion && 'transition-bg duration-1000 delay-300', !reduceMotion && 'transition-bg duration-1000 delay-300',
@@ -62,7 +53,7 @@ export default function Background() {
'max-h-[1000px] max-w-[1000px]', 'max-h-[1000px] max-w-[1000px]',
'bottom-[-20vw] right-[-10vw]', 'bottom-[-20vw] right-[-10vw]',
'blur-orb-secondary', 'blur-orb-secondary',
secondaryOrbClassName, isHLS ? ' bg-orb-secondary-hls' : 'bg-orb-secondary',
'translate-x-0 translate-y-0 rounded-full opacity-30', 'translate-x-0 translate-y-0 rounded-full opacity-30',
!reduceMotion && 'transition-bg duration-1000 delay-300', !reduceMotion && 'transition-bg duration-1000 delay-300',
)} )}
@@ -75,7 +66,7 @@ export default function Background() {
'max-h-[600px] max-w-[600px]', 'max-h-[600px] max-w-[600px]',
'right-[-4vw] top-[-10vw]', 'right-[-4vw] top-[-10vw]',
'blur-orb-tertiary ', 'blur-orb-tertiary ',
tertiaryOrbClassName, isHLS ? ' bg-orb-tertiary-hls' : 'bg-orb-tertiary',
'translate-x-0 translate-y-0 rounded-full opacity-20', 'translate-x-0 translate-y-0 rounded-full opacity-20',
!reduceMotion && 'animate-[float_180s_ease-in_infinite]', !reduceMotion && 'animate-[float_180s_ease-in_infinite]',
!reduceMotion && 'transition-bg duration-1000 delay-300', !reduceMotion && 'transition-bg duration-1000 delay-300',
+1 -8
View File
@@ -9,7 +9,6 @@ import {
GridPlanet, GridPlanet,
GridTire, GridTire,
GridWeb, GridWeb,
Wallet,
} from 'components/common/Icons' } 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'
@@ -18,7 +17,7 @@ import useStore from 'store'
interface Props { interface Props {
text: string | ReactNode text: string | ReactNode
children?: ReactNode children?: ReactNode
bg: Page bg: 'borrow' | 'lend' | 'farm' | 'portfolio' | 'hls-farm' | 'hls-staking'
} }
function IntroBackground(props: { bg: Props['bg'] }) { function IntroBackground(props: { bg: Props['bg'] }) {
@@ -53,12 +52,6 @@ function IntroBackground(props: { bg: Props['bg'] }) {
<GridPlanet /> <GridPlanet />
</div> </div>
) )
case 'v1':
return (
<div className='absolute top-0 right-0 block w-80 opacity-5'>
<Wallet />
</div>
)
default: default:
return ( return (
<div className='absolute bottom-0 right-0 block w-3/4 md:w-120 opacity-5'> <div className='absolute bottom-0 right-0 block w-3/4 md:w-120 opacity-5'>
+1 -1
View File
@@ -23,7 +23,7 @@ export default function MarketDetails({ row, type }: Props) {
symbol: displayCurrencySymbol, symbol: displayCurrencySymbol,
} = useDisplayCurrencyPrice() } = useDisplayCurrencyPrice()
const { asset, ltv, deposits, debt } = row.original const { asset, ltv, cap, liquidity, deposits, debt } = row.original
const details: Detail[] = useMemo(() => { const details: Detail[] = useMemo(() => {
const isDollar = displayCurrencySymbol === '$' const isDollar = displayCurrencySymbol === '$'
+47
View File
@@ -0,0 +1,47 @@
import Card from 'components/common/Card'
import { Cross, ExclamationMarkCircled } from 'components/common/Icons'
import Text from 'components/common/Text'
import { TextLink } from 'components/common/TextLink'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useStore from 'store'
import { DocURL } from 'types/enums/docURL'
export default function MigrationBanner() {
const [_, setMigrationBanner] = useLocalStorage<boolean>(
LocalStorageKeys.MIGRATION_BANNER,
DEFAULT_SETTINGS.migrationBanner,
)
const showMigrationBanner = useStore((s) => s.migrationBanner)
if (!showMigrationBanner) return null
return (
<Card
className='relative w-full bg-info-bg/20 text-info'
contentClassName='flex w-full gap-2 px-4 py-3 items-center'
>
<div className='flex w-6 h-6 p-1 text-white rounded bg-info'>
<ExclamationMarkCircled />
</div>
<Text className='flex flex-grow' size='sm'>
If you have funds on{' '}
<TextLink
href={DocURL.V1_URL}
externalLink
className='mx-1 text-white no-underline hover:underline'
>
Mars v1,
</TextLink>
please withdraw them and deposit them on Mars v2 to migrate.
</Text>
<div
className='absolute right-0 flex items-center h-full px-4 w-11 opacity-80 hover:cursor-pointer hover:opacity-100'
onClick={() => setMigrationBanner(false)}
>
<Cross className='w-3 h-3' />
</div>
</Card>
)
}
@@ -12,12 +12,11 @@ interface Props {
className?: string className?: string
tooltip?: string tooltip?: string
disabled?: boolean disabled?: boolean
placement?: 'top' | 'bottom' | 'left' | 'right'
} }
export default function SwitchWithLabel(props: Props) { export default function SwitchWithLabel(props: Props) {
return ( return (
<div className={classNames('flex w-full items-center ', props.className)}> <div className={classNames('flex w-full', props.className)}>
<div className='flex flex-1'> <div className='flex flex-1'>
<Text className='mr-2 text-white/70' size='sm'> <Text className='mr-2 text-white/70' size='sm'>
{props.label} {props.label}
@@ -25,9 +24,8 @@ export default function SwitchWithLabel(props: Props) {
{props.tooltip && ( {props.tooltip && (
<Tooltip <Tooltip
type='info' type='info'
placement={props.placement ?? 'top'}
content={ content={
<Text size='sm' className='px-2 py-3 max-w-[320px]'> <Text size='sm' className='px-2 py-3'>
{props.tooltip} {props.tooltip}
</Text> </Text>
} }
-65
View File
@@ -1,65 +0,0 @@
import classNames from 'classnames'
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import { useMemo } from 'react'
import SwitchWithLabel from 'components/common/Switch/SwitchWithLabel'
import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig'
import useStore from 'store'
import { getRoute } from 'utils/route'
const underlineClasses =
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
interface Props {
tabs: Tab[]
activeTabIdx: number
showV1Toggle?: boolean
}
export default function Tab(props: Props) {
const accountId = useAccountId()
const { address } = useParams()
const [searchParams] = useSearchParams()
const chainConfig = useChainConfig()
const isV1 = useStore((s) => s.isV1)
const filteredTabs = useMemo(
() =>
props.tabs.map((tab) => (tab.name === 'Farm' && (!chainConfig.farm || isV1) ? null : tab)),
[chainConfig, props.tabs, isV1],
)
return (
<div className='relative flex w-full'>
<div className='flex flex-grow'>
{filteredTabs.map((tab, index) =>
tab ? (
<NavLink
key={tab.page}
to={getRoute(tab.page, searchParams, address, accountId)}
className={classNames(
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
'relative mr-8 text-xl ',
)}
>
{tab.name}
</NavLink>
) : null,
)}
</div>
{props.showV1Toggle && (
<div className='flex items-center w-40 h-full'>
<SwitchWithLabel
name='v1-toggle'
label='Wallet Mode'
value={isV1}
onChange={() => useStore.setState({ isV1: !isV1 })}
tooltip='The Wallet Mode allows you to interact with the Red Bank without the use of a Credit Account. Funds will be deposited and borrowed directly from and to your Wallet. However you will not be able to use the deposited funds for trading or farming.'
placement='bottom'
/>
</div>
)}
</div>
)
}
+2 -9
View File
@@ -11,11 +11,11 @@ import { TextLink } from 'components/common/TextLink'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings' import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys' import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage' import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useChainConfig from 'hooks/useChainConfig'
import useTransactionStore from 'hooks/useTransactionStore' import useTransactionStore from 'hooks/useTransactionStore'
import useStore from 'store' import useStore from 'store'
import { formatAmountWithSymbol } from 'utils/formatters' import { formatAmountWithSymbol } from 'utils/formatters'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import useChainConfig from 'hooks/useChainConfig'
const toastBodyClasses = classNames( const toastBodyClasses = classNames(
'flex flex-wrap w-full group/transaction', 'flex flex-wrap w-full group/transaction',
@@ -99,13 +99,6 @@ export default function Toaster() {
if (!isError && toast.accountId) addTransaction(toast) if (!isError && toast.accountId) addTransaction(toast)
const generalMessage = isError ? 'Transaction failed!' : 'Transaction completed successfully!' const generalMessage = isError ? 'Transaction failed!' : 'Transaction completed successfully!'
const showDetailElement = !!(!details && toast.hash) const showDetailElement = !!(!details && toast.hash)
const address = useStore.getState().address
let target: string
if (!isError) {
target = toast.accountId === address ? 'Red Bank' : `Credit Account ${toast.accountId}`
}
const Msg = () => ( const Msg = () => (
<div className='relative flex flex-wrap w-full m-0 isolate'> <div className='relative flex flex-wrap w-full m-0 isolate'>
<div className='flex w-full gap-2 mb-2'> <div className='flex w-full gap-2 mb-2'>
@@ -148,7 +141,7 @@ export default function Toaster() {
)} )}
> >
{!isError && toast.accountId && ( {!isError && toast.accountId && (
<Text className='mb-1 font-bold text-white'>{target}</Text> <Text className='mb-1 font-bold text-white'>{`Credit Account ${toast.accountId}`}</Text>
)} )}
{showDetailElement && toast.message && ( {showDetailElement && toast.message && (
<Text size='sm' className='w-full mb-1 text-white'> <Text size='sm' className='w-full mb-1 text-white'>
+1 -1
View File
@@ -38,7 +38,7 @@ export const Tooltip = (props: Props) => {
placement={props.placement ?? 'top'} placement={props.placement ?? 'top'}
render={() => ( render={() => (
<TooltipContent <TooltipContent
hideArrow={props.placement === 'bottom' ? true : props.hideArrow} hideArrow={props.hideArrow}
type={props.type} type={props.type}
content={props.content} content={props.content}
className={props.contentClassName} className={props.contentClassName}
+36
View File
@@ -0,0 +1,36 @@
import classNames from 'classnames'
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import useAccountId from 'hooks/useAccountId'
import { getRoute } from 'utils/route'
const underlineClasses =
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
interface Props {
tabs: Tab[]
activeTabIdx: number
}
export default function Tab(props: Props) {
const accountId = useAccountId()
const { address } = useParams()
const [searchParams] = useSearchParams()
return (
<div className='relative w-full'>
{props.tabs.map((tab, index) => (
<NavLink
key={tab.page}
to={getRoute(tab.page, searchParams, address, accountId)}
className={classNames(
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
'relative mr-8 text-xl ',
)}
>
{tab.name}
</NavLink>
))}
</div>
)
}
@@ -1,5 +1,7 @@
import React from 'react'
import useAvailableColumns from 'components/earn/farm/Table/Columns/useAvailableColumns'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import useAvailableColumns from 'components/farm/Table/Columns/useAvailableColumns'
type Props = { type Props = {
data: Vault[] data: Vault[]
@@ -1,16 +1,17 @@
import moment from 'moment/moment' import moment from 'moment/moment'
import { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import DropDownButton from 'components/common/Button/DropDownButton'
import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons' import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId'
import useStore from 'store'
import { VaultStatus } from 'types/enums/vault' import { 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: '' } export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' }
interface Props { interface Props {
@@ -103,7 +104,7 @@ export default function Manage(props: Props) {
if (!address) return null if (!address) return null
return ( return (
<div className='z-10 flex justify-end'> <div className='flex justify-end z-10'>
<DropDownButton <DropDownButton
items={ITEMS} items={ITEMS}
text='Manage' text='Manage'
@@ -1,15 +1,16 @@
import { ColumnDef } from '@tanstack/react-table' import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
import { Deposit, DEPOSIT_META } from 'components/farm/Table/Columns/Deposit'
import DepositCap, { import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
depositCapSortingFn, depositCapSortingFn,
} from 'components/farm/Table/Columns/DepositCap' } from 'components/earn/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL' import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
import { Deposit, DEPOSIT_META } from './Deposit'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
@@ -1,16 +1,18 @@
import { ColumnDef, Row } from '@tanstack/react-table' import { ColumnDef, Row } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
import DepositCap, { import DepositCap, {
DEPOSIT_CAP_META, DEPOSIT_CAP_META,
depositCapSortingFn, depositCapSortingFn,
} from 'components/farm/Table/Columns/DepositCap' } from 'components/earn/farm/Table/Columns/DepositCap'
import Manage, { MANAGE_META } from 'components/farm/Table/Columns/Manage' import Manage, { MANAGE_META } from 'components/earn/farm/Table/Columns/Manage'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import PositionValue, { POSITION_VALUE_META } from 'components/farm/Table/Columns/PositionValue' import PositionValue, {
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL' POSITION_VALUE_META,
} from 'components/earn/farm/Table/Columns/PositionValue'
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
@@ -1,5 +1,7 @@
import React from 'react'
import Table from 'components/common/Table' import Table from 'components/common/Table'
import useDepositedColumns from 'components/farm/Table/Columns/useDepositedColumns' import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
type Props = { type Props = {
data: DepositedVault[] data: DepositedVault[]
@@ -1,8 +1,8 @@
import { Suspense, useMemo } from 'react' import { Suspense, useMemo } from 'react'
import AvailableVaultsTable from 'components/farm/Table/AvailableVaultsTable' import AvailableVaultsTable from 'components/earn/farm/Table/AvailableVaultsTable'
import DepositedVaultsTable from 'components/farm/Table/DepositedVaultsTable' import DepositedVaultsTable from 'components/earn/farm/Table/DepositedVaultsTable'
import VaultUnlockBanner from 'components/farm/VaultUnlockBanner' import VaultUnlockBanner from 'components/earn/farm/VaultUnlockBanner'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useAccountId from 'hooks/useAccountId' import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
@@ -1,6 +1,6 @@
import AvailableLendsTable from 'components/lend/Table/AvailableLendsTable' import AvailableLendsTable from 'components/earn/lend/Table/AvailableLendsTable'
import DepositedLendsTable from 'components/lend/Table/DepositedLendsTable' import DepositedLendsTable from 'components/earn/lend/Table/DepositedLendsTable'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets' import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
@@ -3,8 +3,8 @@ import { useCallback } from 'react'
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 { NAME_META } from 'components/lend/Table/Columns/Name' import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import useAvailableColumns from 'components/lend/Table/Columns/useAvailableColumns' import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
type Props = { type Props = {
data: LendingMarketTableData[] data: LendingMarketTableData[]
@@ -5,7 +5,6 @@ import { BN_ZERO } from 'constants/math'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
export const DEPOSIT_VALUE_META = { export const DEPOSIT_VALUE_META = {
id: 'accountLentValue',
accessorKey: 'accountLentValue', accessorKey: 'accountLentValue',
header: 'Deposited', header: 'Deposited',
} }
@@ -1,14 +1,14 @@
import { ColumnDef } from '@tanstack/react-table' import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron' 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/lend/Table/Columns/DepositCap' } from 'components/earn/lend/Table/Columns/DepositCap'
import LendButton, { LEND_BUTTON_META } from 'components/lend/Table/Columns/LendButton' import LendButton, { LEND_BUTTON_META } from 'components/earn/lend/Table/Columns/LendButton'
import Name, { NAME_META } from 'components/lend/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
@@ -1,23 +1,21 @@
import { ColumnDef } from '@tanstack/react-table' import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import { useMemo } from 'react'
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron' 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/lend/Table/Columns/DepositCap' } from 'components/earn/lend/Table/Columns/DepositCap'
import DepositValue, { import DepositValue, {
DEPOSIT_VALUE_META, DEPOSIT_VALUE_META,
depositedSortingFn, depositedSortingFn,
} from 'components/lend/Table/Columns/DepositValue' } from 'components/earn/lend/Table/Columns/DepositValue'
import Manage, { MANAGE_META } from 'components/lend/Table/Columns/Manage' import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage'
import Name, { NAME_META } from 'components/lend/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import Action from 'components/v1/Table/deposits/Columns/Action'
interface Props { interface Props {
isLoading: boolean isLoading: boolean
v1?: boolean
} }
export default function useDepositedColumns(props: Props) { export default function useDepositedColumns(props: Props) {
@@ -51,13 +49,12 @@ export default function useDepositedColumns(props: Props) {
}, },
{ {
...MANAGE_META, ...MANAGE_META,
cell: ({ row }) => cell: ({ row }) => <Manage data={row.original} />,
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
}, },
{ {
...CHEVRON_META, ...CHEVRON_META,
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />, cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
}, },
] ]
}, [props.isLoading, props.v1]) }, [props.isLoading])
} }
@@ -3,18 +3,16 @@ import { useCallback } from 'react'
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 { DEPOSIT_VALUE_META } from 'components/lend/Table/Columns/DepositValue' import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
import { NAME_META } from 'components/lend/Table/Columns/Name' import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
import useDepositedColumns from 'components/lend/Table/Columns/useDepositedColumns'
type Props = { type Props = {
data: LendingMarketTableData[] data: LendingMarketTableData[]
isLoading: boolean isLoading: boolean
v1?: boolean
} }
export default function DepositedLendsTable(props: Props) { export default function DepositedLendsTable(props: Props) {
const columns = useDepositedColumns({ isLoading: props.isLoading, v1: props.v1 }) const columns = useDepositedColumns({ isLoading: props.isLoading })
const renderExpanded = useCallback( const renderExpanded = useCallback(
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />, (row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
@@ -25,17 +23,10 @@ export default function DepositedLendsTable(props: Props) {
return ( return (
<Table <Table
title={props.v1 ? 'Deposits' : 'Lent Assets'} title='Lent Assets'
columns={columns} columns={columns}
data={props.data} data={props.data}
initialSorting={ initialSorting={[{ id: NAME_META.id, desc: false }]}
props.v1
? [
{ id: DEPOSIT_VALUE_META.id, desc: true },
{ id: NAME_META.id, desc: false },
]
: [{ id: NAME_META.id, desc: false }]
}
renderExpanded={renderExpanded} renderExpanded={renderExpanded}
/> />
) )
+3 -3
View File
@@ -36,7 +36,8 @@ export const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTree
], ],
}, },
...(chainConfig.perps ? [{ pages: ['perps'] as Page[], label: 'Perps' }] : []), ...(chainConfig.perps ? [{ pages: ['perps'] as Page[], label: 'Perps' }] : []),
{ pages: chainConfig.farm ? ['lend', 'farm', 'borrow'] : ['lend'], label: 'Lend & Borrow' }, { pages: chainConfig.farm ? ['lend', 'farm'] : ['lend'], label: 'Earn' },
{ pages: ['borrow'], label: 'Borrow' },
...(chainConfig.hls ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []), ...(chainConfig.hls ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []),
{ pages: ['portfolio'], label: 'Portfolio' }, { pages: ['portfolio'], label: 'Portfolio' },
{ pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) }, { pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) },
@@ -48,7 +49,6 @@ export default function DesktopHeader() {
const isOracleStale = useStore((s) => s.isOracleStale) const isOracleStale = useStore((s) => s.isOracleStale)
const isHLS = useStore((s) => s.isHLS) const isHLS = useStore((s) => s.isHLS)
const accountId = useAccountId() const accountId = useAccountId()
const showAccountMenu = address && !isHLS
function handleCloseFocusMode() { function handleCloseFocusMode() {
if (focusComponent && focusComponent.onClose) focusComponent.onClose() if (focusComponent && focusComponent.onClose) focusComponent.onClose()
@@ -92,7 +92,7 @@ export default function DesktopHeader() {
<div className='flex gap-4'> <div className='flex gap-4'>
{showStaleOracle && <OracleResyncButton />} {showStaleOracle && <OracleResyncButton />}
{accountId && <RewardsCenter />} {accountId && <RewardsCenter />}
{showAccountMenu && <AccountMenu />} {address && !isHLS && <AccountMenu />}
<Wallet /> <Wallet />
<ChainSelect /> <ChainSelect />
<Settings /> <Settings />
+2 -4
View File
@@ -13,11 +13,9 @@ import PortfolioAccountPage from 'pages/PortfolioAccountPage'
import PortfolioPage from 'pages/PortfolioPage' import PortfolioPage from 'pages/PortfolioPage'
import TradePage from 'pages/TradePage' import TradePage from 'pages/TradePage'
import Layout from 'pages/_layout' import Layout from 'pages/_layout'
import useStore from 'store'
export default function Routes() { export default function Routes() {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const isV1 = useStore((s) => s.isV1)
return ( return (
<RoutesWrapper> <RoutesWrapper>
<Route <Route
@@ -30,7 +28,7 @@ export default function Routes() {
<Route path='/trade' element={<TradePage />} /> <Route path='/trade' element={<TradePage />} />
<Route path='/trade-advanced' element={<TradePage />} /> <Route path='/trade-advanced' element={<TradePage />} />
{chainConfig.perps && <Route path='/perps' element={<PerpsPage />} />} {chainConfig.perps && <Route path='/perps' element={<PerpsPage />} />}
{chainConfig.farm && !isV1 && <Route path='/farm' element={<FarmPage />} />} {chainConfig.farm && <Route path='/farm' element={<FarmPage />} />}
<Route path='/lend' element={<LendPage />} /> <Route path='/lend' element={<LendPage />} />
<Route path='/borrow' element={<BorrowPage />} /> <Route path='/borrow' element={<BorrowPage />} />
<Route path='/portfolio' element={<PortfolioPage />} /> <Route path='/portfolio' element={<PortfolioPage />} />
@@ -43,7 +41,7 @@ export default function Routes() {
<Route path='trade' element={<TradePage />} /> <Route path='trade' element={<TradePage />} />
<Route path='trade-advanced' element={<TradePage />} /> <Route path='trade-advanced' element={<TradePage />} />
{chainConfig.perps && <Route path='perps' element={<PerpsPage />} />} {chainConfig.perps && <Route path='perps' element={<PerpsPage />} />}
{chainConfig.farm && !isV1 && <Route path='farm' element={<FarmPage />} />} {chainConfig.farm && <Route path='farm' element={<FarmPage />} />}
<Route path='lend' element={<LendPage />} /> <Route path='lend' element={<LendPage />} />
<Route path='borrow' element={<BorrowPage />} /> <Route path='borrow' element={<BorrowPage />} />
<Route path='portfolio' element={<PortfolioPage />} /> <Route path='portfolio' element={<PortfolioPage />} />
@@ -1,10 +1,10 @@
import { ColumnDef } from '@tanstack/react-table' import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react' import React, { useMemo } from 'react'
import DepositCap, { DEPOSIT_CAP_META } from 'components/farm/Table/Columns/DepositCap' import DepositCap, { DEPOSIT_CAP_META } from 'components/earn/farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/farm/Table/Columns/Name' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL' import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
import Apy, { APY_META } from 'components/hls/Farm/Table/Columns/APY' import Apy, { APY_META } from 'components/hls/Farm/Table/Columns/APY'
import Deposit, { DEPOSIT_META } from 'components/hls/Farm/Table/Columns/Deposit' import Deposit, { DEPOSIT_META } from 'components/hls/Farm/Table/Columns/Deposit'
import MaxLeverage, { MAX_LEV_META } from 'components/hls/Farm/Table/Columns/MaxLeverage' import MaxLeverage, { MAX_LEV_META } from 'components/hls/Farm/Table/Columns/MaxLeverage'
@@ -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}
+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),
)}
/>
)
} }
@@ -5,7 +5,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
import Card from 'components/common/Card' import Card from 'components/common/Card'
import TableSkeleton from 'components/common/Table/TableSkeleton' import TableSkeleton from 'components/common/Table/TableSkeleton'
import Text from 'components/common/Text' import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount' import useAccount from 'hooks/accounts/useAccount'
interface Props { interface Props {
+8 -21
View File
@@ -3,7 +3,7 @@ import { Suspense, useMemo } from 'react'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency' import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/SummarySkeleton' import Skeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math' import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount' import useAccount from 'hooks/accounts/useAccount'
@@ -17,7 +17,6 @@ import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'
interface Props { interface Props {
accountId: string accountId: string
v1?: boolean
} }
function Content(props: Props) { function Content(props: Props) {
@@ -46,25 +45,15 @@ function Content(props: Props) {
return [ return [
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={positionValue} />,
<DisplayCurrency
className='text-xl'
coin={positionValue}
options={{ abbreviated: false }}
/>
),
sub: DEFAULT_PORTFOLIO_STATS[0].sub, sub: DEFAULT_PORTFOLIO_STATS[0].sub,
}, },
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={debts} />,
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
),
sub: DEFAULT_PORTFOLIO_STATS[1].sub, sub: DEFAULT_PORTFOLIO_STATS[1].sub,
}, },
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={netWorth} />,
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
),
sub: DEFAULT_PORTFOLIO_STATS[2].sub, sub: DEFAULT_PORTFOLIO_STATS[2].sub,
}, },
{ {
@@ -85,23 +74,21 @@ function Content(props: Props) {
title: ( title: (
<FormattedNumber <FormattedNumber
className='text-xl' className='text-xl'
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()} amount={leverage.toNumber()}
options={{ suffix: 'x' }} options={{ suffix: 'x' }}
/> />
), ),
sub: props.v1 ? 'Total Leverage' : DEFAULT_PORTFOLIO_STATS[4].sub, sub: DEFAULT_PORTFOLIO_STATS[4].sub,
}, },
] ]
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, props.v1]) }, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
if (props.v1 && account?.lends.length == 0) return null
return ( return (
<Skeleton <Skeleton
stats={stats} stats={stats}
health={health} health={health}
healthFactor={healthFactor} healthFactor={healthFactor}
title={props.v1 ? 'Wallet Mode Portfolio' : `Credit Account ${props.accountId}`} title={`Credit Account ${props.accountId}`}
accountId={props.accountId} accountId={props.accountId}
/> />
) )
+1 -1
View File
@@ -5,7 +5,7 @@ import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/Card/Skeleton' import Skeleton from 'components/portfolio/Card/Skeleton'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings' import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys' import { LocalStorageKeys } from 'constants/localStorageKeys'
+6 -20
View File
@@ -4,10 +4,9 @@ import { useParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency' import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import SummarySkeleton from 'components/portfolio/SummarySkeleton' import SummarySkeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math' import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
import useAccounts from 'hooks/accounts/useAccounts' import useAccounts from 'hooks/accounts/useAccounts'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
@@ -28,11 +27,8 @@ export default function PortfolioSummary() {
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs() const { data: vaultAprs } = useVaultAprs()
const assets = useAllAssets() const assets = useAllAssets()
const { data: v1Account } = useAccount(urlAddress)
const stats = useMemo(() => { const stats = useMemo(() => {
if (!accounts?.length) return if (!accounts?.length) return
if (v1Account && !accounts.find((account) => account.id === urlAddress))
accounts.push(v1Account)
const combinedAccount = accounts.reduce( const combinedAccount = accounts.reduce(
(combinedAccount, account) => { (combinedAccount, account) => {
combinedAccount.debts = combinedAccount.debts.concat(account.debts) combinedAccount.debts = combinedAccount.debts.concat(account.debts)
@@ -64,25 +60,15 @@ export default function PortfolioSummary() {
return [ return [
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={positionValue} />,
<DisplayCurrency
className='text-xl'
coin={positionValue}
options={{ abbreviated: false }}
/>
),
sub: DEFAULT_PORTFOLIO_STATS[0].sub, sub: DEFAULT_PORTFOLIO_STATS[0].sub,
}, },
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={debts} />,
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
),
sub: DEFAULT_PORTFOLIO_STATS[1].sub, sub: DEFAULT_PORTFOLIO_STATS[1].sub,
}, },
{ {
title: ( title: <DisplayCurrency className='text-xl' coin={netWorth} />,
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
),
sub: DEFAULT_PORTFOLIO_STATS[2].sub, sub: DEFAULT_PORTFOLIO_STATS[2].sub,
}, },
{ {
@@ -103,14 +89,14 @@ export default function PortfolioSummary() {
title: ( title: (
<FormattedNumber <FormattedNumber
className='text-xl' className='text-xl'
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()} amount={leverage.toNumber()}
options={{ suffix: 'x' }} options={{ suffix: 'x' }}
/> />
), ),
sub: 'Combined leverage', sub: 'Combined leverage',
}, },
] ]
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, v1Account]) }, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
if (!walletAddress && !urlAddress) return null if (!walletAddress && !urlAddress) return null
+1 -1
View File
@@ -2,7 +2,7 @@ import { useMemo } from 'react'
import AccountBalancesTable from 'components/account/AccountBalancesTable' import AccountBalancesTable from 'components/account/AccountBalancesTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData' import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData' import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount' import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
export default function AccountDetailsCard() { export default function AccountDetailsCard() {
-47
View File
@@ -1,47 +0,0 @@
import BorrowingsTable from 'components/borrow/Table/ActiveBorrowingsTable'
import useV1BorrowingsTableData from 'components/v1/Table/useV1BorrowingsTableData'
import { BN_ZERO } from 'constants/math'
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
export default function Borrowings() {
const { debtAssets } = useV1BorrowingsTableData()
if (!debtAssets?.length) {
return <Fallback />
}
return (
<>
<BorrowingsTable data={debtAssets} isLoading={false} v1 />
</>
)
}
function Fallback() {
const assets = useBorrowEnabledAssets()
const data: BorrowMarketTableData[] = assets.map((asset) => ({
asset,
apy: {
borrow: 0,
deposit: 0,
},
ltv: {
max: 0,
liq: 0,
},
liquidity: BN_ZERO,
marketLiquidityRate: 0,
cap: {
denom: asset.denom,
max: BN_ZERO,
used: BN_ZERO,
},
debt: BN_ZERO,
borrowEnabled: true,
depositEnabled: true,
deposits: BN_ZERO,
accountDebt: BN_ZERO,
}))
return <BorrowingsTable data={data} isLoading v1 />
}
-46
View File
@@ -1,46 +0,0 @@
import DepositsTable from 'components/lend/Table/DepositedLendsTable'
import useV1DepositsTableData from 'components/v1/Table/useV1DepositsTableData'
import { BN_ZERO } from 'constants/math'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
export default function Deposits() {
const { depositAssets } = useV1DepositsTableData()
if (!depositAssets?.length) {
return <Fallback />
}
return (
<>
<DepositsTable data={depositAssets} isLoading={false} v1 />
</>
)
}
function Fallback() {
const assets = useMarketEnabledAssets()
const data: LendingMarketTableData[] = assets.map((asset) => ({
asset,
borrowEnabled: true,
depositEnabled: true,
debt: BN_ZERO,
deposits: BN_ZERO,
liquidity: BN_ZERO,
cap: {
max: BN_ZERO,
used: BN_ZERO,
denom: asset.denom,
},
apy: {
borrow: 0,
deposit: 0,
},
ltv: {
max: 0,
liq: 0,
},
}))
return <DepositsTable data={data} isLoading v1 />
}
@@ -1,20 +0,0 @@
import BorrowButton from 'components/v1/Table/borrowings/Columns/BorrowButton'
import Manage from 'components/v1/Table/borrowings/Columns/Manage'
export const MANAGE_META = {
accessorKey: 'manage',
enableSorting: false,
header: '',
}
interface Props {
data: BorrowMarketTableData
}
export default function Action(props: Props) {
const hasDebt = !props.data.accountDebtAmount?.isZero() ?? false
if (hasDebt) return <Manage data={props.data} />
return <BorrowButton data={props.data} />
}
@@ -1,50 +0,0 @@
import ActionButton from 'components/common/Button/ActionButton'
import { Plus } from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useAccount from 'hooks/accounts/useAccount'
import useStore from 'store'
interface Props {
data: BorrowMarketTableData
}
export default function BorrowButton(props: Props) {
const address = useStore((s) => s.address)
const { data: account } = useAccount(address)
const hasCollateral = account?.lends?.length ?? 0 > 0
return (
<div className='flex justify-end'>
<ConditionalWrapper
condition={!hasCollateral}
wrapper={(children) => (
<Tooltip
type='warning'
content={
<Text size='sm'>{`You dont have assets deposited in the Red Bank. Please deposit assets before you borrow.`}</Text>
}
contentClassName='max-w-[200px]'
className='ml-auto'
>
{children}
</Tooltip>
)}
>
<ActionButton
leftIcon={<Plus />}
disabled={!hasCollateral}
color='tertiary'
onClick={(e) => {
useStore.setState({
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
})
e.stopPropagation()
}}
text='Borrow'
/>
</ConditionalWrapper>
</div>
)
}
@@ -1,47 +0,0 @@
import { useMemo } from 'react'
import DropDownButton from 'components/common/Button/DropDownButton'
import { HandCoins, Plus } from 'components/common/Icons'
import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store'
import { byDenom } from 'utils/array'
interface Props {
data: BorrowMarketTableData
}
export default function Manage(props: Props) {
const address = useStore((s) => s.address)
const { data: balances } = useWalletBalances(address)
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
const ITEMS: DropDownItem[] = useMemo(
() => [
{
icon: <Plus />,
text: 'Borrow more',
onClick: () =>
useStore.setState({
v1BorrowAndRepayModal: { type: 'borrow', data: props.data },
}),
},
{
icon: <HandCoins />,
text: 'Repay',
onClick: () =>
useStore.setState({
v1BorrowAndRepayModal: { type: 'repay', data: props.data },
}),
disabled: !hasBalance,
disabledTooltip: `You dont have any ${props.data.asset.symbol} in your Wallet.`,
},
],
[hasBalance, props.data],
)
return (
<div className='z-10 flex justify-end'>
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div>
)
}
@@ -1,19 +0,0 @@
import DepositButton from 'components/v1/Table/deposits/Columns/DepositButton'
import Manage from 'components/v1/Table/deposits/Columns/Manage'
export const MANAGE_META = {
accessorKey: 'manage',
enableSorting: false,
header: '',
}
interface Props {
data: LendingMarketTableData
}
export default function Action(props: Props) {
const hasDeposits = !props.data.accountLentAmount?.isZero() ?? false
if (hasDeposits) return <Manage data={props.data} />
return <DepositButton data={props.data} />
}
@@ -1,50 +0,0 @@
import ActionButton from 'components/common/Button/ActionButton'
import { ArrowUpLine } from 'components/common/Icons'
import Text from 'components/common/Text'
import { Tooltip } from 'components/common/Tooltip'
import ConditionalWrapper from 'hocs/ConditionalWrapper'
import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store'
import { byDenom } from 'utils/array'
interface Props {
data: LendingMarketTableData
}
export default function DepositButton(props: Props) {
const address = useStore((s) => s.address)
const { data: balances } = useWalletBalances(address)
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
return (
<div className='flex justify-end'>
<ConditionalWrapper
condition={!hasBalance}
wrapper={(children) => (
<Tooltip
type='warning'
content={
<Text size='sm'>{`You dont have any ${props.data.asset.symbol} in your Wallet.`}</Text>
}
contentClassName='max-w-[200px]'
className='ml-auto'
>
{children}
</Tooltip>
)}
>
<ActionButton
leftIcon={<ArrowUpLine />}
disabled={!hasBalance}
color='tertiary'
onClick={(e) => {
useStore.setState({
v1DepositAndWithdrawModal: { type: 'deposit', data: props.data },
})
e.stopPropagation()
}}
text='Deposit'
/>
</ConditionalWrapper>
</div>
)
}
@@ -1,48 +0,0 @@
import { useMemo } from 'react'
import DropDownButton from 'components/common/Button/DropDownButton'
import { ArrowDownLine, ArrowUpLine } from 'components/common/Icons'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store'
import { byDenom } from 'utils/array'
interface Props {
data: LendingMarketTableData
}
export default function Manage(props: Props) {
const address = useStore((s) => s.address)
const { data: balances } = useWalletBalances(address)
const hasBalance = !!balances.find(byDenom(props.data.asset.denom))
const ITEMS: DropDownItem[] = useMemo(
() => [
{
icon: <ArrowUpLine />,
text: 'Deposit more',
onClick: () =>
useStore.setState({
v1DepositAndWithdrawModal: { type: 'deposit', data: props.data },
}),
disabled: !hasBalance,
disabledTooltip: `You dont have any ${props.data.asset.symbol} in your Wallet.`,
},
{
icon: <ArrowDownLine />,
text: 'Withdraw',
onClick: () =>
useStore.setState({
v1DepositAndWithdrawModal: { type: 'withdraw', data: props.data },
}),
},
],
[hasBalance, props.data],
)
return (
<div className='z-10 flex justify-end'>
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
</div>
)
}
@@ -1,38 +0,0 @@
import { useMemo } from 'react'
import { BN_ZERO } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
import useMarkets from 'hooks/markets/useMarkets'
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
import useStore from 'store'
export default function useV1BorrowingsTableData() {
const address = useStore((s) => s.address)
const markets = useMarkets()
const { data: v1Positions } = useAccount(address)
const { convertAmount } = useDisplayCurrencyPrice()
return useMemo((): {
debtAssets: BorrowMarketTableData[]
} => {
const userDebts = v1Positions?.debts ?? []
const debtAssets: BorrowMarketTableData[] = []
markets
.filter((market) => market.borrowEnabled)
.forEach((market) => {
const amount =
userDebts.find((debt) => debt.denom === market.asset.denom)?.amount ?? BN_ZERO
const value = amount ? convertAmount(market.asset, amount) : undefined
const borrowMarketAsset: BorrowMarketTableData = {
...market,
accountDebtAmount: amount,
accountDebtValue: value,
}
debtAssets.push(borrowMarketAsset)
})
return { debtAssets }
}, [v1Positions, markets, convertAmount])
}
@@ -1,39 +0,0 @@
import { useMemo } from 'react'
import { BN_ZERO } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
import useMarkets from 'hooks/markets/useMarkets'
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
import useStore from 'store'
import { byDenom } from 'utils/array'
export default function useV1DepositsTableData(): {
depositAssets: LendingMarketTableData[]
} {
const address = useStore((s) => s.address)
const markets = useMarkets()
const { data: v1Positions } = useAccount(address)
const { convertAmount } = useDisplayCurrencyPrice()
return useMemo(() => {
const depositAssets: LendingMarketTableData[] = []
const userCollateral = v1Positions?.lends ?? []
markets.forEach((market) => {
const amount = userCollateral.find(byDenom(market.asset.denom))?.amount ?? BN_ZERO
const value = amount ? convertAmount(market.asset, amount) : undefined
const lendingMarketAsset: LendingMarketTableData = {
...market,
accountLentValue: value,
accountLentAmount: amount,
}
depositAssets.push(lendingMarketAsset)
})
return {
depositAssets,
}
}, [markets, v1Positions, convertAmount])
}
-21
View File
@@ -1,21 +0,0 @@
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
import Intro from 'components/common/Intro'
import useStore from 'store'
export default function V1Intro() {
const address = useStore((state) => state.address)
return (
<Intro
text={
<>
The <span className='text-white'>Wallet Mode</span> provides simple lending and borrowing
without the use of Credit Accounts. Deposits{' '}
<span className='text-white'>can&lsquo;t be used</span> in the Trade or Farm interface.
</>
}
bg='v1'
>
{!address && <WalletConnectButton className='mt-4' />}
</Intro>
)
}
+1 -2
View File
@@ -1,6 +1,5 @@
export const LEND_AND_BORROW_TABS: Tab[] = [ export const EARN_TABS: Tab[] = [
{ page: 'lend', name: 'Lend' }, { page: 'lend', name: 'Lend' },
{ page: 'borrow', name: 'Borrow' },
{ page: 'farm', name: 'Farm' }, { page: 'farm', name: 'Farm' },
] ]
+2 -10
View File
@@ -1,22 +1,14 @@
import useSWR from 'swr' import useSWR from 'swr'
import getAccount from 'api/accounts/getAccount' import getAccount from 'api/accounts/getAccount'
import getV1Positions from 'api/v1/getV1Positions'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useStore from 'store'
export default function useAccount(accountId?: string, suspense?: boolean) { export default function useAccount(accountId?: string, suspense?: boolean) {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const address = useStore((s) => s.address)
const isV1 = accountId === address
const cacheKey = isV1
? `chains/${chainConfig.id}/v1/user/${accountId}`
: `chains/${chainConfig.id}/accounts/${accountId}`
return useSWR( return useSWR(
accountId && cacheKey, accountId && `chains/${chainConfig.id}/accounts/${accountId}`,
() => (isV1 ? getV1Positions(chainConfig, accountId) : getAccount(chainConfig, accountId)), () => getAccount(chainConfig, accountId),
{ {
suspense: suspense, suspense: suspense,
revalidateOnFocus: false, revalidateOnFocus: false,
+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),
}), }),
) )
}, },
+1 -2
View File
@@ -11,7 +11,6 @@ import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.cl
import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client' import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client'
import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client' import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client'
import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client' import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
import { getUrl } from 'utils/url'
export default function useClients() { export default function useClients() {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
@@ -19,7 +18,7 @@ export default function useClients() {
const swr = useSWR( const swr = useSWR(
`chains/${chainConfig.id}/clients`, `chains/${chainConfig.id}/clients`,
async () => { async () => {
const client = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc)) const client = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
return { return {
creditManager: new MarsCreditManagerQueryClient( creditManager: new MarsCreditManagerQueryClient(
+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
}, },
+5 -11
View File
@@ -1,19 +1,13 @@
import BorrowIntro from 'components/borrow/BorrowIntro'
import Borrowings from 'components/borrow/Borrowings' import Borrowings from 'components/borrow/Borrowings'
import Tab from 'components/common/Tab' import BorrowIntro from 'components/borrow/BorrowIntro'
import V1Borrowings from 'components/v1/Borrowings' import MigrationBanner from 'components/common/MigrationBanner'
import V1Intro from 'components/v1/V1Intro'
import { LEND_AND_BORROW_TABS } from 'constants/pages'
import useStore from 'store'
export default function BorrowPage() { export default function BorrowPage() {
const isV1 = useStore((s) => s.isV1)
return ( return (
<div className='flex flex-wrap w-full gap-6'> <div className='flex flex-wrap w-full gap-6'>
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={1} showV1Toggle /> <MigrationBanner />
{isV1 ? <V1Intro /> : <BorrowIntro />} <BorrowIntro />
{isV1 ? <V1Borrowings /> : <Borrowings />} <Borrowings />
</div> </div>
) )
} }
+7 -5
View File
@@ -1,12 +1,14 @@
import Tab from 'components/common/Tab' import FarmIntro from 'components/earn/farm/FarmIntro'
import FarmIntro from 'components/farm/FarmIntro' import Vaults from 'components/earn/farm/Vaults'
import Vaults from 'components/farm/Vaults' import Tab from 'components/earn/Tab'
import { LEND_AND_BORROW_TABS } from 'constants/pages' import MigrationBanner from 'components/common/MigrationBanner'
import { EARN_TABS } from 'constants/pages'
export default function FarmPage() { export default function FarmPage() {
return ( return (
<div className='flex flex-wrap w-full gap-6'> <div className='flex flex-wrap w-full gap-6'>
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={2} showV1Toggle /> <MigrationBanner />
<Tab tabs={EARN_TABS} activeTabIdx={1} />
<FarmIntro /> <FarmIntro />
<Vaults /> <Vaults />
</div> </div>
+3 -1
View File
@@ -1,11 +1,13 @@
import Tab from 'components/common/Tab' import Tab from 'components/earn/Tab'
import AvailableHLSVaults from 'components/hls/Farm/AvailableHLSVaults' import AvailableHLSVaults from 'components/hls/Farm/AvailableHLSVaults'
import HlsFarmIntro from 'components/hls/Farm/HLSFarmIntro' import HlsFarmIntro from 'components/hls/Farm/HLSFarmIntro'
import MigrationBanner from 'components/common/MigrationBanner'
import { HLS_TABS } from 'constants/pages' import { HLS_TABS } from 'constants/pages'
export default function HLSFarmPage() { export default function HLSFarmPage() {
return ( return (
<div className='flex flex-wrap w-full gap-6'> <div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<Tab tabs={HLS_TABS} activeTabIdx={1} /> <Tab tabs={HLS_TABS} activeTabIdx={1} />
<HlsFarmIntro /> <HlsFarmIntro />
<AvailableHLSVaults /> <AvailableHLSVaults />

Some files were not shown because too many files have changed in this diff Show More