Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8c663b9e4 | ||
|
|
ea07d5f11e | ||
|
|
dae929d851 |
@@ -0,0 +1,13 @@
|
||||
# DO NOT EDIT THIS FILE WHEN USING DOCKER
|
||||
# These values are used to replace the values in the built app,
|
||||
# you should pass environment variables as defined in README.md
|
||||
|
||||
# CONFIG #
|
||||
NEXT_PUBLIC_NETWORK=mainnet
|
||||
|
||||
# OSMOSIS-1 #
|
||||
NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC
|
||||
NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST
|
||||
|
||||
# WALLET CONNECT #
|
||||
NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID
|
||||
+2
-8
@@ -6,24 +6,18 @@ RUN yarn install
|
||||
COPY . .
|
||||
RUN apk --update add patch
|
||||
RUN patch next.config.js next-config.patch
|
||||
|
||||
ENV NEXT_PUBLIC_NETWORK=mainnet
|
||||
ENV NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC
|
||||
ENV NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST
|
||||
ENV NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID
|
||||
ENV NODE_ENV=production
|
||||
|
||||
RUN yarn build
|
||||
|
||||
FROM node:20-alpine as runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=builder /app/package.json .
|
||||
COPY --from=builder /app/yarn.lock .
|
||||
COPY --from=builder /app/next.config.js .
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
|
||||
COPY entrypoint.sh .
|
||||
|
||||
RUN apk add --no-cache --upgrade bash
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mars-v2-frontend",
|
||||
"version": "2.2.4",
|
||||
"version": "2.2.3",
|
||||
"homepage": "./",
|
||||
"private": false,
|
||||
"license": "SEE LICENSE IN LICENSE FILE",
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<svg viewBox="0 0 240 240" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="240" height="240" rx="120" fill="#E50571" />
|
||||
<path d="M149.107 60.9396L63.3276 181.702H89.6637L175.888 60.9396H149.107Z" fill="white" />
|
||||
<path
|
||||
d="M92.4053 60.9396L117.644 96.5239L104.476 115.934L65.5205 60.9396H92.4053Z"
|
||||
fill="url(#paint0_linear_6269_3439)"
|
||||
/>
|
||||
<path
|
||||
d="M151.664 181.712L123.682 142.354L136.851 123.483L178 181.712H151.664Z"
|
||||
fill="url(#paint1_linear_6269_3439)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_6269_3439"
|
||||
x1="86.3698"
|
||||
y1="68.4878"
|
||||
x2="121.753"
|
||||
y2="111.957"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.75" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_6269_3439"
|
||||
x1="157.7"
|
||||
y1="172.547"
|
||||
x2="114.305"
|
||||
y2="113.014"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" stop-opacity="0.68" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
+1
-8
@@ -10,12 +10,7 @@ import {
|
||||
TotalDepositResponse,
|
||||
VaultConfigBaseForAddr,
|
||||
} from 'types/generated/mars-params/MarsParams.types'
|
||||
import {
|
||||
ArrayOfMarket,
|
||||
ArrayOfUserCollateralResponse,
|
||||
ArrayOfUserDebtResponse,
|
||||
UserCollateralResponse,
|
||||
} from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
import { ArrayOfMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
|
||||
interface Cache<T> extends Map<string, { data: T | null; timestamp: number }> {}
|
||||
|
||||
@@ -67,5 +62,3 @@ export const underlyingDebtCache: Cache<string> = new Map()
|
||||
export const previewDepositCache: Cache<{ vaultAddress: string; amount: string }> = new Map()
|
||||
export const stakingAprCache: Cache<StakingApr[]> = new Map()
|
||||
export const assetParamsCache: Cache<AssetParamsBaseForAddr[]> = new Map()
|
||||
export const userCollateralCache: Cache<ArrayOfUserCollateralResponse> = new Map()
|
||||
export const userDebtCache: Cache<ArrayOfUserDebtResponse> = new Map()
|
||||
|
||||
@@ -6,9 +6,7 @@ import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMo
|
||||
import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client'
|
||||
import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.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 { getUrl } from 'utils/url'
|
||||
|
||||
let _cosmWasmClient: Map<string, CosmWasmClient> = new Map()
|
||||
let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map()
|
||||
@@ -17,7 +15,6 @@ let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map()
|
||||
let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map()
|
||||
let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map()
|
||||
let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map()
|
||||
let _redBankQueryClient: Map<string, MarsRedBankQueryClient> = new Map()
|
||||
|
||||
const getClient = async (rpc: string) => {
|
||||
try {
|
||||
@@ -35,7 +32,7 @@ const getClient = async (rpc: string) => {
|
||||
const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.creditManager
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_creditManagerQueryClient.get(key)) {
|
||||
@@ -52,7 +49,7 @@ const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getParamsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.params
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_paramsQueryClient.get(key)) {
|
||||
@@ -69,7 +66,7 @@ const getParamsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getOracleQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.oracle
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_oracleQueryClient.get(key)) {
|
||||
@@ -85,7 +82,7 @@ const getOracleQueryClient = async (chainConfig: ChainConfig) => {
|
||||
|
||||
const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => {
|
||||
try {
|
||||
const client = await getClient(getUrl(chainConfig.endpoints.rpc))
|
||||
const client = await getClient(chainConfig.endpoints.rpc)
|
||||
return new MarsMockVaultQueryClient(client, address)
|
||||
} catch (error) {
|
||||
throw error
|
||||
@@ -95,7 +92,7 @@ const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) =>
|
||||
const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.incentives
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
if (!_incentivesQueryClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@@ -111,7 +108,7 @@ const getIncentivesQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.swapper
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
if (!_swapperOsmosisClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@@ -127,7 +124,7 @@ const getSwapperQueryClient = async (chainConfig: ChainConfig) => {
|
||||
const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.perps
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const rpc = chainConfig.endpoints.rpc
|
||||
const key = rpc + contract
|
||||
if (!_perpsClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
@@ -140,31 +137,13 @@ const getPerpsQueryClient = async (chainConfig: ChainConfig) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getRedBankQueryClient = async (chainConfig: ChainConfig) => {
|
||||
try {
|
||||
const contract = chainConfig.contracts.redBank
|
||||
const rpc = getUrl(chainConfig.endpoints.rpc)
|
||||
const key = rpc + contract
|
||||
|
||||
if (!_redBankQueryClient.get(key)) {
|
||||
const client = await getClient(rpc)
|
||||
_redBankQueryClient.set(key, new MarsRedBankQueryClient(client, contract))
|
||||
}
|
||||
|
||||
return _redBankQueryClient.get(key)!
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getClient,
|
||||
getCreditManagerQueryClient,
|
||||
getIncentivesQueryClient,
|
||||
getOracleQueryClient,
|
||||
getParamsQueryClient,
|
||||
getPerpsQueryClient,
|
||||
getRedBankQueryClient,
|
||||
getSwapperQueryClient,
|
||||
getVaultQueryClient,
|
||||
getPerpsQueryClient,
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { cacheFn, userCollateralCache, userDebtCache } from 'api/cache'
|
||||
import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import {
|
||||
ArrayOfUserCollateralResponse,
|
||||
ArrayOfUserDebtResponse,
|
||||
} from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
|
||||
export default async function getV1Positions(
|
||||
chainConfig: ChainConfig,
|
||||
user?: string,
|
||||
): Promise<Account> {
|
||||
if (!user) return new Promise((_, reject) => reject('No account Wallet ID found'))
|
||||
|
||||
const redBankQueryClient = await getRedBankQueryClient(chainConfig)
|
||||
|
||||
const userCollateral: ArrayOfUserCollateralResponse = await cacheFn(
|
||||
() => redBankQueryClient.userCollaterals({ user: user, limit: 100 }),
|
||||
userCollateralCache,
|
||||
`${chainConfig.id}/v1/deposits/${user}`,
|
||||
)
|
||||
const userDebt: ArrayOfUserDebtResponse = await cacheFn(
|
||||
() => redBankQueryClient.userDebts({ user: user, limit: 100 }),
|
||||
userDebtCache,
|
||||
`${chainConfig.id}/v1/debts/${user}`,
|
||||
)
|
||||
|
||||
if (userCollateral && userDebt) {
|
||||
return {
|
||||
id: user,
|
||||
debts: userDebt.map((debt) => new BNCoin(debt)),
|
||||
lends: userCollateral.map((lend) => new BNCoin(lend)),
|
||||
deposits: [],
|
||||
vaults: [],
|
||||
perps: [],
|
||||
kind: 'default',
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((_, reject) => reject('No account found'))
|
||||
}
|
||||
@@ -10,12 +10,12 @@ import Text from 'components/common/Text'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
asset: Asset
|
||||
title: string
|
||||
coinBalances: BNCoin[]
|
||||
@@ -29,7 +29,6 @@ interface Props {
|
||||
|
||||
export default function AssetAmountSelectActionModal(props: Props) {
|
||||
const {
|
||||
account,
|
||||
asset,
|
||||
title,
|
||||
coinBalances,
|
||||
@@ -42,6 +41,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
} = props
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
||||
const account = useCurrentAccount()
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setAmount(value)
|
||||
@@ -54,6 +54,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
onAction(amount, amount.isEqualTo(maxAmount))
|
||||
}, [amount, maxAmount, onAction])
|
||||
|
||||
if (!account) return
|
||||
return (
|
||||
<Modal
|
||||
onClose={onClose}
|
||||
|
||||
@@ -35,9 +35,18 @@ interface Props {
|
||||
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 }) {
|
||||
return (
|
||||
<Card className='w-full'>
|
||||
<Card className='mt-6'>
|
||||
<div className='flex items-start p-4'>
|
||||
<InfoCircle className='w-6 mr-2 flex-0' />
|
||||
<div className='flex flex-col flex-1 gap-1'>
|
||||
@@ -81,6 +90,7 @@ function BorrowModal(props: Props) {
|
||||
const apy = modal.marketData.apy.borrow
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const totalDebt = BN(getDebtAmount(modal))
|
||||
const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO
|
||||
const markets = useMarkets()
|
||||
|
||||
@@ -227,7 +237,7 @@ function BorrowModal(props: Props) {
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<AssetImage asset={asset} size={24} />
|
||||
{getAssetLogo(modal)}
|
||||
<Text>
|
||||
{isRepay ? 'Repay' : 'Borrow'} {asset.symbol}
|
||||
</Text>
|
||||
@@ -241,14 +251,14 @@ function BorrowModal(props: Props) {
|
||||
title={formatPercent(modal.marketData.apy.borrow)}
|
||||
sub={'Borrow Rate APY'}
|
||||
/>
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
{totalDebt.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()}
|
||||
amount={totalDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
@@ -257,7 +267,7 @@ function BorrowModal(props: Props) {
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
@@ -293,57 +303,59 @@ function BorrowModal(props: Props) {
|
||||
<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'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap w-full'>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
{isRepay && maxRepayAmount.isZero() && (
|
||||
<RepayNotAvailable asset={asset} repayFromWallet={repayFromWallet} />
|
||||
)}
|
||||
{isRepay ? (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Repay from Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Repay your debt directly from your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider />
|
||||
<div className='flex items-center w-full'>
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={repayFromWallet}
|
||||
onChange={setRepayFromWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider className='my-6' />
|
||||
<div className='flex flex-wrap flex-1'>
|
||||
<Text className='w-full mb-1'>Receive funds to Wallet</Text>
|
||||
<Text size='xs' className='text-white/50'>
|
||||
Your borrowed funds will directly go to your wallet
|
||||
</Text>
|
||||
</div>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className='flex flex-wrap items-center justify-end'>
|
||||
<Switch
|
||||
name='borrow-to-wallet'
|
||||
checked={borrowToWallet}
|
||||
onChange={setBorrowToWallet}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
|
||||
@@ -23,7 +23,6 @@ interface Props {
|
||||
}
|
||||
|
||||
function LendAndReclaimModal({ currentAccount, config }: Props) {
|
||||
const account = useCurrentAccount()
|
||||
const lend = useStore((s) => s.lend)
|
||||
const reclaim = useStore((s) => s.reclaim)
|
||||
const { close } = useLendAndReclaimModal()
|
||||
@@ -66,11 +65,8 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
|
||||
},
|
||||
[asset.denom, close, currentAccount.id, isLendAction, lend, reclaim],
|
||||
)
|
||||
if (!account) return null
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={data} />}
|
||||
coinBalances={coinBalances}
|
||||
|
||||
@@ -10,8 +10,6 @@ import {
|
||||
LendAndReclaimModalController,
|
||||
SettingsModal,
|
||||
UnlockModal,
|
||||
V1BorrowAndRepay,
|
||||
V1DepositAndWithdraw,
|
||||
VaultModal,
|
||||
WalletAssets,
|
||||
WithdrawFromVaultsModal,
|
||||
@@ -34,8 +32,6 @@ export default function ModalsContainer() {
|
||||
<AlertDialogController />
|
||||
<HlsModal />
|
||||
<HlsManageModal />
|
||||
<V1DepositAndWithdraw />
|
||||
<V1BorrowAndRepay />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,13 +4,11 @@ export { default as AlertDialogController } from 'components/Modals/AlertDialog'
|
||||
export { default as BorrowModal } from 'components/Modals/BorrowModal'
|
||||
export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw'
|
||||
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 SettingsModal } from 'components/Modals/Settings'
|
||||
export { default as UnlockModal } from 'components/Modals/Unlock'
|
||||
export { default as VaultModal } from 'components/Modals/Vault'
|
||||
export { default as WalletAssets } from 'components/Modals/WalletAssets'
|
||||
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
|
||||
export { default as V1BorrowAndRepay } from 'components/Modals/v1/V1BorrowAndRepay'
|
||||
export { default as V1DepositAndWithdraw } from 'components/Modals/v1/V1DepositAndWithdraw'
|
||||
export { default as HlsModal } from 'components/Modals/HLS'
|
||||
export { default as HlsManageModal } from 'components/Modals/HLS/Manage'
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Modal from 'components/Modals/Modal'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Button from 'components/common/Button'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import Divider from 'components/common/Divider'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Borrow(props: Props) {
|
||||
const { account } = props
|
||||
const modal = useStore((s) => s.v1BorrowAndRepayModal)
|
||||
const baseAsset = useBaseAsset()
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [max, setMax] = useState(BN_ZERO)
|
||||
const { simulateBorrow } = useUpdatedAccount(account)
|
||||
const apy = modal?.data.apy.borrow ?? 0
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
|
||||
|
||||
const accountDebtWithInterest = useMemo(
|
||||
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||
[accountDebt, apy],
|
||||
)
|
||||
|
||||
const close = useCallback(() => {
|
||||
setAmount(BN_ZERO)
|
||||
useStore.setState({ v1BorrowAndRepayModal: null })
|
||||
}, [setAmount])
|
||||
|
||||
const onConfirmClick = useCallback(() => {
|
||||
v1Action('borrow', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
|
||||
close()
|
||||
}, [v1Action, asset, amount, close])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newAmount: BigNumber) => {
|
||||
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||
},
|
||||
[amount, setAmount],
|
||||
)
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
const borrowCoin = BNCoin.fromDenomAndBigNumber(
|
||||
asset.denom,
|
||||
amount.isGreaterThan(max) ? max : amount,
|
||||
)
|
||||
simulateBorrow('wallet', borrowCoin)
|
||||
}, [amount, max, asset, simulateBorrow])
|
||||
|
||||
const maxBorrow = useMemo(() => {
|
||||
const maxBorrowAmount = computeMaxBorrowAmount(asset.denom, 'wallet')
|
||||
|
||||
return BigNumber.min(maxBorrowAmount, modal?.data.liquidity || 0)
|
||||
}, [asset.denom, computeMaxBorrowAmount, modal?.data.liquidity])
|
||||
|
||||
useEffect(() => {
|
||||
if (maxBorrow.isEqualTo(max)) return
|
||||
setMax(maxBorrow)
|
||||
}, [account, maxBorrow, max])
|
||||
|
||||
useEffect(() => {
|
||||
if (amount.isLessThanOrEqualTo(max)) return
|
||||
handleChange(max)
|
||||
setAmount(max)
|
||||
}, [amount, max, handleChange])
|
||||
|
||||
if (!modal) return null
|
||||
return (
|
||||
<Modal
|
||||
onClose={close}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<AssetImage asset={modal.data.asset} size={24} />
|
||||
<Text>{`Borrow ${asset.symbol} from the Red Bank`}</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
|
||||
{accountDebt.isGreaterThan(0) && (
|
||||
<>
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
suffix: ` ${asset.symbol}`,
|
||||
}}
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Total Borrowed
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={modal.data.liquidity.toNumber() ?? 0}
|
||||
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
|
||||
animate
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data.liquidity ?? BN_ZERO)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Liquidity available
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-start flex-1 gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-1 p-4 bg-white/5'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
<Divider />
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
disabled={amount.isZero()}
|
||||
text={`Borrow ${asset.symbol}`}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { BN } from 'utils/helpers'
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Deposit(props: Props) {
|
||||
const { account } = props
|
||||
const baseAsset = useBaseAsset()
|
||||
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
|
||||
const address = useStore((s) => s.address)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [fundingAsset, setFundingAsset] = useState<BNCoin>(
|
||||
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
|
||||
)
|
||||
const { data: walletBalances } = useWalletBalances(address)
|
||||
const { simulateDeposits } = useUpdatedAccount(account)
|
||||
const balance = useCurrentWalletBalance(asset.denom)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
|
||||
const baseBalance = useMemo(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
[walletBalances, baseAsset],
|
||||
)
|
||||
|
||||
const close = useCallback(() => {
|
||||
useStore.setState({ v1DepositAndWithdrawModal: null })
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
v1Action('deposit', fundingAsset)
|
||||
close()
|
||||
}, [v1Action, fundingAsset, close])
|
||||
|
||||
useEffect(() => {
|
||||
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
|
||||
useStore.setState({ focusComponent: { component: <WalletBridges /> } })
|
||||
}
|
||||
}, [baseBalance])
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
simulateDeposits('lend', [fundingAsset])
|
||||
}, [fundingAsset, simulateDeposits])
|
||||
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setFundingAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
|
||||
},
|
||||
[asset.denom],
|
||||
)
|
||||
|
||||
if (!modal) return
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={modal.data} />}
|
||||
coinBalances={balance ? [BNCoin.fromCoin(balance)] : []}
|
||||
actionButtonText={`Deposit ${asset.symbol}`}
|
||||
title={`Deposit ${asset.symbol} into the Red Bank`}
|
||||
onClose={close}
|
||||
onAction={handleClick}
|
||||
onChange={handleAmountChange}
|
||||
onDebounce={onDebounce}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Modal from 'components/Modals/Modal'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Button from 'components/common/Button'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import Divider from 'components/common/Divider'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight, InfoCircle } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
function RepayNotAvailable(props: { asset: Asset }) {
|
||||
return (
|
||||
<Card className='w-full'>
|
||||
<div className='flex items-start p-4'>
|
||||
<InfoCircle className='w-6 mr-2 flex-0' />
|
||||
<div className='flex flex-col flex-1 gap-1'>
|
||||
<Text size='sm'>No funds for repay</Text>
|
||||
<Text
|
||||
size='xs'
|
||||
className='text-white/40'
|
||||
>{`Unfortunately you don't have any ${props.asset.symbol} in your Wallet to repay the debt.`}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Repay(props: Props) {
|
||||
const { account } = props
|
||||
const modal = useStore((s) => s.v1BorrowAndRepayModal)
|
||||
const baseAsset = useBaseAsset()
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const balance = useCurrentWalletBalance(asset.denom)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
const [max, setMax] = useState(BN_ZERO)
|
||||
const { simulateRepay } = useUpdatedAccount(account)
|
||||
const apy = modal?.data.apy.borrow ?? 0
|
||||
const accountDebt = modal?.data.accountDebtAmount ?? BN_ZERO
|
||||
const markets = useMarkets()
|
||||
|
||||
const accountDebtWithInterest = useMemo(
|
||||
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||
[accountDebt, apy],
|
||||
)
|
||||
|
||||
const overpayExeedsCap = useMemo(() => {
|
||||
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
|
||||
if (!marketAsset) return
|
||||
const overpayAmount = accountDebtWithInterest.minus(accountDebt)
|
||||
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
|
||||
|
||||
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
|
||||
}, [markets, asset.denom, accountDebt, accountDebtWithInterest])
|
||||
|
||||
const maxRepayAmount = useMemo(() => {
|
||||
const maxBalance = BN(balance?.amount ?? 0)
|
||||
return BigNumber.min(maxBalance, overpayExeedsCap ? accountDebt : accountDebtWithInterest)
|
||||
}, [accountDebtWithInterest, overpayExeedsCap, accountDebt, balance?.amount])
|
||||
|
||||
const close = useCallback(() => {
|
||||
setAmount(BN_ZERO)
|
||||
useStore.setState({ v1BorrowAndRepayModal: null })
|
||||
}, [setAmount])
|
||||
|
||||
const onConfirmClick = useCallback(() => {
|
||||
v1Action('repay', BNCoin.fromDenomAndBigNumber(asset.denom, amount))
|
||||
close()
|
||||
}, [v1Action, asset, amount, close])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newAmount: BigNumber) => {
|
||||
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||
},
|
||||
[amount, setAmount],
|
||||
)
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
const repayCoin = BNCoin.fromDenomAndBigNumber(
|
||||
asset.denom,
|
||||
amount.isGreaterThan(accountDebt) ? accountDebt : amount,
|
||||
)
|
||||
simulateRepay(repayCoin, true)
|
||||
}, [amount, accountDebt, asset, simulateRepay])
|
||||
|
||||
useEffect(() => {
|
||||
if (maxRepayAmount.isEqualTo(max)) return
|
||||
setMax(maxRepayAmount)
|
||||
}, [max, maxRepayAmount])
|
||||
|
||||
useEffect(() => {
|
||||
if (amount.isLessThanOrEqualTo(max)) return
|
||||
handleChange(max)
|
||||
setAmount(max)
|
||||
}, [amount, max, handleChange])
|
||||
|
||||
if (!modal) return null
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onClose={close}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<AssetImage asset={modal.data.asset} size={24} />
|
||||
<Text>
|
||||
{'Repay'} {asset.symbol}
|
||||
</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||
<TitleAndSubCell title={formatPercent(apy)} sub={'Borrow Rate APY'} />
|
||||
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={accountDebt.toNumber()}
|
||||
options={{
|
||||
decimals: asset.decimals,
|
||||
abbreviated: false,
|
||||
suffix: ` ${asset.symbol}`,
|
||||
}}
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, accountDebt)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Total Borrowed
|
||||
</Text>
|
||||
</div>
|
||||
<div className='h-100 w-[1px] bg-white/10' />
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<div className='flex gap-2'>
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
amount={modal.data?.liquidity.toNumber() ?? 0}
|
||||
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
|
||||
animate
|
||||
/>
|
||||
<DisplayCurrency
|
||||
className='text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(asset.denom, modal.data?.liquidity ?? BN_ZERO)}
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
Liquidity available
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-start flex-1 gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-1 p-4 bg-white/5'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={asset}
|
||||
onChange={handleChange}
|
||||
onDebounce={onDebounce}
|
||||
amount={amount}
|
||||
max={max}
|
||||
disabled={max.isZero()}
|
||||
className='w-full'
|
||||
maxText='Max'
|
||||
warningMessages={[]}
|
||||
/>
|
||||
<Divider />
|
||||
{maxRepayAmount.isZero() && <RepayNotAvailable asset={asset} />}
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
className='w-full'
|
||||
disabled={amount.isZero()}
|
||||
text={`Repay ${asset.symbol}`}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
import Borrow from 'components/Modals/v1/Borrow'
|
||||
import Repay from 'components/Modals/v1/Repay'
|
||||
|
||||
export default function V1BorrowAndRepayModal() {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
const modal = useStore<V1BorrowAndRepayModal | null>((s) => s.v1BorrowAndRepayModal)
|
||||
const isBorrow = modal?.type === 'borrow'
|
||||
|
||||
if (!modal || !account) return null
|
||||
if (isBorrow) return <Borrow account={account} />
|
||||
return <Repay account={account} />
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useStore from 'store'
|
||||
import Deposit from 'components/Modals/v1/Deposit'
|
||||
import Withdraw from 'components/Modals/v1/Withdraw'
|
||||
|
||||
export default function V1DepositAndWithdraw() {
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: account } = useAccount(address)
|
||||
const modal = useStore<V1DepositAndWithdrawModal | null>((s) => s.v1DepositAndWithdrawModal)
|
||||
const isDeposit = modal?.type === 'deposit'
|
||||
|
||||
if (!modal || !account) return null
|
||||
if (isDeposit) return <Deposit account={account} />
|
||||
return <Withdraw account={account} />
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function Withdraw(props: Props) {
|
||||
const { account } = props
|
||||
const baseAsset = useBaseAsset()
|
||||
const modal = useStore((s) => s.v1DepositAndWithdrawModal)
|
||||
const asset = modal?.data.asset ?? baseAsset
|
||||
const [withdrawAsset, setWithdrawAsset] = useState<BNCoin>(
|
||||
BNCoin.fromDenomAndBigNumber(modal?.data.asset.denom ?? baseAsset.denom, BN_ZERO),
|
||||
)
|
||||
const { computeMaxWithdrawAmount } = useHealthComputer(account)
|
||||
const maxWithdrawAmount = computeMaxWithdrawAmount(asset.denom)
|
||||
const { simulateWithdraw } = useUpdatedAccount(account)
|
||||
const balance = BNCoin.fromDenomAndBigNumber(asset.denom, maxWithdrawAmount)
|
||||
const v1Action = useStore((s) => s.v1Action)
|
||||
|
||||
const close = useCallback(() => {
|
||||
useStore.setState({ v1DepositAndWithdrawModal: null })
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
v1Action('withdraw', withdrawAsset)
|
||||
close()
|
||||
}, [v1Action, withdrawAsset, close])
|
||||
|
||||
const onDebounce = useCallback(() => {
|
||||
simulateWithdraw(false, withdrawAsset)
|
||||
}, [withdrawAsset, simulateWithdraw])
|
||||
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setWithdrawAsset(BNCoin.fromDenomAndBigNumber(asset.denom, value))
|
||||
},
|
||||
[asset.denom],
|
||||
)
|
||||
|
||||
if (!modal) return
|
||||
|
||||
return (
|
||||
<AssetAmountSelectActionModal
|
||||
account={account}
|
||||
asset={asset}
|
||||
contentHeader={<DetailsHeader data={modal.data} />}
|
||||
coinBalances={[balance]}
|
||||
actionButtonText={`Withdraw ${asset.symbol}`}
|
||||
title={`Withdraw ${asset.symbol} from the Red Bank`}
|
||||
onClose={close}
|
||||
onAction={handleClick}
|
||||
onChange={handleAmountChange}
|
||||
onDebounce={onDebounce}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import Text from 'components/common/Text'
|
||||
import { TextLink } from 'components/common/TextLink'
|
||||
import { generateToastContent } from 'components/common/Toaster'
|
||||
import useTransactions from 'hooks/localStorage/useTransactions'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useStore from 'store'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
|
||||
export default function RecentTransactions() {
|
||||
const address = useStore((s) => s.address)
|
||||
@@ -47,9 +47,7 @@ export default function RecentTransactions() {
|
||||
key={hash}
|
||||
>
|
||||
<div className='flex items-start justify-between w-full pb-2'>
|
||||
<Text className='flex font-bold'>
|
||||
{accountId === address ? 'Red Bank' : `Credit Account ${accountId}`}
|
||||
</Text>
|
||||
<Text className='flex font-bold'>Credit Account {accountId}</Text>
|
||||
<Text size='sm' className='text-white/70'>
|
||||
{moment.unix(timestamp).format('lll')}
|
||||
</Text>
|
||||
|
||||
@@ -18,7 +18,6 @@ import chains from 'configs/chains'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBaseAsset from 'hooks/assets/useBasetAsset'
|
||||
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useCurrentWallet from 'hooks/useCurrentWallet'
|
||||
import useICNSDomain from 'hooks/useICNSDomain'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
@@ -28,6 +27,7 @@ import { NETWORK } from 'types/enums/network'
|
||||
import { ChainInfoID } from 'types/enums/wallet'
|
||||
import { truncate } from 'utils/formatters'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
|
||||
export default function WalletConnectedButton() {
|
||||
// ---------------
|
||||
@@ -90,7 +90,7 @@ export default function WalletConnectedButton() {
|
||||
})
|
||||
}
|
||||
|
||||
navigate(getRoute(getPage(pathname), new URLSearchParams()))
|
||||
navigate(getRoute(getPage(pathname), searchParams))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -10,7 +10,6 @@ import useChainConfig from 'hooks/useChainConfig'
|
||||
import useCurrentWallet from 'hooks/useCurrentWallet'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getUrl } from 'utils/url'
|
||||
|
||||
interface Props {
|
||||
providerId?: string
|
||||
@@ -54,7 +53,7 @@ export default function WalletConnecting(props: Props) {
|
||||
setIsConnecting(true)
|
||||
try {
|
||||
const response = await connect({ extensionProviderId, chainId: chainConfig.id })
|
||||
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||
const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
|
||||
const walletClient: WalletClient = {
|
||||
broadcast,
|
||||
cosmWasmClient: cosmClient,
|
||||
@@ -138,7 +137,7 @@ export default function WalletConnecting(props: Props) {
|
||||
setIsConnecting(true)
|
||||
try {
|
||||
await mobileConnect({ mobileProviderId, chainId: chainConfig.id })
|
||||
const cosmClient = await CosmWasmClient.connect(getUrl(chainConfig.endpoints.rpc))
|
||||
const cosmClient = await CosmWasmClient.connect(chainConfig.endpoints.rpc)
|
||||
const walletClient: WalletClient = {
|
||||
broadcast,
|
||||
cosmWasmClient: cosmClient,
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function Wallet() {
|
||||
const address = useStore((s) => s.address)
|
||||
|
||||
useEffect(() => {
|
||||
if (address && address === currentWallet?.account.address) return
|
||||
if (address) return
|
||||
useStore.setState({
|
||||
address: undefined,
|
||||
userDomain: undefined,
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
|
||||
const columns = useAccountBalancesColumns(account, showLiquidationPrice)
|
||||
|
||||
if (accountBalanceData.length === 0 && account.id !== address)
|
||||
if (accountBalanceData.length === 0)
|
||||
return (
|
||||
<ConditionalWrapper
|
||||
condition={!hideCard}
|
||||
|
||||
@@ -7,7 +7,7 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
|
||||
@@ -12,19 +12,18 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ThreeDots } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useAccountIds from 'hooks/accounts/useAccountIds'
|
||||
import useAccounts from 'hooks/accounts/useAccounts'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useVaultAprs from 'hooks/vaults/useVaultAprs'
|
||||
import useStore from 'store'
|
||||
@@ -34,40 +33,33 @@ import {
|
||||
calculateAccountBalanceValue,
|
||||
calculateAccountLeverage,
|
||||
} from 'utils/accounts'
|
||||
import { getPage } from 'utils/route'
|
||||
|
||||
export default function AccountDetailsController() {
|
||||
const address = useStore((s) => s.address)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const isV1 = useStore((s) => s.isV1)
|
||||
const { data: _, isLoading } = useAccounts('default', address)
|
||||
const { data: accountIds } = useAccountIds(address, false, true)
|
||||
|
||||
const accountId = useAccountId()
|
||||
const currentAccount = useCurrentAccount()
|
||||
const { data: v1Account } = useAccount(address)
|
||||
const { pathname } = useLocation()
|
||||
const page = getPage(pathname)
|
||||
|
||||
const account = isV1 && page !== 'trade' ? v1Account : currentAccount
|
||||
const account = useCurrentAccount()
|
||||
const focusComponent = useStore((s) => s.focusComponent)
|
||||
const isOwnAccount = (accountId && accountIds?.includes(accountId)) || account?.id === address
|
||||
const hideAccountDetails =
|
||||
!address || focusComponent || !isOwnAccount || isHLS || page.includes('portfolio')
|
||||
const isLoadingAccountDetails = (isLoading && accountId && !focusComponent) || !account
|
||||
const isOwnAccount = accountId && accountIds?.includes(accountId)
|
||||
|
||||
if (hideAccountDetails) return null
|
||||
if (isLoadingAccountDetails) return <Skeleton />
|
||||
if (!address || focusComponent || !isOwnAccount || isHLS) return null
|
||||
|
||||
return <AccountDetails account={account} page={page} />
|
||||
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
||||
|
||||
return <AccountDetails account={account} />
|
||||
}
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
page: Page
|
||||
}
|
||||
|
||||
function AccountDetails(props: Props) {
|
||||
const { account, page } = props
|
||||
const { account } = props
|
||||
const location = useLocation()
|
||||
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||
const { data: vaultAprs } = useVaultAprs()
|
||||
const [reduceMotion] = useLocalStorage<boolean>(
|
||||
@@ -132,7 +124,10 @@ function AccountDetails(props: Props) {
|
||||
vaultAprs,
|
||||
],
|
||||
)
|
||||
const isFullWidth = page === 'trade' || page === 'perps'
|
||||
const isFullWidth =
|
||||
location.pathname.includes('trade') ||
|
||||
location.pathname === '/' ||
|
||||
location.pathname.includes('perps')
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,7 +6,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
|
||||
import Button from 'components/common/Button'
|
||||
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/common/Icons'
|
||||
import SwitchAutoLend from 'components/common/Switch/SwitchAutoLend'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
|
||||
@@ -42,7 +42,6 @@ export default function AccountSummaryHeader(props: Props) {
|
||||
updatedHealthFactor,
|
||||
isAccountDetails,
|
||||
} = props
|
||||
const address = useStore((s) => s.address)
|
||||
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
||||
const accountBalance = useMemo(
|
||||
() => (account ? calculateAccountBalanceValue(account, prices, assets) : BN_ZERO),
|
||||
@@ -69,9 +68,10 @@ export default function AccountSummaryHeader(props: Props) {
|
||||
/>
|
||||
)}
|
||||
{isAccountDetails && (
|
||||
<Text size='sm' className='w-full pb-1 text-white/50'>
|
||||
{account.id === address ? 'Red Bank' : `Credit Account ${account.id}`}
|
||||
</Text>
|
||||
<Text
|
||||
size='sm'
|
||||
className='w-full pb-1 text-white/50'
|
||||
>{`Credit Account ${account.id}`}</Text>
|
||||
)}
|
||||
<div className='flex items-end w-full gap-2 pb-2 border-b border-white/5'>
|
||||
<DisplayCurrency
|
||||
|
||||
@@ -7,7 +7,7 @@ import AccountStrategiesTable from 'components/account/AccountStrategiesTable'
|
||||
import AccountSummaryHeader from 'components/account/AccountSummary/AccountSummaryHeader'
|
||||
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
|
||||
import Accordion from 'components/common/Accordion'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
@@ -63,22 +63,16 @@ export default function HealthBar({
|
||||
health={isUpdated ? updatedHealth : health}
|
||||
healthFactor={isUpdated ? updatedHealthFactor : healthFactor}
|
||||
>
|
||||
<div className={classNames('flex w-full', showIcon && 'gap-2')}>
|
||||
<>
|
||||
{showIcon && (
|
||||
<HealthIcon
|
||||
health={health}
|
||||
isLoading={healthFactor === 0}
|
||||
className={iconClassName}
|
||||
className={classNames('mr-2', iconClassName)}
|
||||
colorClass='text-white'
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={classNames(
|
||||
'flex w-full flex-shrink',
|
||||
'rounded-full overflow-hidden',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className={classNames('flex w-full', 'rounded-full overflow-hidden', className)}>
|
||||
<svg
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
@@ -159,7 +153,7 @@ export default function HealthBar({
|
||||
)}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</HealthTooltip>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ExclamationMarkCircled, Heart } from 'components/common/Icons'
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
health: number
|
||||
className?: string
|
||||
className: string
|
||||
colorClass?: string
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ export default function HealthIcon(props: Props) {
|
||||
const color = colorClass ?? 'text-white'
|
||||
|
||||
return (
|
||||
<div className='w-5'>
|
||||
<>
|
||||
{!isLoading && health === 0 ? (
|
||||
<ExclamationMarkCircled className={classNames(' text-loss animate-pulse', className)} />
|
||||
<ExclamationMarkCircled className={classNames('w-5 text-loss animate-pulse', className)} />
|
||||
) : (
|
||||
<Heart
|
||||
className={classNames(
|
||||
@@ -26,6 +26,6 @@ export default function HealthIcon(props: Props) {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import Button from 'components/common/Button'
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { HandCoins, Plus } from 'components/common/Icons'
|
||||
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function BorrowActionButtons(props: Props) {
|
||||
const { asset, accountDebt } = props.data
|
||||
const marketAssets = useMarketEnabledAssets()
|
||||
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
|
||||
|
||||
const borrowHandler = useCallback(() => {
|
||||
if (!currentAsset) return null
|
||||
useStore.setState({ borrowModal: { asset: currentAsset, marketData: props.data } })
|
||||
}, [currentAsset, props.data])
|
||||
|
||||
const repayHandler = useCallback(() => {
|
||||
if (!currentAsset) return null
|
||||
useStore.setState({
|
||||
borrowModal: { asset: currentAsset, marketData: props.data, isRepay: true },
|
||||
})
|
||||
}, [currentAsset, props.data])
|
||||
|
||||
return (
|
||||
<div className='flex flex-row space-x-2'>
|
||||
<ActionButton
|
||||
leftIcon={<Plus className='w-3' />}
|
||||
onClick={borrowHandler}
|
||||
color='secondary'
|
||||
text={accountDebt ? 'Borrow more' : 'Borrow'}
|
||||
className='text-center min-w-40'
|
||||
/>
|
||||
{accountDebt && (
|
||||
<Button color='tertiary' leftIcon={<HandCoins />} text='Repay' onClick={repayHandler} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
import ActiveBorrowingsTable from 'components/borrow/Table/ActiveBorrowingsTable'
|
||||
import AvailableBorrowingsTable from 'components/borrow/Table/AvailableBorrowingsTable'
|
||||
import DepositedBorrowingsTable from 'components/borrow/Table/DepositedBorrowingsTable'
|
||||
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
|
||||
|
||||
export default function Borrowings() {
|
||||
const { accountBorrowedAssets, availableAssets, allAssets } = useBorrowMarketAssetsTableData()
|
||||
const data = useBorrowMarketAssetsTableData()
|
||||
|
||||
if (!allAssets?.length) {
|
||||
if (!data?.allAssets?.length) {
|
||||
return <Fallback />
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ActiveBorrowingsTable data={accountBorrowedAssets} isLoading={false} />
|
||||
<AvailableBorrowingsTable data={availableAssets} isLoading={false} />
|
||||
<DepositedBorrowingsTable data={data.accountBorrowedAssets} isLoading={false} />
|
||||
<AvailableBorrowingsTable data={data.availableAssets} isLoading={false} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { DEBT_VALUE_META } from 'components/borrow/Table/Columns/DebtValue'
|
||||
import { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import useBorrowingsColumns from 'components/borrow/Table/Columns/useActiveColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
|
||||
type Props = {
|
||||
data: BorrowMarketTableData[]
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function ActiveBorrowingsTable(props: Props) {
|
||||
const columns = useBorrowingsColumns({ v1: props.v1 })
|
||||
|
||||
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
|
||||
return <MarketDetails row={row} type='borrow' />
|
||||
}, [])
|
||||
|
||||
if (!props.data.length) return null
|
||||
|
||||
return (
|
||||
<Table
|
||||
title={props.v1 ? 'Borrowings' : 'Borrowed Assets'}
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={
|
||||
props.v1
|
||||
? [
|
||||
{ id: DEBT_VALUE_META.id, desc: true },
|
||||
{ id: NAME_META.id, desc: false },
|
||||
]
|
||||
: [{ id: NAME_META.id, desc: false }]
|
||||
}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -2,10 +2,12 @@ import { Row } from '@tanstack/react-table'
|
||||
import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import BorrowActionButtons from 'components/borrow/BorrowActionButtons'
|
||||
import { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import useAvailableColumns from 'components/borrow/Table/Columns/useAvailableColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
|
||||
|
||||
type Props = {
|
||||
data: BorrowMarketTableData[]
|
||||
@@ -18,7 +20,14 @@ export default function AvailableBorrowingsTable(props: Props) {
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<BorrowMarketTableData>, _: TanstackTable<BorrowMarketTableData>) => {
|
||||
const currentRow = row as Row<BorrowMarketTableData>
|
||||
return <MarketDetails row={currentRow} type='borrow' />
|
||||
return (
|
||||
<>
|
||||
<ActionButtonRow row={currentRow}>
|
||||
<BorrowActionButtons data={row.original} />
|
||||
</ActionButtonRow>
|
||||
<MarketDetails row={currentRow} type='borrow' />
|
||||
</>
|
||||
)
|
||||
},
|
||||
[],
|
||||
)
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { Plus } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useStore from 'store'
|
||||
|
||||
export const BORROW_BUTTON_META = {
|
||||
accessorKey: 'borrow',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
export default function BorrowButton(props: Props) {
|
||||
const account = useCurrentAccount()
|
||||
const address = useStore((s) => s.address)
|
||||
const hasNoDeposits = !account?.deposits?.length && !account?.lends?.length && !!address
|
||||
|
||||
const borrowHandler = useCallback(() => {
|
||||
if (!props.data.asset) return null
|
||||
useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } })
|
||||
}, [props.data])
|
||||
|
||||
return (
|
||||
<div className='flex justify-end'>
|
||||
<ConditionalWrapper
|
||||
condition={hasNoDeposits}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have any collateral.
|
||||
Please first deposit into your Credit Account before borrowing.`}</Text>
|
||||
}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<Plus />}
|
||||
disabled={hasNoDeposits}
|
||||
color='tertiary'
|
||||
onClick={(e) => {
|
||||
borrowHandler()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
text='Borrow'
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import Loading from 'components/common/Loading'
|
||||
export const BORROW_RATE_META = {
|
||||
accessorKey: 'apy.borrow',
|
||||
header: 'Borrow Rate APY',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { ChevronDown, ChevronUp } from 'components/common/Icons'
|
||||
|
||||
export const CHEVRON_META = {
|
||||
id: 'chevron',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
meta: {
|
||||
className: 'w-5',
|
||||
},
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isExpanded: boolean
|
||||
}
|
||||
export default function Chevron(props: Props) {
|
||||
return (
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
|
||||
import AmountAndValue from 'components/common/AmountAndValue'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export const DEBT_META = {
|
||||
accessorKey: 'debt',
|
||||
header: 'Debt',
|
||||
}
|
||||
|
||||
export const debtSortingFn = (
|
||||
a: Row<BorrowMarketTableData>,
|
||||
b: Row<BorrowMarketTableData>,
|
||||
): number => {
|
||||
const assetA = a.original.asset
|
||||
const assetB = b.original.asset
|
||||
if (!a.original.accountDebt || !b.original.accountDebt) return 0
|
||||
const debtA = a.original.accountDebt.shiftedBy(-assetA.decimals)
|
||||
const debtB = b.original.accountDebt.shiftedBy(-assetB.decimals)
|
||||
return debtA.minus(debtB).toNumber()
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
}
|
||||
|
||||
export default function Debt(props: Props) {
|
||||
const marketAssets = useMarketEnabledAssets()
|
||||
const asset = marketAssets.find(byDenom(props.data.asset.denom))
|
||||
|
||||
if (!asset) return null
|
||||
|
||||
return <AmountAndValue asset={asset} amount={props.data?.accountDebt ?? BN_ZERO} />
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
|
||||
import AmountAndValue from 'components/common/AmountAndValue'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const DEBT_VALUE_META = {
|
||||
id: 'accountDebtValue',
|
||||
accessorKey: 'accountDebtValue',
|
||||
header: 'Debt',
|
||||
}
|
||||
|
||||
export const debtSortingFn = (
|
||||
a: Row<BorrowMarketTableData>,
|
||||
b: Row<BorrowMarketTableData>,
|
||||
): number => {
|
||||
const debtValueA = BN(a.original?.accountDebtValue ?? 0)
|
||||
const debtValueB = BN(b.original?.accountDebtValue ?? 0)
|
||||
return debtValueA.minus(debtValueB).toNumber()
|
||||
}
|
||||
|
||||
interface Props {
|
||||
asset: Asset
|
||||
debtAmount?: BigNumber
|
||||
}
|
||||
export default function DebtValue(props: Props) {
|
||||
return (
|
||||
<AmountAndValue asset={props.asset} amount={props.debtAmount ? props.debtAmount : BN_ZERO} />
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ export const LIQUIDITY_META = {
|
||||
accessorKey: 'liquidity',
|
||||
header: 'Liquidity Available',
|
||||
id: 'liquidity',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
export const liquiditySortingFn = (
|
||||
|
||||
@@ -1,55 +1,20 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { HandCoins, Plus } from 'components/common/Icons'
|
||||
import useStore from 'store'
|
||||
import { ChevronDown, ChevronUp } from 'components/common/Icons'
|
||||
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
header: 'Manage',
|
||||
meta: { className: 'w-30' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: BorrowMarketTableData
|
||||
isExpanded: boolean
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const address = useStore((s) => s.address)
|
||||
|
||||
const borrowHandler = useCallback(() => {
|
||||
if (!props.data.asset) return null
|
||||
useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } })
|
||||
}, [props.data])
|
||||
|
||||
const repayHandler = useCallback(() => {
|
||||
if (!props.data.asset) return null
|
||||
useStore.setState({
|
||||
borrowModal: { asset: props.data.asset, marketData: props.data, isRepay: true },
|
||||
})
|
||||
}, [props.data])
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <Plus />,
|
||||
text: 'Borrow more',
|
||||
onClick: borrowHandler,
|
||||
},
|
||||
{
|
||||
icon: <HandCoins />,
|
||||
text: 'Repay',
|
||||
onClick: repayHandler,
|
||||
},
|
||||
],
|
||||
[borrowHandler, repayHandler],
|
||||
)
|
||||
|
||||
if (!address) return null
|
||||
|
||||
return (
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import BorrowButton, { BORROW_BUTTON_META } from 'components/borrow/Table/Columns/BorrowButton'
|
||||
import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate'
|
||||
import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
|
||||
import Liquidity, {
|
||||
LIQUIDITY_META,
|
||||
liquiditySortingFn,
|
||||
} from 'components/borrow/Table/Columns/Liquidity'
|
||||
import Manage, { MANAGE_META } from 'components/borrow/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
|
||||
export default function useAvailableColumns() {
|
||||
@@ -27,12 +26,8 @@ export default function useAvailableColumns() {
|
||||
sortingFn: liquiditySortingFn,
|
||||
},
|
||||
{
|
||||
...BORROW_BUTTON_META,
|
||||
cell: ({ row }) => <BorrowButton data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
|
||||
+6
-22
@@ -2,24 +2,15 @@ import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate'
|
||||
import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron'
|
||||
import DebtValue, {
|
||||
DEBT_VALUE_META,
|
||||
debtSortingFn,
|
||||
} from 'components/borrow/Table/Columns/DebtValue'
|
||||
import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt'
|
||||
import Liquidity, {
|
||||
LIQUIDITY_META,
|
||||
liquiditySortingFn,
|
||||
} from 'components/borrow/Table/Columns/Liquidity'
|
||||
import Manage, { MANAGE_META } from 'components/borrow/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import Action from 'components/v1/Table/borrowings/Columns/Action'
|
||||
|
||||
interface Props {
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function useActiveColumns(props: Props) {
|
||||
export default function useDepositedColumns() {
|
||||
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
||||
return [
|
||||
{
|
||||
@@ -27,10 +18,8 @@ export default function useActiveColumns(props: Props) {
|
||||
cell: ({ row }) => <Name data={row.original} />,
|
||||
},
|
||||
{
|
||||
...DEBT_VALUE_META,
|
||||
cell: ({ row }) => (
|
||||
<DebtValue asset={row.original.asset} debtAmount={row.original.accountDebtAmount} />
|
||||
),
|
||||
...DEBT_META,
|
||||
cell: ({ row }) => <Debt data={row.original} />,
|
||||
sortingFn: debtSortingFn,
|
||||
},
|
||||
{
|
||||
@@ -44,13 +33,8 @@ export default function useActiveColumns(props: Props) {
|
||||
},
|
||||
{
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) =>
|
||||
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [props.v1])
|
||||
}, [])
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import BorrowActionButtons from 'components/borrow/BorrowActionButtons'
|
||||
import { NAME_META } from 'components/borrow/Table/Columns/Name'
|
||||
import useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
|
||||
|
||||
type Props = {
|
||||
data: BorrowMarketTableData[]
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export default function DepositedBorrowingsTable(props: Props) {
|
||||
const columns = useDepositedColumns()
|
||||
|
||||
const renderExpanded = useCallback((row: Row<BorrowMarketTableData>) => {
|
||||
const currentRow = row as Row<BorrowMarketTableData>
|
||||
return (
|
||||
<>
|
||||
<ActionButtonRow row={currentRow}>
|
||||
<BorrowActionButtons data={row.original} />
|
||||
</ActionButtonRow>
|
||||
<MarketDetails row={row} type='borrow' />
|
||||
</>
|
||||
)
|
||||
}, [])
|
||||
|
||||
if (!props.data.length) return null
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Borrowed Assets'
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||
|
||||
export default function useBorrowMarketAssetsTableData() {
|
||||
const account = useCurrentAccount()
|
||||
const markets = useMarkets()
|
||||
const { convertAmount } = useDisplayCurrencyPrice()
|
||||
|
||||
return useMemo((): {
|
||||
accountBorrowedAssets: BorrowMarketTableData[]
|
||||
@@ -21,21 +18,15 @@ export default function useBorrowMarketAssetsTableData() {
|
||||
markets
|
||||
.filter((market) => market.borrowEnabled)
|
||||
.forEach((market) => {
|
||||
const amount =
|
||||
account?.debts?.find((debt) => debt.denom === market.asset.denom)?.amount ?? BN_ZERO
|
||||
const value = amount ? convertAmount(market.asset, amount) : undefined
|
||||
const debt = account?.debts?.find((debt) => debt.denom === market.asset.denom)
|
||||
|
||||
const borrowMarketAsset: BorrowMarketTableData = {
|
||||
...market,
|
||||
accountDebtAmount: amount,
|
||||
accountDebtValue: value,
|
||||
}
|
||||
|
||||
if (borrowMarketAsset.accountDebtAmount?.isZero()) {
|
||||
availableAssets.push(borrowMarketAsset)
|
||||
} else {
|
||||
accountBorrowedAssets.push(borrowMarketAsset)
|
||||
accountDebt: debt?.amount,
|
||||
}
|
||||
;(borrowMarketAsset.accountDebt ? accountBorrowedAssets : availableAssets).push(
|
||||
borrowMarketAsset,
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
@@ -43,5 +34,5 @@ export default function useBorrowMarketAssetsTableData() {
|
||||
availableAssets,
|
||||
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
||||
}
|
||||
}, [account?.debts, markets, convertAmount])
|
||||
}, [account?.debts, markets])
|
||||
}
|
||||
|
||||
@@ -15,28 +15,19 @@ export default function Background() {
|
||||
)
|
||||
const { pathname } = useLocation()
|
||||
const page = getPage(pathname)
|
||||
const [isHLS] = useMemo(() => [page.split('-')[0] === 'hls'], [page])
|
||||
const isHLS = useMemo(() => page.split('-')[0] === 'hls', [page])
|
||||
|
||||
useEffect(() => {
|
||||
useStore.setState({ isHLS: isHLS })
|
||||
useStore.setState({ 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 (
|
||||
<div
|
||||
className={classNames(
|
||||
'fixed inset-0',
|
||||
'w-full h-full',
|
||||
'overflow-hidden pointer-events-none background ',
|
||||
bodyClassName,
|
||||
isHLS ? 'bg-body-hls' : 'bg-body',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
)}
|
||||
>
|
||||
@@ -48,7 +39,7 @@ export default function Background() {
|
||||
'max-h-[500px] max-w-[500px]',
|
||||
'left-[-10vw] top-[-10vw]',
|
||||
'blur-orb-primary',
|
||||
primaryOrbClassName,
|
||||
isHLS ? ' bg-orb-primary-hls' : 'bg-orb-primary',
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
!reduceMotion && 'animate-[float_120s_ease-in-out_infinite_2s]',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
@@ -62,7 +53,7 @@ export default function Background() {
|
||||
'max-h-[1000px] max-w-[1000px]',
|
||||
'bottom-[-20vw] right-[-10vw]',
|
||||
'blur-orb-secondary',
|
||||
secondaryOrbClassName,
|
||||
isHLS ? ' bg-orb-secondary-hls' : 'bg-orb-secondary',
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-30',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
)}
|
||||
@@ -75,7 +66,7 @@ export default function Background() {
|
||||
'max-h-[600px] max-w-[600px]',
|
||||
'right-[-4vw] top-[-10vw]',
|
||||
'blur-orb-tertiary ',
|
||||
tertiaryOrbClassName,
|
||||
isHLS ? ' bg-orb-tertiary-hls' : 'bg-orb-tertiary',
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
!reduceMotion && 'animate-[float_180s_ease-in_infinite]',
|
||||
!reduceMotion && 'transition-bg duration-1000 delay-300',
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Button from 'components/common/Button/index'
|
||||
import { ChevronDown } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
|
||||
interface Props extends ButtonProps {
|
||||
items: DropDownItem[]
|
||||
text: string
|
||||
showProgressIndicator?: boolean
|
||||
}
|
||||
|
||||
export default function DropDownButton(props: Props) {
|
||||
@@ -20,20 +16,16 @@ export default function DropDownButton(props: Props) {
|
||||
content={<DropDown closeMenu={() => toggleIsOpen(false)} {...props} />}
|
||||
type='info'
|
||||
placement='bottom'
|
||||
contentClassName='!bg-white/10 backdrop-blur-xl !p-0 w-full min-w-[140px]'
|
||||
contentClassName='!bg-white/10 backdrop-blur-xl !p-0'
|
||||
interactive
|
||||
hideArrow
|
||||
visible={isOpen}
|
||||
onClickOutside={() => toggleIsOpen(false)}
|
||||
>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
toggleIsOpen()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
onClick={() => toggleIsOpen()}
|
||||
rightIcon={<ChevronDown />}
|
||||
iconClassName='w-3 h-3'
|
||||
showProgressIndicator={props.showProgressIndicator}
|
||||
{...props}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -47,7 +39,7 @@ interface DropDownProps {
|
||||
|
||||
function DropDown(props: DropDownProps) {
|
||||
return (
|
||||
<div className='w-full'>
|
||||
<div>
|
||||
{props.items.map((item) => (
|
||||
<DropDownItem key={item.text} item={item} closeMenu={props.closeMenu} />
|
||||
))}
|
||||
@@ -62,38 +54,15 @@ interface DropDownItemProps {
|
||||
|
||||
function DropDownItem(props: DropDownItemProps) {
|
||||
return (
|
||||
<ConditionalWrapper
|
||||
condition={!!props.item.disabled}
|
||||
wrapper={(children) => {
|
||||
if (!props.item.disabledTooltip) return children
|
||||
return (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={<Text size='sm'>{props.item.disabledTooltip}</Text>}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)
|
||||
<button
|
||||
onClick={() => {
|
||||
props.item.onClick()
|
||||
props.closeMenu()
|
||||
}}
|
||||
className=' px-4 py-3 flex gap-2 items-center hover:bg-white/5 w-full [&:not(:last-child)]:border-b border-white/10'
|
||||
>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
props.item.onClick()
|
||||
props.closeMenu()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
className={classNames(
|
||||
'z-1 px-4 py-3 flex gap-2 items-center w-full [&:not(:last-child)]:border-b border-white/10',
|
||||
props.item.disabled ? 'bg-black/20 text-white/40 cursor-events-none' : 'hover:bg-white/5',
|
||||
)}
|
||||
disabled={props.item.disabled}
|
||||
>
|
||||
<div className='flex justify-center w-4 h-4'>{props.item.icon}</div>
|
||||
<Text size='sm'>{props.item.text}</Text>
|
||||
</button>
|
||||
</ConditionalWrapper>
|
||||
<div className='flex justify-center w-5 h-5'>{props.item.icon}</div>
|
||||
<Text size='sm'>{props.item.text}</Text>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ export default function DepositCapMessage(props: Props) {
|
||||
|
||||
return (
|
||||
<div className={classNames('flex items-start', props.className)}>
|
||||
{props.showIcon && (
|
||||
<div className='w-6 mr-5'>
|
||||
<InfoCircle />
|
||||
</div>
|
||||
)}
|
||||
{props.showIcon && <InfoCircle width={26} className='mr-5' />}
|
||||
<div className='flex flex-col gap-2'>
|
||||
<Text size='sm'>Deposit Cap Reached!</Text>
|
||||
<Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
GridPlanet,
|
||||
GridTire,
|
||||
GridWeb,
|
||||
Wallet,
|
||||
} from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
@@ -18,7 +17,7 @@ import useStore from 'store'
|
||||
interface Props {
|
||||
text: string | ReactNode
|
||||
children?: ReactNode
|
||||
bg: Page
|
||||
bg: 'borrow' | 'lend' | 'farm' | 'portfolio' | 'hls-farm' | 'hls-staking'
|
||||
}
|
||||
|
||||
function IntroBackground(props: { bg: Props['bg'] }) {
|
||||
@@ -53,12 +52,6 @@ function IntroBackground(props: { bg: Props['bg'] }) {
|
||||
<GridPlanet />
|
||||
</div>
|
||||
)
|
||||
case 'v1':
|
||||
return (
|
||||
<div className='absolute top-0 right-0 block w-80 opacity-5'>
|
||||
<Wallet />
|
||||
</div>
|
||||
)
|
||||
default:
|
||||
return (
|
||||
<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,
|
||||
} = useDisplayCurrencyPrice()
|
||||
|
||||
const { asset, ltv, deposits, debt } = row.original
|
||||
const { asset, ltv, cap, liquidity, deposits, debt } = row.original
|
||||
|
||||
const details: Detail[] = useMemo(() => {
|
||||
const isDollar = displayCurrencySymbol === '$'
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import Card from 'components/common/Card'
|
||||
import { Cross, ExclamationMarkCircled } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { TextLink } from 'components/common/TextLink'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useStore from 'store'
|
||||
import { DocURL } from 'types/enums/docURL'
|
||||
|
||||
export default function MigrationBanner() {
|
||||
const [_, setMigrationBanner] = useLocalStorage<boolean>(
|
||||
LocalStorageKeys.MIGRATION_BANNER,
|
||||
DEFAULT_SETTINGS.migrationBanner,
|
||||
)
|
||||
|
||||
const showMigrationBanner = useStore((s) => s.migrationBanner)
|
||||
|
||||
if (!showMigrationBanner) return null
|
||||
return (
|
||||
<Card
|
||||
className='relative w-full bg-info-bg/20 text-info'
|
||||
contentClassName='flex w-full gap-2 px-4 py-3 items-center'
|
||||
>
|
||||
<div className='flex w-6 h-6 p-1 text-white rounded bg-info'>
|
||||
<ExclamationMarkCircled />
|
||||
</div>
|
||||
<Text className='flex flex-grow' size='sm'>
|
||||
If you have funds on{' '}
|
||||
<TextLink
|
||||
href={DocURL.V1_URL}
|
||||
externalLink
|
||||
className='mx-1 text-white no-underline hover:underline'
|
||||
>
|
||||
Mars v1,
|
||||
</TextLink>
|
||||
please withdraw them and deposit them on Mars v2 to migrate.
|
||||
</Text>
|
||||
<div
|
||||
className='absolute right-0 flex items-center h-full px-4 w-11 opacity-80 hover:cursor-pointer hover:opacity-100'
|
||||
onClick={() => setMigrationBanner(false)}
|
||||
>
|
||||
<Cross className='w-3 h-3' />
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -12,12 +12,11 @@ interface Props {
|
||||
className?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
placement?: 'top' | 'bottom' | 'left' | 'right'
|
||||
}
|
||||
|
||||
export default function SwitchWithLabel(props: Props) {
|
||||
return (
|
||||
<div className={classNames('flex w-full items-center ', props.className)}>
|
||||
<div className={classNames('flex w-full', props.className)}>
|
||||
<div className='flex flex-1'>
|
||||
<Text className='mr-2 text-white/70' size='sm'>
|
||||
{props.label}
|
||||
@@ -25,9 +24,8 @@ export default function SwitchWithLabel(props: Props) {
|
||||
{props.tooltip && (
|
||||
<Tooltip
|
||||
type='info'
|
||||
placement={props.placement ?? 'top'}
|
||||
content={
|
||||
<Text size='sm' className='px-2 py-3 max-w-[320px]'>
|
||||
<Text size='sm' className='px-2 py-3'>
|
||||
{props.tooltip}
|
||||
</Text>
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
import classNames from 'classnames'
|
||||
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import SwitchWithLabel from 'components/common/Switch/SwitchWithLabel'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useStore from 'store'
|
||||
import { getRoute } from 'utils/route'
|
||||
|
||||
const underlineClasses =
|
||||
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
|
||||
|
||||
interface Props {
|
||||
tabs: Tab[]
|
||||
activeTabIdx: number
|
||||
showV1Toggle?: boolean
|
||||
}
|
||||
|
||||
export default function Tab(props: Props) {
|
||||
const accountId = useAccountId()
|
||||
const { address } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const chainConfig = useChainConfig()
|
||||
const isV1 = useStore((s) => s.isV1)
|
||||
|
||||
const filteredTabs = useMemo(
|
||||
() =>
|
||||
props.tabs.map((tab) => (tab.name === 'Farm' && (!chainConfig.farm || isV1) ? null : tab)),
|
||||
[chainConfig, props.tabs, isV1],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='relative flex w-full'>
|
||||
<div className='flex flex-grow'>
|
||||
{filteredTabs.map((tab, index) =>
|
||||
tab ? (
|
||||
<NavLink
|
||||
key={tab.page}
|
||||
to={getRoute(tab.page, searchParams, address, accountId)}
|
||||
className={classNames(
|
||||
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
|
||||
'relative mr-8 text-xl ',
|
||||
)}
|
||||
>
|
||||
{tab.name}
|
||||
</NavLink>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
{props.showV1Toggle && (
|
||||
<div className='flex items-center w-40 h-full'>
|
||||
<SwitchWithLabel
|
||||
name='v1-toggle'
|
||||
label='Wallet Mode'
|
||||
value={isV1}
|
||||
onChange={() => useStore.setState({ isV1: !isV1 })}
|
||||
tooltip='The Wallet Mode allows you to interact with the Red Bank without the use of a Credit Account. Funds will be deposited and borrowed directly from and to your Wallet. However you will not be able to use the deposited funds for trading or farming.'
|
||||
placement='bottom'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,7 +10,6 @@ interface Props<T> {
|
||||
className?: string
|
||||
isSelectable?: boolean
|
||||
type?: TableType
|
||||
onClick?: (id: string) => void
|
||||
}
|
||||
|
||||
function getBorderColor(
|
||||
@@ -37,7 +36,7 @@ export default function Row<T>(props: Props<T>) {
|
||||
key={`${row.id}-row`}
|
||||
className={classNames(
|
||||
'group/row transition-bg',
|
||||
(renderExpanded || isSelectable || props.onClick) && 'hover:cursor-pointer',
|
||||
(renderExpanded || isSelectable) && 'hover:cursor-pointer',
|
||||
canExpand && row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
@@ -50,10 +49,6 @@ export default function Row<T>(props: Props<T>) {
|
||||
table.resetExpanded()
|
||||
!isExpanded && row.toggleExpanded()
|
||||
}
|
||||
|
||||
if (props.onClick) {
|
||||
props.onClick((row.original as any).asset.denom)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => {
|
||||
@@ -66,7 +61,7 @@ export default function Row<T>(props: Props<T>) {
|
||||
spacingClassName ?? 'px-3 py-4',
|
||||
type && type !== 'strategies' && isSymbolOrName && 'border-l',
|
||||
type && type !== 'strategies' && getBorderColor(type, cell.row.original as any),
|
||||
cell.column.columnDef.meta?.className ?? 'w-min',
|
||||
cell.column.columnDef.meta?.className,
|
||||
)}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
|
||||
@@ -31,7 +31,6 @@ interface Props<T> {
|
||||
hideCard?: boolean
|
||||
setRowSelection?: OnChangeFn<RowSelectionState>
|
||||
selectedRows?: RowSelectionState
|
||||
onClickRow?: (id: string) => void
|
||||
}
|
||||
|
||||
export default function Table<T>(props: Props<T>) {
|
||||
@@ -76,7 +75,6 @@ export default function Table<T>(props: Props<T>) {
|
||||
props.spacingClassName ?? 'px-4 py-3',
|
||||
header.column.getCanSort() && 'hover:cursor-pointer',
|
||||
header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right',
|
||||
'w-min',
|
||||
header.column.columnDef.meta?.className,
|
||||
)}
|
||||
>
|
||||
@@ -124,7 +122,6 @@ export default function Table<T>(props: Props<T>) {
|
||||
spacingClassName={props.spacingClassName}
|
||||
isSelectable={!!props.setRowSelection}
|
||||
type={props.type}
|
||||
onClick={props.onClickRow}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
@@ -11,11 +11,11 @@ import { TextLink } from 'components/common/TextLink'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useTransactionStore from 'hooks/useTransactionStore'
|
||||
import useStore from 'store'
|
||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
|
||||
const toastBodyClasses = classNames(
|
||||
'flex flex-wrap w-full group/transaction',
|
||||
@@ -99,13 +99,6 @@ export default function Toaster() {
|
||||
if (!isError && toast.accountId) addTransaction(toast)
|
||||
const generalMessage = isError ? 'Transaction failed!' : 'Transaction completed successfully!'
|
||||
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 = () => (
|
||||
<div className='relative flex flex-wrap w-full m-0 isolate'>
|
||||
<div className='flex w-full gap-2 mb-2'>
|
||||
@@ -148,7 +141,7 @@ export default function Toaster() {
|
||||
)}
|
||||
>
|
||||
{!isError && toast.accountId && (
|
||||
<Text className='mb-1 font-bold text-white'>{target}</Text>
|
||||
<Text className='mb-1 font-bold text-white'>{`Credit Account ${toast.accountId}`}</Text>
|
||||
)}
|
||||
{showDetailElement && toast.message && (
|
||||
<Text size='sm' className='w-full mb-1 text-white'>
|
||||
|
||||
@@ -16,9 +16,9 @@ export default function TooltipContent(props: Props) {
|
||||
<div>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex max-w-[320px] flex-1 gap-2 rounded-base p-3 text-sm shadow-tooltip backdrop-blur-[100px]',
|
||||
'flex max-w-[320px] flex-1 gap-2 rounded-lg p-3 text-sm shadow-tooltip backdrop-blur-[100px]',
|
||||
'relative isolate max-w-full overflow-hidden',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-lg before:p-[1px] before:border-glas',
|
||||
props.type === 'info' && 'bg-white/10',
|
||||
props.type === 'warning' && 'bg-warning',
|
||||
props.type === 'error' && 'bg-error',
|
||||
|
||||
@@ -38,7 +38,7 @@ export const Tooltip = (props: Props) => {
|
||||
placement={props.placement ?? 'top'}
|
||||
render={() => (
|
||||
<TooltipContent
|
||||
hideArrow={props.placement === 'bottom' ? true : props.hideArrow}
|
||||
hideArrow={props.hideArrow}
|
||||
type={props.type}
|
||||
content={props.content}
|
||||
className={props.contentClassName}
|
||||
@@ -48,7 +48,7 @@ export const Tooltip = (props: Props) => {
|
||||
visible={props.visible}
|
||||
>
|
||||
{props.children ? (
|
||||
<div
|
||||
<span
|
||||
className={classNames(
|
||||
props.underline &&
|
||||
'border-b hover:cursor-help border-dashed border-white/20 pb-1 hover:border-transparent',
|
||||
@@ -57,7 +57,7 @@ export const Tooltip = (props: Props) => {
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
className={classNames(
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import classNames from 'classnames'
|
||||
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
|
||||
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import { getRoute } from 'utils/route'
|
||||
|
||||
const underlineClasses =
|
||||
'relative before:absolute before:h-[2px] before:-bottom-1 before:left-0 before:right-0 before:gradient-active-tab'
|
||||
|
||||
interface Props {
|
||||
tabs: Tab[]
|
||||
activeTabIdx: number
|
||||
}
|
||||
|
||||
export default function Tab(props: Props) {
|
||||
const accountId = useAccountId()
|
||||
const { address } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
return (
|
||||
<div className='relative w-full'>
|
||||
{props.tabs.map((tab, index) => (
|
||||
<NavLink
|
||||
key={tab.page}
|
||||
to={getRoute(tab.page, searchParams, address, accountId)}
|
||||
className={classNames(
|
||||
props.activeTabIdx === index ? underlineClasses : 'text-white/40',
|
||||
'relative mr-8 text-xl ',
|
||||
)}
|
||||
>
|
||||
{tab.name}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
import useAvailableColumns from 'components/earn/farm/Table/Columns/useAvailableColumns'
|
||||
import Table from 'components/common/Table'
|
||||
import useAvailableColumns from 'components/farm/Table/Columns/useAvailableColumns'
|
||||
|
||||
type Props = {
|
||||
data: Vault[]
|
||||
+1
-9
@@ -1,7 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { Plus } from 'components/common/Icons'
|
||||
import Loading from 'components/common/Loading'
|
||||
import useStore from 'store'
|
||||
|
||||
@@ -10,8 +9,6 @@ interface Props {
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export const DEPOSIT_META = { accessorKey: 'deposit', enableSorting: false, header: '' }
|
||||
|
||||
export const Deposit = (props: Props) => {
|
||||
const { vault } = props
|
||||
|
||||
@@ -29,12 +26,7 @@ export const Deposit = (props: Props) => {
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-end'>
|
||||
<ActionButton
|
||||
onClick={enterVaultHandler}
|
||||
color='tertiary'
|
||||
text='Deposit'
|
||||
leftIcon={<Plus />}
|
||||
/>
|
||||
<ActionButton onClick={enterVaultHandler} color='tertiary' text='Deposit' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import { ChevronDown } from 'components/common/Icons'
|
||||
import Loading from 'components/common/Loading'
|
||||
|
||||
export const DETAILS_META = { accessorKey: 'details', enableSorting: false, header: 'Deposit' }
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
isExpanded: boolean
|
||||
}
|
||||
|
||||
export default function Details(props: Props) {
|
||||
if (props.isLoading) return <Loading />
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className={classNames('w-4', props.isExpanded && 'rotate-180')}>
|
||||
<ChevronDown />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+8
-7
@@ -1,15 +1,16 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy'
|
||||
import { Deposit, DEPOSIT_META } from 'components/farm/Table/Columns/Deposit'
|
||||
import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
|
||||
import { Deposit } from 'components/earn/farm/Table/Columns/Deposit'
|
||||
import DepositCap, {
|
||||
DEPOSIT_CAP_META,
|
||||
depositCapSortingFn,
|
||||
} from 'components/farm/Table/Columns/DepositCap'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
|
||||
} from 'components/earn/farm/Table/Columns/DepositCap'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
||||
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
|
||||
import { DETAILS_META } from 'components/earn/farm/Table/Columns/Details'
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
@@ -40,7 +41,7 @@ export default function useAvailableColumns(props: Props) {
|
||||
cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||
},
|
||||
{
|
||||
...DEPOSIT_META,
|
||||
...DETAILS_META,
|
||||
cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||
},
|
||||
]
|
||||
+11
-15
@@ -1,16 +1,18 @@
|
||||
import { ColumnDef, Row } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Apy, { APY_META } from 'components/farm/Table/Columns/Apy'
|
||||
import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy'
|
||||
import DepositCap, {
|
||||
DEPOSIT_CAP_META,
|
||||
depositCapSortingFn,
|
||||
} from 'components/farm/Table/Columns/DepositCap'
|
||||
import Manage, { MANAGE_META } from 'components/farm/Table/Columns/Manage'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||
import PositionValue, { POSITION_VALUE_META } from 'components/farm/Table/Columns/PositionValue'
|
||||
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
|
||||
} from 'components/earn/farm/Table/Columns/DepositCap'
|
||||
import Details, { DETAILS_META } from 'components/earn/farm/Table/Columns/Details'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
||||
import PositionValue, {
|
||||
POSITION_VALUE_META,
|
||||
} from 'components/earn/farm/Table/Columns/PositionValue'
|
||||
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
@@ -53,14 +55,8 @@ export default function useDepositedColumns(props: Props) {
|
||||
),
|
||||
},
|
||||
{
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) => (
|
||||
<Manage
|
||||
vault={row.original}
|
||||
isLoading={props.isLoading}
|
||||
isExpanded={row.getIsExpanded()}
|
||||
/>
|
||||
),
|
||||
...DETAILS_META,
|
||||
cell: ({ row }) => <Details isLoading={props.isLoading} isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [props.isLoading])
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns'
|
||||
import VaultExpanded from 'components/earn/farm/VaultExpanded'
|
||||
import Table from 'components/common/Table'
|
||||
|
||||
type Props = {
|
||||
data: DepositedVault[]
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export default function DepositedVaultsTable(props: Props) {
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<DepositedVault>, table: TanStackTable<DepositedVault>) => (
|
||||
<VaultExpanded row={row} resetExpanded={table.resetExpanded} />
|
||||
),
|
||||
[],
|
||||
)
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Deposited Vaults'
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: 'name', desc: true }]}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Suspense, useMemo } from 'react'
|
||||
|
||||
import AvailableVaultsTable from 'components/farm/Table/AvailableVaultsTable'
|
||||
import DepositedVaultsTable from 'components/farm/Table/DepositedVaultsTable'
|
||||
import VaultUnlockBanner from 'components/farm/VaultUnlockBanner'
|
||||
import AvailableVaultsTable from 'components/earn/farm/Table/AvailableVaultsTable'
|
||||
import DepositedVaultsTable from 'components/earn/farm/Table/DepositedVaultsTable'
|
||||
import VaultUnlockBanner from 'components/earn/farm/VaultUnlockBanner'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
@@ -0,0 +1,98 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent'
|
||||
import Button from 'components/common/Button'
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useAlertDialog from 'hooks/useAlertDialog'
|
||||
import useAutoLend from 'hooks/useAutoLend'
|
||||
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
|
||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
|
||||
const buttonClassnames = 'm-0 flex w-40'
|
||||
const iconClassnames = 'ml-0 mr-1 w-4 h-4'
|
||||
|
||||
export default function LendingActionButtons(props: Props) {
|
||||
const { asset, accountLentValue: accountLendValue } = props.data
|
||||
const accountDeposits = useCurrentAccountDeposits()
|
||||
const { openLend, openReclaim } = useLendAndReclaimModal()
|
||||
const { open: showAlertDialog } = useAlertDialog()
|
||||
const { isAutoLendEnabledForCurrentAccount } = useAutoLend()
|
||||
const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount
|
||||
const address = useStore((s) => s.address)
|
||||
const accountId = useAccountId()
|
||||
const hasNoDeposit = !!(!assetDepositAmount && address && accountId)
|
||||
|
||||
const handleUnlend = useCallback(() => {
|
||||
if (isAutoLendEnabledForCurrentAccount) {
|
||||
showAlertDialog({
|
||||
icon: <ExclamationMarkCircled width={18} />,
|
||||
title: 'Disable Automatically Lend Assets',
|
||||
content:
|
||||
"Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.",
|
||||
positiveButton: {
|
||||
onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(),
|
||||
text: 'Continue to Account Settings',
|
||||
icon: <Enter />,
|
||||
},
|
||||
negativeButton: {
|
||||
text: 'Cancel',
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
openReclaim(props.data)
|
||||
}, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog])
|
||||
|
||||
return (
|
||||
<div className='flex flex-row space-x-2'>
|
||||
{accountLendValue && accountLendValue.isGreaterThan(0) && (
|
||||
<Button
|
||||
leftIcon={<ArrowDownLine />}
|
||||
iconClassName={iconClassnames}
|
||||
color='secondary'
|
||||
onClick={handleUnlend}
|
||||
className={buttonClassnames}
|
||||
>
|
||||
Unlend
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<ConditionalWrapper
|
||||
condition={hasNoDeposit}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have any ${asset.symbol}. Please first deposit ${asset.symbol} into your Credit Account before lending.`}</Text>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<ArrowUpLine />}
|
||||
iconClassName={iconClassnames}
|
||||
disabled={hasNoDeposit}
|
||||
color='secondary'
|
||||
onClick={() => openLend(props.data)}
|
||||
className={buttonClassnames}
|
||||
text='Lend'
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import AvailableLendsTable from 'components/lend/Table/AvailableLendsTable'
|
||||
import DepositedLendsTable from 'components/lend/Table/DepositedLendsTable'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import AvailableLendsTable from 'components/earn/lend/Table/AvailableLendsTable'
|
||||
import DepositedLendsTable from 'components/earn/lend/Table/DepositedLendsTable'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
|
||||
|
||||
+7
-2
@@ -1,10 +1,12 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import LendingActionButtons from 'components/earn/lend/LendingActionButtons'
|
||||
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
||||
import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
import { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||
import useAvailableColumns from 'components/lend/Table/Columns/useAvailableColumns'
|
||||
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
|
||||
|
||||
type Props = {
|
||||
data: LendingMarketTableData[]
|
||||
@@ -17,6 +19,9 @@ export default function AvailableLendsTable(props: Props) {
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<LendingMarketTableData>) => (
|
||||
<>
|
||||
<ActionButtonRow row={row}>
|
||||
<LendingActionButtons data={row.original} />
|
||||
</ActionButtonRow>
|
||||
<MarketDetails row={row} type='lend' />
|
||||
</>
|
||||
),
|
||||
+1
@@ -10,6 +10,7 @@ export const DEPOSIT_CAP_META = {
|
||||
accessorKey: 'marketDepositCap',
|
||||
header: 'Deposit Cap',
|
||||
id: 'marketDepositCap',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
export const marketDepositCapSortingFn = (
|
||||
-1
@@ -5,7 +5,6 @@ import { BN_ZERO } from 'constants/math'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const DEPOSIT_VALUE_META = {
|
||||
id: 'accountLentValue',
|
||||
accessorKey: 'accountLentValue',
|
||||
header: 'Deposited',
|
||||
}
|
||||
+5
-5
@@ -1,18 +1,18 @@
|
||||
import { ChevronDown, ChevronUp } from 'components/common/Icons'
|
||||
|
||||
export const CHEVRON_META = {
|
||||
id: 'chevron',
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
header: 'Manage',
|
||||
meta: {
|
||||
className: 'w-5',
|
||||
className: 'w-30',
|
||||
},
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isExpanded: boolean
|
||||
}
|
||||
export default function Chevron(props: Props) {
|
||||
export default function Manage(props: Props) {
|
||||
return (
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
|
||||
+6
-11
@@ -1,14 +1,13 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
|
||||
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
|
||||
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
|
||||
import DepositCap, {
|
||||
DEPOSIT_CAP_META,
|
||||
marketDepositCapSortingFn,
|
||||
} from 'components/lend/Table/Columns/DepositCap'
|
||||
import LendButton, { LEND_BUTTON_META } from 'components/lend/Table/Columns/LendButton'
|
||||
import Name, { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||
} from 'components/earn/lend/Table/Columns/DepositCap'
|
||||
import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
@@ -37,12 +36,8 @@ export default function useAvailableColumns(props: Props) {
|
||||
sortingFn: marketDepositCapSortingFn,
|
||||
},
|
||||
{
|
||||
...LEND_BUTTON_META,
|
||||
cell: ({ row }) => <LendButton data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [props.isLoading])
|
||||
+7
-15
@@ -1,23 +1,20 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Apy, { APY_META } from 'components/lend/Table/Columns/Apy'
|
||||
import Chevron, { CHEVRON_META } from 'components/lend/Table/Columns/Chevron'
|
||||
import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy'
|
||||
import DepositCap, {
|
||||
DEPOSIT_CAP_META,
|
||||
marketDepositCapSortingFn,
|
||||
} from 'components/lend/Table/Columns/DepositCap'
|
||||
} from 'components/earn/lend/Table/Columns/DepositCap'
|
||||
import DepositValue, {
|
||||
DEPOSIT_VALUE_META,
|
||||
depositedSortingFn,
|
||||
} from 'components/lend/Table/Columns/DepositValue'
|
||||
import Manage, { MANAGE_META } from 'components/lend/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||
import Action from 'components/v1/Table/deposits/Columns/Action'
|
||||
} from 'components/earn/lend/Table/Columns/DepositValue'
|
||||
import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage'
|
||||
import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function useDepositedColumns(props: Props) {
|
||||
@@ -51,13 +48,8 @@ export default function useDepositedColumns(props: Props) {
|
||||
},
|
||||
{
|
||||
...MANAGE_META,
|
||||
cell: ({ row }) =>
|
||||
props.v1 ? <Action data={row.original} /> : <Manage data={row.original} />,
|
||||
},
|
||||
{
|
||||
...CHEVRON_META,
|
||||
cell: ({ row }) => <Chevron isExpanded={row.getIsExpanded()} />,
|
||||
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||
},
|
||||
]
|
||||
}, [props.isLoading, props.v1])
|
||||
}, [props.isLoading])
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import LendingActionButtons from 'components/earn/lend/LendingActionButtons'
|
||||
import { NAME_META } from 'components/earn/lend/Table/Columns/Name'
|
||||
import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns'
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
import ActionButtonRow from 'components/common/Table/ActionButtonRow'
|
||||
|
||||
type Props = {
|
||||
data: LendingMarketTableData[]
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export default function DepositedLendsTable(props: Props) {
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<LendingMarketTableData>) => (
|
||||
<>
|
||||
<ActionButtonRow row={row}>
|
||||
<LendingActionButtons data={row.original} />
|
||||
</ActionButtonRow>
|
||||
<MarketDetails row={row} type='lend' />
|
||||
</>
|
||||
),
|
||||
[],
|
||||
)
|
||||
|
||||
if (!props.data.length) return null
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Lent Assets'
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: NAME_META.id, desc: false }]}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
import moment from 'moment/moment'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons'
|
||||
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'
|
||||
|
||||
export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' }
|
||||
|
||||
interface Props {
|
||||
vault: DepositedVault
|
||||
isLoading: boolean
|
||||
isExpanded: boolean
|
||||
}
|
||||
|
||||
export default function Manage(props: Props) {
|
||||
const accountId = useAccountId()
|
||||
const address = useStore((s) => s.address)
|
||||
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
|
||||
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
|
||||
const [isConfirming, setIsConfirming] = useState(false)
|
||||
|
||||
const depositMoreHandler = useCallback(() => {
|
||||
useStore.setState({
|
||||
vaultModal: {
|
||||
vault: props.vault,
|
||||
isDeposited: true,
|
||||
selectedBorrowDenoms: [props.vault.denoms.secondary],
|
||||
isCreate: false,
|
||||
},
|
||||
})
|
||||
}, [props.vault])
|
||||
|
||||
const unlockHandler = useCallback(
|
||||
() => useStore.setState({ unlockModal: { vault: props.vault } }),
|
||||
[props.vault],
|
||||
)
|
||||
|
||||
const withdrawHandler = useCallback(async () => {
|
||||
if (!accountId) return
|
||||
setIsConfirming(true)
|
||||
await withdrawFromVaults({
|
||||
accountId: accountId,
|
||||
vaults: [props.vault],
|
||||
slippage,
|
||||
})
|
||||
}, [accountId, props.vault, slippage, withdrawFromVaults])
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <Plus />,
|
||||
text: 'Deposit more',
|
||||
onClick: depositMoreHandler,
|
||||
},
|
||||
...(props.vault.status === VaultStatus.ACTIVE
|
||||
? [
|
||||
{
|
||||
icon: <LockUnlocked />,
|
||||
text: 'Unlock to withdraw',
|
||||
onClick: unlockHandler,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(props.vault.status === VaultStatus.UNLOCKING
|
||||
? [
|
||||
{
|
||||
icon: <LockLocked />,
|
||||
text: `Withdraw in ${moment(props.vault?.unlocksAt).fromNow(true)}`,
|
||||
onClick: () => {},
|
||||
disabled: true,
|
||||
disabledTooltip: '',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(props.vault.status === VaultStatus.UNLOCKED
|
||||
? [
|
||||
{
|
||||
icon: <AccountArrowDown />,
|
||||
text: 'Withdraw funds',
|
||||
onClick: withdrawHandler,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
[
|
||||
depositMoreHandler,
|
||||
props.vault.status,
|
||||
props.vault?.unlocksAt,
|
||||
unlockHandler,
|
||||
withdrawHandler,
|
||||
],
|
||||
)
|
||||
|
||||
if (props.isLoading) return <Loading />
|
||||
|
||||
if (!address) return null
|
||||
|
||||
return (
|
||||
<div className='z-10 flex justify-end'>
|
||||
<DropDownButton
|
||||
items={ITEMS}
|
||||
text='Manage'
|
||||
color='tertiary'
|
||||
showProgressIndicator={isConfirming}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import Table from 'components/common/Table'
|
||||
import useDepositedColumns from 'components/farm/Table/Columns/useDepositedColumns'
|
||||
|
||||
type Props = {
|
||||
data: DepositedVault[]
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
export default function DepositedVaultsTable(props: Props) {
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Deposited Vaults'
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={[{ id: 'name', desc: true }]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -36,7 +36,8 @@ export const menuTree = (walletId: WalletID, chainConfig: ChainConfig): MenuTree
|
||||
],
|
||||
},
|
||||
...(chainConfig.perps ? [{ pages: ['perps'] as Page[], label: 'Perps' }] : []),
|
||||
{ pages: chainConfig.farm ? ['lend', 'farm', 'borrow'] : ['lend'], label: 'Lend & Borrow' },
|
||||
{ pages: chainConfig.farm ? ['lend', 'farm'] : ['lend'], label: 'Earn' },
|
||||
{ pages: ['borrow'], label: 'Borrow' },
|
||||
...(chainConfig.hls ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []),
|
||||
{ pages: ['portfolio'], label: 'Portfolio' },
|
||||
{ pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) },
|
||||
@@ -48,7 +49,6 @@ export default function DesktopHeader() {
|
||||
const isOracleStale = useStore((s) => s.isOracleStale)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const accountId = useAccountId()
|
||||
const showAccountMenu = address && !isHLS
|
||||
|
||||
function handleCloseFocusMode() {
|
||||
if (focusComponent && focusComponent.onClose) focusComponent.onClose()
|
||||
@@ -92,7 +92,7 @@ export default function DesktopHeader() {
|
||||
<div className='flex gap-4'>
|
||||
{showStaleOracle && <OracleResyncButton />}
|
||||
{accountId && <RewardsCenter />}
|
||||
{showAccountMenu && <AccountMenu />}
|
||||
{address && !isHLS && <AccountMenu />}
|
||||
<Wallet />
|
||||
<ChainSelect />
|
||||
<Settings />
|
||||
|
||||
@@ -13,11 +13,9 @@ import PortfolioAccountPage from 'pages/PortfolioAccountPage'
|
||||
import PortfolioPage from 'pages/PortfolioPage'
|
||||
import TradePage from 'pages/TradePage'
|
||||
import Layout from 'pages/_layout'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function Routes() {
|
||||
const chainConfig = useChainConfig()
|
||||
const isV1 = useStore((s) => s.isV1)
|
||||
return (
|
||||
<RoutesWrapper>
|
||||
<Route
|
||||
@@ -30,7 +28,7 @@ export default function Routes() {
|
||||
<Route path='/trade' element={<TradePage />} />
|
||||
<Route path='/trade-advanced' element={<TradePage />} />
|
||||
{chainConfig.perps && <Route path='/perps' element={<PerpsPage />} />}
|
||||
{chainConfig.farm && !isV1 && <Route path='/farm' element={<FarmPage />} />}
|
||||
{chainConfig.farm && <Route path='/farm' element={<FarmPage />} />}
|
||||
<Route path='/lend' element={<LendPage />} />
|
||||
<Route path='/borrow' element={<BorrowPage />} />
|
||||
<Route path='/portfolio' element={<PortfolioPage />} />
|
||||
@@ -43,7 +41,7 @@ export default function Routes() {
|
||||
<Route path='trade' element={<TradePage />} />
|
||||
<Route path='trade-advanced' element={<TradePage />} />
|
||||
{chainConfig.perps && <Route path='perps' element={<PerpsPage />} />}
|
||||
{chainConfig.farm && !isV1 && <Route path='farm' element={<FarmPage />} />}
|
||||
{chainConfig.farm && <Route path='farm' element={<FarmPage />} />}
|
||||
<Route path='lend' element={<LendPage />} />
|
||||
<Route path='borrow' element={<BorrowPage />} />
|
||||
<Route path='portfolio' element={<PortfolioPage />} />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
|
||||
import DepositCap, { DEPOSIT_CAP_META } from 'components/farm/Table/Columns/DepositCap'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/farm/Table/Columns/Name'
|
||||
import TVL, { TVL_META } from 'components/farm/Table/Columns/TVL'
|
||||
import DepositCap, { DEPOSIT_CAP_META } from 'components/earn/farm/Table/Columns/DepositCap'
|
||||
import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV'
|
||||
import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name'
|
||||
import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL'
|
||||
import Apy, { APY_META } from 'components/hls/Farm/Table/Columns/APY'
|
||||
import Deposit, { DEPOSIT_META } from 'components/hls/Farm/Table/Columns/Deposit'
|
||||
import MaxLeverage, { MAX_LEV_META } from 'components/hls/Farm/Table/Columns/MaxLeverage'
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { ArrowUpLine } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
|
||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export const LEND_BUTTON_META = {
|
||||
accessorKey: 'lend',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
export default function LendButton(props: Props) {
|
||||
const { openLend } = useLendAndReclaimModal()
|
||||
const accountDeposits = useCurrentAccountDeposits()
|
||||
const assetDepositAmount = accountDeposits.find(byDenom(props.data.asset.denom))?.amount
|
||||
const address = useStore((s) => s.address)
|
||||
const accountId = useAccountId()
|
||||
const hasNoDeposit = !!(!assetDepositAmount && address && accountId)
|
||||
|
||||
return (
|
||||
<div className='flex justify-end'>
|
||||
<ConditionalWrapper
|
||||
condition={hasNoDeposit}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
content={
|
||||
<Text size='sm'>{`You don’t have any ${props.data.asset.symbol}.
|
||||
Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`}</Text>
|
||||
}
|
||||
contentClassName='max-w-[200px]'
|
||||
className='ml-auto'
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<ActionButton
|
||||
leftIcon={<ArrowUpLine />}
|
||||
disabled={hasNoDeposit}
|
||||
color='tertiary'
|
||||
onClick={(e) => {
|
||||
openLend(props.data)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
text='Lend'
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent'
|
||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||
import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useAlertDialog from 'hooks/useAlertDialog'
|
||||
import useAutoLend from 'hooks/useAutoLend'
|
||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||
import useStore from 'store'
|
||||
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: '',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: LendingMarketTableData
|
||||
}
|
||||
export default function Manage(props: Props) {
|
||||
const { openLend, openReclaim } = useLendAndReclaimModal()
|
||||
const { isAutoLendEnabledForCurrentAccount } = useAutoLend()
|
||||
const { open: showAlertDialog } = useAlertDialog()
|
||||
const address = useStore((s) => s.address)
|
||||
const account = useCurrentAccount()
|
||||
|
||||
const hasAssetInDeposits = useMemo(
|
||||
() => !!account?.deposits?.find((deposit) => deposit.denom === props.data.asset.denom),
|
||||
[account?.deposits, props.data.asset.denom],
|
||||
)
|
||||
|
||||
const handleUnlend = useCallback(() => {
|
||||
if (isAutoLendEnabledForCurrentAccount) {
|
||||
showAlertDialog({
|
||||
icon: <ExclamationMarkCircled width={18} />,
|
||||
title: 'Disable Automatically Lend Assets',
|
||||
content:
|
||||
"Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.",
|
||||
positiveButton: {
|
||||
onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(),
|
||||
text: 'Continue to Account Settings',
|
||||
icon: <Enter />,
|
||||
},
|
||||
negativeButton: {
|
||||
text: 'Cancel',
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
openReclaim(props.data)
|
||||
}, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog])
|
||||
|
||||
const ITEMS: DropDownItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <ArrowUpLine />,
|
||||
text: 'Lend more',
|
||||
onClick: () => openLend(props.data),
|
||||
disabled: !hasAssetInDeposits,
|
||||
disabledTooltip: `You don’t have any ${props.data.asset.symbol}.
|
||||
Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`,
|
||||
},
|
||||
{
|
||||
icon: <ArrowDownLine />,
|
||||
text: 'Unlend',
|
||||
onClick: handleUnlend,
|
||||
},
|
||||
],
|
||||
[handleUnlend, hasAssetInDeposits, openLend, props.data],
|
||||
)
|
||||
|
||||
if (!address) return null
|
||||
|
||||
return (
|
||||
<div className='flex justify-end z-10'>
|
||||
<DropDownButton items={ITEMS} text='Manage' color='tertiary' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import MarketDetails from 'components/common/MarketDetails'
|
||||
import Table from 'components/common/Table'
|
||||
import { DEPOSIT_VALUE_META } from 'components/lend/Table/Columns/DepositValue'
|
||||
import { NAME_META } from 'components/lend/Table/Columns/Name'
|
||||
import useDepositedColumns from 'components/lend/Table/Columns/useDepositedColumns'
|
||||
|
||||
type Props = {
|
||||
data: LendingMarketTableData[]
|
||||
isLoading: boolean
|
||||
v1?: boolean
|
||||
}
|
||||
|
||||
export default function DepositedLendsTable(props: Props) {
|
||||
const columns = useDepositedColumns({ isLoading: props.isLoading, v1: props.v1 })
|
||||
|
||||
const renderExpanded = useCallback(
|
||||
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
|
||||
[],
|
||||
)
|
||||
|
||||
if (!props.data.length) return null
|
||||
|
||||
return (
|
||||
<Table
|
||||
title={props.v1 ? 'Deposits' : 'Lent Assets'}
|
||||
columns={columns}
|
||||
data={props.data}
|
||||
initialSorting={
|
||||
props.v1
|
||||
? [
|
||||
{ id: DEPOSIT_VALUE_META.id, desc: true },
|
||||
{ id: NAME_META.id, desc: false },
|
||||
]
|
||||
: [{ id: NAME_META.id, desc: false }]
|
||||
}
|
||||
renderExpanded={renderExpanded}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,35 +1,10 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
|
||||
import Table from 'components/common/Table'
|
||||
import usePerpsBalancesColumns from 'components/perps/BalancesTable/Columns/usePerpsBalancesColumns'
|
||||
import usePerpsBalancesData from 'components/perps/BalancesTable/usePerpsBalancesData'
|
||||
import { SearchParams } from 'types/enums/searchParams'
|
||||
import { getSearchParamsObject } from 'utils/route'
|
||||
import Table from 'components/common/Table'
|
||||
|
||||
export default function PerpsBalancesTable() {
|
||||
const data = usePerpsBalancesData()
|
||||
const columns = usePerpsBalancesColumns()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
|
||||
const onClickRow = useCallback(
|
||||
(denom: string) => {
|
||||
const params = getSearchParamsObject(searchParams)
|
||||
setSearchParams({
|
||||
...params,
|
||||
[SearchParams.PERPS_MARKET]: denom,
|
||||
})
|
||||
},
|
||||
[searchParams, setSearchParams],
|
||||
)
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Perp Positions'
|
||||
columns={columns}
|
||||
data={data}
|
||||
initialSorting={[]}
|
||||
onClickRow={onClickRow}
|
||||
/>
|
||||
)
|
||||
return <Table title='Perp Positions' columns={columns} data={data} initialSorting={[]} />
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMar
|
||||
import Card from 'components/common/Card'
|
||||
import TableSkeleton from 'components/common/Table/TableSkeleton'
|
||||
import Text from 'components/common/Text'
|
||||
import useLendingMarketAssetsTableData from 'components/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
|
||||
interface Props {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user