Compare commits
23 Commits
main
...
wallet-mod
Author | SHA1 | Date | |
---|---|---|---|
|
2c7c0e99e0 | ||
|
1c3e4de4dd | ||
|
65ff38f117 | ||
|
1a45d64bac | ||
|
89d41fa5cf | ||
|
df7ef30a43 | ||
|
21bedd7905 | ||
|
37be3240eb | ||
|
f609540809 | ||
|
106de661a8 | ||
|
40593ae987 | ||
|
e3b5e330ee | ||
|
7eac8e7a35 | ||
|
af478c56d5 | ||
|
a6f4c24f15 | ||
|
6946ceddfc | ||
|
0154065ffb | ||
|
4f64234a75 | ||
|
26f1ef4a2c | ||
|
34db8aea1a | ||
|
75edb21c02 | ||
|
442b7a3a8c | ||
|
3f28ccd09c |
@ -10,7 +10,12 @@ import {
|
|||||||
TotalDepositResponse,
|
TotalDepositResponse,
|
||||||
VaultConfigBaseForAddr,
|
VaultConfigBaseForAddr,
|
||||||
} from 'types/generated/mars-params/MarsParams.types'
|
} from 'types/generated/mars-params/MarsParams.types'
|
||||||
import { ArrayOfMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
import {
|
||||||
|
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 }> {}
|
||||||
|
|
||||||
@ -62,3 +67,5 @@ 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()
|
||||||
|
@ -6,7 +6,9 @@ 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()
|
||||||
@ -15,6 +17,7 @@ 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 {
|
||||||
@ -32,7 +35,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||||
const key = rpc + contract
|
const key = rpc + contract
|
||||||
|
|
||||||
if (!_creditManagerQueryClient.get(key)) {
|
if (!_creditManagerQueryClient.get(key)) {
|
||||||
@ -49,7 +52,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||||
const key = rpc + contract
|
const key = rpc + contract
|
||||||
|
|
||||||
if (!_paramsQueryClient.get(key)) {
|
if (!_paramsQueryClient.get(key)) {
|
||||||
@ -66,7 +69,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||||
const key = rpc + contract
|
const key = rpc + contract
|
||||||
|
|
||||||
if (!_oracleQueryClient.get(key)) {
|
if (!_oracleQueryClient.get(key)) {
|
||||||
@ -82,7 +85,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(chainConfig.endpoints.rpc)
|
const client = await getClient(getUrl(chainConfig.endpoints.rpc))
|
||||||
return new MarsMockVaultQueryClient(client, address)
|
return new MarsMockVaultQueryClient(client, address)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
@ -92,7 +95,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(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)
|
||||||
@ -108,7 +111,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(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)
|
||||||
@ -124,7 +127,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 = chainConfig.endpoints.rpc
|
const rpc = getUrl(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)
|
||||||
@ -137,13 +140,31 @@ 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
src/api/v1/getV1Positions.ts
Normal file
41
src/api/v1/getV1Positions.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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,6 +29,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function AssetAmountSelectActionModal(props: Props) {
|
export default function AssetAmountSelectActionModal(props: Props) {
|
||||||
const {
|
const {
|
||||||
|
account,
|
||||||
asset,
|
asset,
|
||||||
title,
|
title,
|
||||||
coinBalances,
|
coinBalances,
|
||||||
@ -41,7 +42,6 @@ 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,7 +54,6 @@ 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}
|
||||||
|
@ -35,18 +35,9 @@ 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='mt-6'>
|
<Card className='w-full'>
|
||||||
<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'>
|
||||||
@ -90,7 +81,6 @@ 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()
|
||||||
|
|
||||||
@ -237,7 +227,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'>
|
||||||
{getAssetLogo(modal)}
|
<AssetImage asset={asset} size={24} />
|
||||||
<Text>
|
<Text>
|
||||||
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
|
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
|
||||||
</Text>
|
</Text>
|
||||||
@ -251,14 +241,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'}
|
||||||
/>
|
/>
|
||||||
{totalDebt.isGreaterThan(0) && (
|
{accountDebt.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={totalDebt.toNumber()}
|
amount={accountDebt.toNumber()}
|
||||||
options={{
|
options={{
|
||||||
decimals: asset.decimals,
|
decimals: asset.decimals,
|
||||||
abbreviated: false,
|
abbreviated: false,
|
||||||
@ -267,7 +257,7 @@ function BorrowModal(props: Props) {
|
|||||||
/>
|
/>
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
className='text-xs'
|
className='text-xs'
|
||||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)}
|
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||||
parentheses
|
parentheses
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -303,59 +293,57 @@ 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 min-h-[380px]'
|
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||||
>
|
>
|
||||||
<div className='flex flex-wrap w-full'>
|
<TokenInputWithSlider
|
||||||
<TokenInputWithSlider
|
asset={asset}
|
||||||
asset={asset}
|
onChange={handleChange}
|
||||||
onChange={handleChange}
|
onDebounce={onDebounce}
|
||||||
onDebounce={onDebounce}
|
amount={amount}
|
||||||
amount={amount}
|
max={max}
|
||||||
max={max}
|
disabled={max.isZero()}
|
||||||
disabled={max.isZero()}
|
className='w-full'
|
||||||
className='w-full'
|
maxText='Max'
|
||||||
maxText='Max'
|
warningMessages={[]}
|
||||||
warningMessages={[]}
|
/>
|
||||||
/>
|
{isRepay && maxRepayAmount.isZero() && (
|
||||||
{isRepay && maxRepayAmount.isZero() && (
|
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
)}
|
||||||
)}
|
{isRepay ? (
|
||||||
{isRepay ? (
|
<>
|
||||||
<>
|
<Divider />
|
||||||
<Divider className='my-6' />
|
<div className='flex items-center w-full'>
|
||||||
<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>
|
||||||
<div className='flex flex-wrap items-center justify-end'>
|
<Switch
|
||||||
<Switch
|
name='borrow-to-wallet'
|
||||||
name='borrow-to-wallet'
|
checked={repayFromWallet}
|
||||||
checked={repayFromWallet}
|
onChange={setRepayFromWallet}
|
||||||
onChange={setRepayFromWallet}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
) : (
|
||||||
) : (
|
<>
|
||||||
<>
|
<Divider />
|
||||||
<Divider className='my-6' />
|
<div className='flex items-center w-full'>
|
||||||
<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>
|
||||||
<div className='flex flex-wrap items-center justify-end'>
|
<Switch
|
||||||
<Switch
|
name='borrow-to-wallet'
|
||||||
name='borrow-to-wallet'
|
checked={borrowToWallet}
|
||||||
checked={borrowToWallet}
|
onChange={setBorrowToWallet}
|
||||||
onChange={setBorrowToWallet}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
onClick={onConfirmClick}
|
onClick={onConfirmClick}
|
||||||
className='w-full'
|
className='w-full'
|
||||||
|
@ -23,6 +23,7 @@ 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()
|
||||||
@ -65,8 +66,11 @@ 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,6 +10,8 @@ import {
|
|||||||
LendAndReclaimModalController,
|
LendAndReclaimModalController,
|
||||||
SettingsModal,
|
SettingsModal,
|
||||||
UnlockModal,
|
UnlockModal,
|
||||||
|
V1BorrowAndRepay,
|
||||||
|
V1DepositAndWithdraw,
|
||||||
VaultModal,
|
VaultModal,
|
||||||
WalletAssets,
|
WalletAssets,
|
||||||
WithdrawFromVaultsModal,
|
WithdrawFromVaultsModal,
|
||||||
@ -32,6 +34,8 @@ export default function ModalsContainer() {
|
|||||||
<AlertDialogController />
|
<AlertDialogController />
|
||||||
<HlsModal />
|
<HlsModal />
|
||||||
<HlsManageModal />
|
<HlsManageModal />
|
||||||
|
<V1DepositAndWithdraw />
|
||||||
|
<V1BorrowAndRepay />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,13 @@ 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 HlsModal } from 'components/Modals/HLS'
|
export { default as V1BorrowAndRepay } from 'components/Modals/v1/V1BorrowAndRepay'
|
||||||
export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
|
export { default as V1DepositAndWithdraw } from 'components/Modals/v1/V1DepositAndWithdraw'
|
||||||
|
179
src/components/Modals/v1/Borrow.tsx
Normal file
179
src/components/Modals/v1/Borrow.tsx
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
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
src/components/Modals/v1/Deposit.tsx
Normal file
82
src/components/Modals/v1/Deposit.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
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
src/components/Modals/v1/Repay.tsx
Normal file
208
src/components/Modals/v1/Repay.tsx
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
15
src/components/Modals/v1/V1BorrowAndRepay.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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} />
|
||||||
|
}
|
15
src/components/Modals/v1/V1DepositAndWithdraw.tsx
Normal file
15
src/components/Modals/v1/V1DepositAndWithdraw.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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
src/components/Modals/v1/Withdraw.tsx
Normal file
66
src/components/Modals/v1/Withdraw.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
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}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -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 useStore from 'store'
|
|
||||||
import useChainConfig from 'hooks/useChainConfig'
|
import useChainConfig from 'hooks/useChainConfig'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
export default function RecentTransactions() {
|
export default function RecentTransactions() {
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
@ -47,7 +47,9 @@ 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'>Credit Account {accountId}</Text>
|
<Text className='flex font-bold'>
|
||||||
|
{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>
|
||||||
|
@ -10,6 +10,7 @@ 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
|
||||||
@ -53,7 +54,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(chainConfig.endpoints.rpc)
|
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||||
const walletClient: WalletClient = {
|
const walletClient: WalletClient = {
|
||||||
broadcast,
|
broadcast,
|
||||||
cosmWasmClient: cosmClient,
|
cosmWasmClient: cosmClient,
|
||||||
@ -137,7 +138,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(chainConfig.endpoints.rpc)
|
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||||
const walletClient: WalletClient = {
|
const walletClient: WalletClient = {
|
||||||
broadcast,
|
broadcast,
|
||||||
cosmWasmClient: cosmClient,
|
cosmWasmClient: cosmClient,
|
||||||
|
@ -13,7 +13,7 @@ export default function Wallet() {
|
|||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (address) return
|
if (address && address === currentWallet?.account.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)
|
if (accountBalanceData.length === 0 && account.id !== address)
|
||||||
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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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'
|
||||||
|
@ -12,18 +12,19 @@ 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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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 useHealthComputer from 'hooks/useHealthComputer'
|
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
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'
|
||||||
@ -33,33 +34,40 @@ 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 = useCurrentAccount()
|
const account = isV1 && page !== 'trade' ? v1Account : currentAccount
|
||||||
const focusComponent = useStore((s) => s.focusComponent)
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
const isOwnAccount = accountId && accountIds?.includes(accountId)
|
const isOwnAccount = (accountId && accountIds?.includes(accountId)) || account?.id === address
|
||||||
|
const hideAccountDetails =
|
||||||
|
!address || focusComponent || !isOwnAccount || isHLS || page.includes('portfolio')
|
||||||
|
const isLoadingAccountDetails = (isLoading && accountId && !focusComponent) || !account
|
||||||
|
|
||||||
if (!address || focusComponent || !isOwnAccount || isHLS) return null
|
if (hideAccountDetails) return null
|
||||||
|
if (isLoadingAccountDetails) return <Skeleton />
|
||||||
|
|
||||||
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
return <AccountDetails account={account} page={page} />
|
||||||
|
|
||||||
return <AccountDetails account={account} />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account
|
account: Account
|
||||||
|
page: Page
|
||||||
}
|
}
|
||||||
|
|
||||||
function AccountDetails(props: Props) {
|
function AccountDetails(props: Props) {
|
||||||
const { account } = props
|
const { account, page } = 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>(
|
||||||
@ -124,10 +132,7 @@ function AccountDetails(props: Props) {
|
|||||||
vaultAprs,
|
vaultAprs,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const isFullWidth =
|
const isFullWidth = page === 'trade' || page === 'perps'
|
||||||
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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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,6 +42,7 @@ 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),
|
||||||
@ -68,10 +69,9 @@ export default function AccountSummaryHeader(props: Props) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isAccountDetails && (
|
{isAccountDetails && (
|
||||||
<Text
|
<Text size='sm' className='w-full pb-1 text-white/50'>
|
||||||
size='sm'
|
{account.id === address ? 'Red Bank' : `Credit Account ${account.id}`}
|
||||||
className='w-full pb-1 text-white/50'
|
</Text>
|
||||||
>{`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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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'
|
||||||
|
@ -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 data = useBorrowMarketAssetsTableData()
|
const { accountBorrowedAssets, availableAssets, allAssets } = useBorrowMarketAssetsTableData()
|
||||||
|
|
||||||
if (!data?.allAssets?.length) {
|
if (!allAssets?.length) {
|
||||||
return <Fallback />
|
return <Fallback />
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DepositedBorrowingsTable data={data.accountBorrowedAssets} isLoading={false} />
|
<ActiveBorrowingsTable data={accountBorrowedAssets} isLoading={false} />
|
||||||
<AvailableBorrowingsTable data={data.availableAssets} isLoading={false} />
|
<AvailableBorrowingsTable data={availableAssets} isLoading={false} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
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 useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns'
|
import useBorrowingsColumns from 'components/borrow/Table/Columns/useActiveColumns'
|
||||||
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 DepositedBorrowingsTable(props: Props) {
|
export default function ActiveBorrowingsTable(props: Props) {
|
||||||
const columns = useDepositedColumns()
|
const columns = useBorrowingsColumns({ v1: props.v1 })
|
||||||
|
|
||||||
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
|
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
|
||||||
return <MarketDetails row={row} type='borrow' />
|
return <MarketDetails row={row} type='borrow' />
|
||||||
@ -22,10 +24,17 @@ export default function DepositedBorrowingsTable(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
title='Borrowed Assets'
|
title={props.v1 ? 'Borrowings' : 'Borrowed Assets'}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={props.data}
|
data={props.data}
|
||||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
initialSorting={
|
||||||
|
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,36 +0,0 @@
|
|||||||
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} />
|
|
||||||
}
|
|
30
src/components/borrow/Table/Columns/DebtValue.tsx
Normal file
30
src/components/borrow/Table/Columns/DebtValue.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
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='flex justify-end z-10'>
|
<div className='z-10 flex justify-end'>
|
||||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -3,15 +3,23 @@ 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 Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt'
|
import DebtValue, {
|
||||||
|
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'
|
||||||
|
|
||||||
export default function useDepositedColumns() {
|
interface Props {
|
||||||
|
v1?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useActiveColumns(props: Props) {
|
||||||
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -19,8 +27,10 @@ export default function useDepositedColumns() {
|
|||||||
cell: ({ row }) => <Name data={row.original} />,
|
cell: ({ row }) => <Name data={row.original} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...DEBT_META,
|
...DEBT_VALUE_META,
|
||||||
cell: ({ row }) => <Debt data={row.original} />,
|
cell: ({ row }) => (
|
||||||
|
<DebtValue asset={row.original.asset} debtAmount={row.original.accountDebtAmount} />
|
||||||
|
),
|
||||||
sortingFn: debtSortingFn,
|
sortingFn: debtSortingFn,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -34,12 +44,13 @@ export default function useDepositedColumns() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
...MANAGE_META,
|
...MANAGE_META,
|
||||||
cell: ({ row }) => <Manage data={row.original} />,
|
cell: ({ row }) =>
|
||||||
|
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,11 +1,14 @@
|
|||||||
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[]
|
||||||
@ -18,15 +21,21 @@ export default function useBorrowMarketAssetsTableData() {
|
|||||||
markets
|
markets
|
||||||
.filter((market) => market.borrowEnabled)
|
.filter((market) => market.borrowEnabled)
|
||||||
.forEach((market) => {
|
.forEach((market) => {
|
||||||
const debt = account?.debts?.find((debt) => debt.denom === market.asset.denom)
|
const amount =
|
||||||
|
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,
|
||||||
accountDebt: debt?.amount,
|
accountDebtAmount: amount,
|
||||||
|
accountDebtValue: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borrowMarketAsset.accountDebtAmount?.isZero()) {
|
||||||
|
availableAssets.push(borrowMarketAsset)
|
||||||
|
} else {
|
||||||
|
accountBorrowedAssets.push(borrowMarketAsset)
|
||||||
}
|
}
|
||||||
;(borrowMarketAsset.accountDebt ? accountBorrowedAssets : availableAssets).push(
|
|
||||||
borrowMarketAsset,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -34,5 +43,5 @@ export default function useBorrowMarketAssetsTableData() {
|
|||||||
availableAssets,
|
availableAssets,
|
||||||
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
||||||
}
|
}
|
||||||
}, [account?.debts, markets])
|
}, [account?.debts, markets, convertAmount])
|
||||||
}
|
}
|
||||||
|
@ -15,19 +15,28 @@ 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 })
|
useStore.setState({ isHLS: 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 ',
|
||||||
isHLS ? 'bg-body-hls' : 'bg-body',
|
bodyClassName,
|
||||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -39,7 +48,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',
|
||||||
isHLS ? ' bg-orb-primary-hls' : 'bg-orb-primary',
|
primaryOrbClassName,
|
||||||
'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',
|
||||||
@ -53,7 +62,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',
|
||||||
isHLS ? ' bg-orb-secondary-hls' : 'bg-orb-secondary',
|
secondaryOrbClassName,
|
||||||
'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',
|
||||||
)}
|
)}
|
||||||
@ -66,7 +75,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 ',
|
||||||
isHLS ? ' bg-orb-tertiary-hls' : 'bg-orb-tertiary',
|
tertiaryOrbClassName,
|
||||||
'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',
|
||||||
|
@ -9,6 +9,7 @@ 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'
|
||||||
@ -17,7 +18,7 @@ import useStore from 'store'
|
|||||||
interface Props {
|
interface Props {
|
||||||
text: string | ReactNode
|
text: string | ReactNode
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
bg: 'borrow' | 'lend' | 'farm' | 'portfolio' | 'hls-farm' | 'hls-staking'
|
bg: Page
|
||||||
}
|
}
|
||||||
|
|
||||||
function IntroBackground(props: { bg: Props['bg'] }) {
|
function IntroBackground(props: { bg: Props['bg'] }) {
|
||||||
@ -52,6 +53,12 @@ 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'>
|
||||||
|
@ -23,7 +23,7 @@ export default function MarketDetails({ row, type }: Props) {
|
|||||||
symbol: displayCurrencySymbol,
|
symbol: displayCurrencySymbol,
|
||||||
} = useDisplayCurrencyPrice()
|
} = useDisplayCurrencyPrice()
|
||||||
|
|
||||||
const { asset, ltv, cap, liquidity, deposits, debt } = row.original
|
const { asset, ltv, deposits, debt } = row.original
|
||||||
|
|
||||||
const details: Detail[] = useMemo(() => {
|
const details: Detail[] = useMemo(() => {
|
||||||
const isDollar = displayCurrencySymbol === '$'
|
const isDollar = displayCurrencySymbol === '$'
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
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,11 +12,12 @@ 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', props.className)}>
|
<div className={classNames('flex w-full items-center ', 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}
|
||||||
@ -24,8 +25,9 @@ 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'>
|
<Text size='sm' className='px-2 py-3 max-w-[320px]'>
|
||||||
{props.tooltip}
|
{props.tooltip}
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
|
65
src/components/common/Tab.tsx
Normal file
65
src/components/common/Tab.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
@ -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,6 +99,13 @@ 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'>
|
||||||
@ -141,7 +148,7 @@ export default function Toaster() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!isError && toast.accountId && (
|
{!isError && toast.accountId && (
|
||||||
<Text className='mb-1 font-bold text-white'>{`Credit Account ${toast.accountId}`}</Text>
|
<Text className='mb-1 font-bold text-white'>{target}</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'>
|
||||||
|
@ -38,7 +38,7 @@ export const Tooltip = (props: Props) => {
|
|||||||
placement={props.placement ?? 'top'}
|
placement={props.placement ?? 'top'}
|
||||||
render={() => (
|
render={() => (
|
||||||
<TooltipContent
|
<TooltipContent
|
||||||
hideArrow={props.hideArrow}
|
hideArrow={props.placement === 'bottom' ? true : props.hideArrow}
|
||||||
type={props.type}
|
type={props.type}
|
||||||
content={props.content}
|
content={props.content}
|
||||||
className={props.contentClassName}
|
className={props.contentClassName}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
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,7 +1,5 @@
|
|||||||
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,17 +1,16 @@
|
|||||||
import moment from 'moment/moment'
|
import moment from 'moment/moment'
|
||||||
import React, { useCallback, useMemo, useState } from 'react'
|
import { 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 {
|
||||||
@ -104,7 +103,7 @@ export default function Manage(props: Props) {
|
|||||||
if (!address) return null
|
if (!address) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-end z-10'>
|
<div className='z-10 flex justify-end'>
|
||||||
<DropDownButton
|
<DropDownButton
|
||||||
items={ITEMS}
|
items={ITEMS}
|
||||||
text='Manage'
|
text='Manage'
|
@ -1,16 +1,15 @@
|
|||||||
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/earn/farm/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/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/earn/farm/Table/Columns/DepositCap'
|
} from 'components/farm/Table/Columns/DepositCap'
|
||||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||||
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
|
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
|
||||||
|
|
||||||
import { Deposit, DEPOSIT_META } from './Deposit'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
@ -1,18 +1,16 @@
|
|||||||
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/earn/farm/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy'
|
||||||
import DepositCap, {
|
import DepositCap, {
|
||||||
DEPOSIT_CAP_META,
|
DEPOSIT_CAP_META,
|
||||||
depositCapSortingFn,
|
depositCapSortingFn,
|
||||||
} from 'components/earn/farm/Table/Columns/DepositCap'
|
} from 'components/farm/Table/Columns/DepositCap'
|
||||||
import Manage, { MANAGE_META } from 'components/earn/farm/Table/Columns/Manage'
|
import Manage, { MANAGE_META } from 'components/farm/Table/Columns/Manage'
|
||||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||||
import PositionValue, {
|
import PositionValue, { POSITION_VALUE_META } from 'components/farm/Table/Columns/PositionValue'
|
||||||
POSITION_VALUE_META,
|
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
|
||||||
} 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,7 +1,5 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import Table from 'components/common/Table'
|
import Table from 'components/common/Table'
|
||||||
import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
|
import useDepositedColumns from 'components/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/earn/farm/Table/AvailableVaultsTable'
|
import AvailableVaultsTable from 'components/farm/Table/AvailableVaultsTable'
|
||||||
import DepositedVaultsTable from 'components/earn/farm/Table/DepositedVaultsTable'
|
import DepositedVaultsTable from 'components/farm/Table/DepositedVaultsTable'
|
||||||
import VaultUnlockBanner from 'components/earn/farm/VaultUnlockBanner'
|
import VaultUnlockBanner from 'components/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'
|
@ -36,8 +36,7 @@ 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'] : ['lend'], label: 'Earn' },
|
{ pages: chainConfig.farm ? ['lend', 'farm', 'borrow'] : ['lend'], label: 'Lend & Borrow' },
|
||||||
{ 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) },
|
||||||
@ -49,6 +48,7 @@ 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 />}
|
||||||
{address && !isHLS && <AccountMenu />}
|
{showAccountMenu && <AccountMenu />}
|
||||||
<Wallet />
|
<Wallet />
|
||||||
<ChainSelect />
|
<ChainSelect />
|
||||||
<Settings />
|
<Settings />
|
||||||
|
@ -13,9 +13,11 @@ 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
|
||||||
@ -28,7 +30,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 && <Route path='/farm' element={<FarmPage />} />}
|
{chainConfig.farm && !isV1 && <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 />} />
|
||||||
@ -41,7 +43,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 && <Route path='farm' element={<FarmPage />} />}
|
{chainConfig.farm && !isV1 && <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 React, { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import DepositCap, { DEPOSIT_CAP_META } from 'components/earn/farm/Table/Columns/DepositCap'
|
import DepositCap, { DEPOSIT_CAP_META } from 'components/farm/Table/Columns/DepositCap'
|
||||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||||
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
|
import TVL, { TVL_META } from 'components/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'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import AvailableLendsTable from 'components/earn/lend/Table/AvailableLendsTable'
|
import AvailableLendsTable from 'components/lend/Table/AvailableLendsTable'
|
||||||
import DepositedLendsTable from 'components/earn/lend/Table/DepositedLendsTable'
|
import DepositedLendsTable from 'components/lend/Table/DepositedLendsTable'
|
||||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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/earn/lend/Table/Columns/Name'
|
import { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||||
import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
|
import useAvailableColumns from 'components/lend/Table/Columns/useAvailableColumns'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: LendingMarketTableData[]
|
data: LendingMarketTableData[]
|
@ -5,6 +5,7 @@ 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/earn/lend/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
|
||||||
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
|
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
|
||||||
import DepositCap, {
|
import DepositCap, {
|
||||||
DEPOSIT_CAP_META,
|
DEPOSIT_CAP_META,
|
||||||
marketDepositCapSortingFn,
|
marketDepositCapSortingFn,
|
||||||
} from 'components/earn/lend/Table/Columns/DepositCap'
|
} from 'components/lend/Table/Columns/DepositCap'
|
||||||
import LendButton, { LEND_BUTTON_META } from 'components/earn/lend/Table/Columns/LendButton'
|
import LendButton, { LEND_BUTTON_META } from 'components/lend/Table/Columns/LendButton'
|
||||||
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
@ -1,21 +1,23 @@
|
|||||||
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/earn/lend/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
|
||||||
import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron'
|
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
|
||||||
import DepositCap, {
|
import DepositCap, {
|
||||||
DEPOSIT_CAP_META,
|
DEPOSIT_CAP_META,
|
||||||
marketDepositCapSortingFn,
|
marketDepositCapSortingFn,
|
||||||
} from 'components/earn/lend/Table/Columns/DepositCap'
|
} from 'components/lend/Table/Columns/DepositCap'
|
||||||
import DepositValue, {
|
import DepositValue, {
|
||||||
DEPOSIT_VALUE_META,
|
DEPOSIT_VALUE_META,
|
||||||
depositedSortingFn,
|
depositedSortingFn,
|
||||||
} from 'components/earn/lend/Table/Columns/DepositValue'
|
} from 'components/lend/Table/Columns/DepositValue'
|
||||||
import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage'
|
import Manage, { MANAGE_META } from 'components/lend/Table/Columns/Manage'
|
||||||
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/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) {
|
||||||
@ -49,12 +51,13 @@ export default function useDepositedColumns(props: Props) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
...MANAGE_META,
|
...MANAGE_META,
|
||||||
cell: ({ row }) => <Manage data={row.original} />,
|
cell: ({ row }) =>
|
||||||
|
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.isLoading, props.v1])
|
||||||
}
|
}
|
@ -3,16 +3,18 @@ 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/earn/lend/Table/Columns/Name'
|
import { DEPOSIT_VALUE_META } from 'components/lend/Table/Columns/DepositValue'
|
||||||
import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
|
import { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||||
|
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 })
|
const columns = useDepositedColumns({ isLoading: props.isLoading, v1: props.v1 })
|
||||||
|
|
||||||
const renderExpanded = useCallback(
|
const renderExpanded = useCallback(
|
||||||
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
|
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
|
||||||
@ -23,10 +25,17 @@ export default function DepositedLendsTable(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
title='Lent Assets'
|
title={props.v1 ? 'Deposits' : 'Lent Assets'}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={props.data}
|
data={props.data}
|
||||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
initialSorting={
|
||||||
|
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}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
@ -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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||||
import useAccount from 'hooks/accounts/useAccount'
|
import useAccount from 'hooks/accounts/useAccount'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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,6 +17,7 @@ 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) {
|
||||||
@ -45,15 +46,25 @@ function Content(props: Props) {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={positionValue} />,
|
title: (
|
||||||
|
<DisplayCurrency
|
||||||
|
className='text-xl'
|
||||||
|
coin={positionValue}
|
||||||
|
options={{ abbreviated: false }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={debts} />,
|
title: (
|
||||||
|
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={netWorth} />,
|
title: (
|
||||||
|
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -74,21 +85,23 @@ function Content(props: Props) {
|
|||||||
title: (
|
title: (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className='text-xl'
|
className='text-xl'
|
||||||
amount={leverage.toNumber()}
|
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()}
|
||||||
options={{ suffix: 'x' }}
|
options={{ suffix: 'x' }}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[4].sub,
|
sub: props.v1 ? 'Total Leverage' : DEFAULT_PORTFOLIO_STATS[4].sub,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
|
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, props.v1])
|
||||||
|
|
||||||
|
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={`Credit Account ${props.accountId}`}
|
title={props.v1 ? 'Wallet Mode Portfolio' : `Credit Account ${props.accountId}`}
|
||||||
accountId={props.accountId}
|
accountId={props.accountId}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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'
|
||||||
|
@ -4,9 +4,10 @@ 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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/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'
|
||||||
@ -27,8 +28,11 @@ 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)
|
||||||
@ -60,15 +64,25 @@ export default function PortfolioSummary() {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={positionValue} />,
|
title: (
|
||||||
|
<DisplayCurrency
|
||||||
|
className='text-xl'
|
||||||
|
coin={positionValue}
|
||||||
|
options={{ abbreviated: false }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[0].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={debts} />,
|
title: (
|
||||||
|
<DisplayCurrency className='text-xl' coin={debts} options={{ abbreviated: false }} />
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[1].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: <DisplayCurrency className='text-xl' coin={netWorth} />,
|
title: (
|
||||||
|
<DisplayCurrency className='text-xl' coin={netWorth} options={{ abbreviated: false }} />
|
||||||
|
),
|
||||||
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
|
sub: DEFAULT_PORTFOLIO_STATS[2].sub,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -89,14 +103,14 @@ export default function PortfolioSummary() {
|
|||||||
title: (
|
title: (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className='text-xl'
|
className='text-xl'
|
||||||
amount={leverage.toNumber()}
|
amount={isNaN(leverage.toNumber()) ? 1 : leverage.toNumber()}
|
||||||
options={{ suffix: 'x' }}
|
options={{ suffix: 'x' }}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
sub: 'Combined leverage',
|
sub: 'Combined leverage',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
|
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs, v1Account])
|
||||||
|
|
||||||
if (!walletAddress && !urlAddress) return null
|
if (!walletAddress && !urlAddress) return null
|
||||||
|
|
||||||
|
@ -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/earn/lend/Table/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||||
|
|
||||||
export default function AccountDetailsCard() {
|
export default function AccountDetailsCard() {
|
||||||
|
47
src/components/v1/Borrowings.tsx
Normal file
47
src/components/v1/Borrowings.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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
src/components/v1/Deposits.tsx
Normal file
46
src/components/v1/Deposits.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
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 />
|
||||||
|
}
|
20
src/components/v1/Table/borrowings/Columns/Action.tsx
Normal file
20
src/components/v1/Table/borrowings/Columns/Action.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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} />
|
||||||
|
}
|
50
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
50
src/components/v1/Table/borrowings/Columns/BorrowButton.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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 don’t 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>
|
||||||
|
)
|
||||||
|
}
|
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
47
src/components/v1/Table/borrowings/Columns/Manage.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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 don’t 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>
|
||||||
|
)
|
||||||
|
}
|
19
src/components/v1/Table/deposits/Columns/Action.tsx
Normal file
19
src/components/v1/Table/deposits/Columns/Action.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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} />
|
||||||
|
}
|
50
src/components/v1/Table/deposits/Columns/DepositButton.tsx
Normal file
50
src/components/v1/Table/deposits/Columns/DepositButton.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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 don’t 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>
|
||||||
|
)
|
||||||
|
}
|
48
src/components/v1/Table/deposits/Columns/Manage.tsx
Normal file
48
src/components/v1/Table/deposits/Columns/Manage.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
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 don’t 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>
|
||||||
|
)
|
||||||
|
}
|
38
src/components/v1/Table/useV1BorrowingsTableData.ts
Normal file
38
src/components/v1/Table/useV1BorrowingsTableData.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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])
|
||||||
|
}
|
39
src/components/v1/Table/useV1DepositsTableData.ts
Normal file
39
src/components/v1/Table/useV1DepositsTableData.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
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
src/components/v1/V1Intro.tsx
Normal file
21
src/components/v1/V1Intro.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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‘t be used</span> in the Trade or Farm interface.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
bg='v1'
|
||||||
|
>
|
||||||
|
{!address && <WalletConnectButton className='mt-4' />}
|
||||||
|
</Intro>
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
export const EARN_TABS: Tab[] = [
|
export const LEND_AND_BORROW_TABS: Tab[] = [
|
||||||
{ page: 'lend', name: 'Lend' },
|
{ page: 'lend', name: 'Lend' },
|
||||||
|
{ page: 'borrow', name: 'Borrow' },
|
||||||
{ page: 'farm', name: 'Farm' },
|
{ page: 'farm', name: 'Farm' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
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 && `chains/${chainConfig.id}/accounts/${accountId}`,
|
accountId && cacheKey,
|
||||||
() => getAccount(chainConfig, accountId),
|
() => (isV1 ? getV1Positions(chainConfig, accountId) : getAccount(chainConfig, accountId)),
|
||||||
{
|
{
|
||||||
suspense: suspense,
|
suspense: suspense,
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
|
@ -11,6 +11,7 @@ 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()
|
||||||
@ -18,7 +19,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(chainConfig.endpoints.rpc)
|
const client = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
creditManager: new MarsCreditManagerQueryClient(
|
creditManager: new MarsCreditManagerQueryClient(
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import Borrowings from 'components/borrow/Borrowings'
|
|
||||||
import BorrowIntro from 'components/borrow/BorrowIntro'
|
import BorrowIntro from 'components/borrow/BorrowIntro'
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
import Borrowings from 'components/borrow/Borrowings'
|
||||||
|
import Tab from 'components/common/Tab'
|
||||||
|
import V1Borrowings from 'components/v1/Borrowings'
|
||||||
|
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'>
|
||||||
<MigrationBanner />
|
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={1} showV1Toggle />
|
||||||
<BorrowIntro />
|
{isV1 ? <V1Intro /> : <BorrowIntro />}
|
||||||
<Borrowings />
|
{isV1 ? <V1Borrowings /> : <Borrowings />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import FarmIntro from 'components/earn/farm/FarmIntro'
|
import Tab from 'components/common/Tab'
|
||||||
import Vaults from 'components/earn/farm/Vaults'
|
import FarmIntro from 'components/farm/FarmIntro'
|
||||||
import Tab from 'components/earn/Tab'
|
import Vaults from 'components/farm/Vaults'
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
import { LEND_AND_BORROW_TABS } from 'constants/pages'
|
||||||
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'>
|
||||||
<MigrationBanner />
|
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={2} showV1Toggle />
|
||||||
<Tab tabs={EARN_TABS} activeTabIdx={1} />
|
|
||||||
<FarmIntro />
|
<FarmIntro />
|
||||||
<Vaults />
|
<Vaults />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import Tab from 'components/earn/Tab'
|
import Tab from 'components/common/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 />
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import Tab from 'components/earn/Tab'
|
import Tab from 'components/common/Tab'
|
||||||
import ActiveStakingAccounts from 'components/hls/Staking/ActiveStakingAccounts'
|
import ActiveStakingAccounts from 'components/hls/Staking/ActiveStakingAccounts'
|
||||||
import AvailableHlsStakingAssets from 'components/hls/Staking/AvailableHLSStakingAssets'
|
import AvailableHlsStakingAssets from 'components/hls/Staking/AvailableHLSStakingAssets'
|
||||||
import HLSStakingIntro from 'components/hls/Staking/HLSStakingIntro'
|
import HLSStakingIntro from 'components/hls/Staking/HLSStakingIntro'
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
|
||||||
import { HLS_TABS } from 'constants/pages'
|
import { HLS_TABS } from 'constants/pages'
|
||||||
|
|
||||||
export default function HLSStakingPage() {
|
export default function HLSStakingPage() {
|
||||||
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={0} />
|
<Tab tabs={HLS_TABS} activeTabIdx={0} />
|
||||||
<HLSStakingIntro />
|
<HLSStakingIntro />
|
||||||
<AvailableHlsStakingAssets />
|
<AvailableHlsStakingAssets />
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
import Tab from 'components/common/Tab'
|
||||||
import Tab from 'components/earn/Tab'
|
import LendIntro from 'components/lend/LendIntro'
|
||||||
import LendIntro from 'components/earn/lend/LendIntro'
|
import Lends from 'components/lend/Lends'
|
||||||
import Lends from 'components/earn/lend/Lends'
|
import Deposits from 'components/v1/Deposits'
|
||||||
import { EARN_TABS } from 'constants/pages'
|
import V1Intro from 'components/v1/V1Intro'
|
||||||
import useChainConfig from 'hooks/useChainConfig'
|
import { LEND_AND_BORROW_TABS } from 'constants/pages'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
export default function LendPage() {
|
export default function LendPage() {
|
||||||
const chainConfig = useChainConfig()
|
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'>
|
||||||
<MigrationBanner />
|
<Tab tabs={LEND_AND_BORROW_TABS} activeTabIdx={0} showV1Toggle />
|
||||||
{chainConfig.farm && <Tab tabs={EARN_TABS} activeTabIdx={0} />}
|
{isV1 ? <V1Intro /> : <LendIntro />}
|
||||||
<LendIntro />
|
{isV1 ? <Deposits /> : <Lends />}
|
||||||
<Lends />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||||
|
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
|
||||||
import ShareBar from 'components/common/ShareBar'
|
import ShareBar from 'components/common/ShareBar'
|
||||||
import Balances from 'components/portfolio/Account/Balances'
|
import Balances from 'components/portfolio/Account/Balances'
|
||||||
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
||||||
@ -25,7 +24,6 @@ export default function PortfolioAccountPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
<MigrationBanner />
|
|
||||||
<BreadCrumbs accountId={accountId} />
|
<BreadCrumbs accountId={accountId} />
|
||||||
<Summary accountId={accountId} />
|
<Summary accountId={accountId} />
|
||||||
<Balances accountId={accountId} />
|
<Balances accountId={accountId} />
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
import { useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import ShareBar from 'components/common/ShareBar'
|
||||||
|
import Summary from 'components/portfolio/Account/Summary'
|
||||||
import AccountOverview from 'components/portfolio/Overview'
|
import AccountOverview from 'components/portfolio/Overview'
|
||||||
import PortfolioSummary from 'components/portfolio/Overview/Summary'
|
import PortfolioSummary from 'components/portfolio/Overview/Summary'
|
||||||
import PortfolioIntro from 'components/portfolio/PortfolioIntro'
|
import PortfolioIntro from 'components/portfolio/PortfolioIntro'
|
||||||
import ShareBar from 'components/common/ShareBar'
|
|
||||||
|
|
||||||
export default function PortfolioPage() {
|
export default function PortfolioPage() {
|
||||||
|
const { address } = useParams()
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
<MigrationBanner />
|
|
||||||
<PortfolioIntro />
|
<PortfolioIntro />
|
||||||
<PortfolioSummary />
|
<PortfolioSummary />
|
||||||
|
{address && <Summary accountId={address} v1 />}
|
||||||
<AccountOverview />
|
<AccountOverview />
|
||||||
<ShareBar text='Have a look at this @mars_protocol portfolio!' />
|
<ShareBar text='Have a look at this @mars_protocol portfolio!' />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
|
||||||
import AccountDetailsCard from 'components/trade/AccountDetailsCard'
|
import AccountDetailsCard from 'components/trade/AccountDetailsCard'
|
||||||
import TradeChart from 'components/trade/TradeChart'
|
import TradeChart from 'components/trade/TradeChart'
|
||||||
import TradeModule from 'components/trade/TradeModule'
|
import TradeModule from 'components/trade/TradeModule'
|
||||||
@ -47,7 +46,6 @@ export default function TradePage() {
|
|||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col w-full h-full gap-4'>
|
<div className='flex flex-col w-full h-full gap-4'>
|
||||||
<MigrationBanner />
|
|
||||||
<div className='grid w-full grid-cols-[auto_346px] gap-4'>
|
<div className='grid w-full grid-cols-[auto_346px] gap-4'>
|
||||||
<TradeChart buyAsset={buyAsset} sellAsset={sellAsset} />
|
<TradeChart buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||||
<TradeModule buyAsset={buyAsset} sellAsset={sellAsset} isAdvanced={isAdvanced} />
|
<TradeModule buyAsset={buyAsset} sellAsset={sellAsset} isAdvanced={isAdvanced} />
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user