mirror of
https://github.com/cerc-io/mars-interface.git
synced 2025-06-14 17:55:41 +00:00
release v1.4.4
This commit is contained in:
parent
7fc6bea7f6
commit
01fc911c34
@ -1,6 +1,5 @@
|
|||||||
import 'chart.js/auto'
|
import 'chart.js/auto'
|
||||||
|
|
||||||
import { Coin } from '@cosmjs/stargate'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import {
|
import {
|
||||||
BorrowCapacity,
|
BorrowCapacity,
|
||||||
@ -22,7 +21,7 @@ import {
|
|||||||
maintainanceMarginWeightedDepositValue,
|
maintainanceMarginWeightedDepositValue,
|
||||||
producePercentData,
|
producePercentData,
|
||||||
} from 'libs/assetInfo'
|
} from 'libs/assetInfo'
|
||||||
import { formatValue, lookup, lookupSymbol, magnify } from 'libs/parse'
|
import { formatValue, lookup, lookupSymbol } from 'libs/parse'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { Bar } from 'react-chartjs-2'
|
import { Bar } from 'react-chartjs-2'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -46,7 +45,6 @@ interface Props {
|
|||||||
actionButtonSpec: ModalActionButton
|
actionButtonSpec: ModalActionButton
|
||||||
submitted: boolean
|
submitted: boolean
|
||||||
feeError?: string
|
feeError?: string
|
||||||
txFee?: Coin
|
|
||||||
activeView: ViewType
|
activeView: ViewType
|
||||||
denom: string
|
denom: string
|
||||||
decimals: number
|
decimals: number
|
||||||
@ -67,7 +65,6 @@ export const Action = ({
|
|||||||
actionButtonSpec,
|
actionButtonSpec,
|
||||||
submitted,
|
submitted,
|
||||||
feeError,
|
feeError,
|
||||||
txFee,
|
|
||||||
activeView,
|
activeView,
|
||||||
denom,
|
denom,
|
||||||
decimals,
|
decimals,
|
||||||
@ -229,13 +226,8 @@ export const Action = ({
|
|||||||
}, [denom, availableBalanceBaseCurrency, currentAssetPrice, marketAssetLiquidity])
|
}, [denom, availableBalanceBaseCurrency, currentAssetPrice, marketAssetLiquidity])
|
||||||
|
|
||||||
const repayMax = useMemo((): number => {
|
const repayMax = useMemo((): number => {
|
||||||
let adjustedWalletBalance = walletBalance
|
return Math.min(assetBorrowBalance, walletBalance)
|
||||||
if (denom === baseCurrency.denom) {
|
}, [assetBorrowBalance, walletBalance, denom, baseCurrency.denom])
|
||||||
adjustedWalletBalance = walletBalance - Number(magnify(Number(txFee), 6))
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.min(assetBorrowBalance, adjustedWalletBalance)
|
|
||||||
}, [assetBorrowBalance, walletBalance, txFee, denom, baseCurrency.denom])
|
|
||||||
|
|
||||||
const maxWithdrawableAmount = useMemo((): number => {
|
const maxWithdrawableAmount = useMemo((): number => {
|
||||||
const assetLtvRatio = findByDenom(marketInfo, denom)?.max_loan_to_value || 0
|
const assetLtvRatio = findByDenom(marketInfo, denom)?.max_loan_to_value || 0
|
||||||
|
@ -1,581 +1,280 @@
|
|||||||
import 'chart.js/auto'
|
import { TxBroadcastResult } from '@marsprotocol/wallet-connector'
|
||||||
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import classNames from 'classnames'
|
import { Action, Notification, TxResponse } from 'components/common'
|
||||||
import {
|
|
||||||
BorrowCapacity,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
ConnectButton,
|
|
||||||
DisplayCurrency,
|
|
||||||
ErrorMessage,
|
|
||||||
InputSection,
|
|
||||||
} from 'components/common'
|
|
||||||
import { findByDenom } from 'functions'
|
import { findByDenom } from 'functions'
|
||||||
import { maxBorrowableAmount } from 'functions/redbank/maxBorrowableAmount'
|
|
||||||
import { produceBarChartConfig } from 'functions/redbank/produceBarChartConfig'
|
|
||||||
import { produceUpdatedAssetData } from 'functions/redbank/produceUpdatedAssetData'
|
|
||||||
import { useUserBalance } from 'hooks/queries'
|
|
||||||
import {
|
import {
|
||||||
balanceSum,
|
getRedbankBorrowMsgOptions,
|
||||||
ltvWeightedDepositValue,
|
getRedbankDepositMsgOptions,
|
||||||
maintainanceMarginWeightedDepositValue,
|
getRedbankRepayMsgOptions,
|
||||||
producePercentData,
|
getRedbankWithdrawMsgOptions,
|
||||||
} from 'libs/assetInfo'
|
} from 'functions/messages'
|
||||||
import { formatValue, lookup, lookupSymbol } from 'libs/parse'
|
import { useEstimateFee } from 'hooks/queries'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { ltvWeightedDepositValue, maintainanceMarginWeightedDepositValue } from 'libs/assetInfo'
|
||||||
import { Bar } from 'react-chartjs-2'
|
import { lookup, lookupDecimals } from 'libs/parse'
|
||||||
|
import isEqual from 'lodash.isequal'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import React, { useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import colors from 'styles/_assets.module.scss'
|
import { NotificationType, ViewType } from 'types/enums'
|
||||||
import { ViewType } from 'types/enums'
|
import { QUERY_KEYS } from 'types/enums/queryKeys'
|
||||||
|
|
||||||
import styles from './Action.module.scss'
|
import styles from './RedbankAction.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
amount: number
|
|
||||||
redBankAssets: RedBankAsset[]
|
|
||||||
depositAssets: RedBankAsset[]
|
|
||||||
borrowAssets: RedBankAsset[]
|
|
||||||
setIsMax: (isMax: boolean) => void
|
|
||||||
setCapHit: (capHit: boolean) => void
|
|
||||||
setAmountCallback: (amount: number) => void
|
|
||||||
mmScaledDepositAmount: number
|
|
||||||
ltvScaledDepositAmount: number
|
|
||||||
totalBorrowBaseCurrencyAmount: number
|
|
||||||
actionButtonSpec: ModalActionButton
|
|
||||||
submitted: boolean
|
|
||||||
feeError?: string
|
|
||||||
activeView: ViewType
|
activeView: ViewType
|
||||||
denom: string
|
id: string
|
||||||
decimals: number
|
|
||||||
handleClose: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Action = ({
|
export const RedbankAction = React.memo(
|
||||||
amount,
|
({ activeView, id }: Props) => {
|
||||||
redBankAssets,
|
// ------------------
|
||||||
depositAssets,
|
// EXTERNAL HOOKS
|
||||||
borrowAssets,
|
// ------------------
|
||||||
setIsMax,
|
const { t } = useTranslation()
|
||||||
setCapHit,
|
const router = useRouter()
|
||||||
setAmountCallback,
|
const queryClient = useQueryClient()
|
||||||
mmScaledDepositAmount,
|
|
||||||
ltvScaledDepositAmount,
|
|
||||||
totalBorrowBaseCurrencyAmount,
|
|
||||||
actionButtonSpec,
|
|
||||||
submitted,
|
|
||||||
feeError,
|
|
||||||
activeView,
|
|
||||||
denom,
|
|
||||||
decimals,
|
|
||||||
handleClose,
|
|
||||||
}: Props) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
// ------------------
|
|
||||||
// STORE STATE
|
|
||||||
// ------------------
|
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
|
||||||
const marketInfo = useStore((s) => s.marketInfo)
|
|
||||||
const marketAssetLiquidity = useStore((s) => s.marketAssetLiquidity)
|
|
||||||
const userCollateral = useStore((s) => s.userCollateral)
|
|
||||||
const userWalletAddress = useStore((s) => s.userWalletAddress)
|
|
||||||
const whitelistedAssets = useStore((s) => s.whitelistedAssets)
|
|
||||||
const convertToBaseCurrency = useStore((s) => s.convertToBaseCurrency)
|
|
||||||
const findUserDebt = useStore((s) => s.findUserDebt)
|
|
||||||
const enableAnimations = useStore((s) => s.enableAnimations)
|
|
||||||
const baseCurrencyDecimals = useStore((s) => s.baseCurrency.decimals)
|
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
// LOCAL STATE
|
// STORE STATE
|
||||||
// ------------------
|
// ------------------
|
||||||
const [currentAssetPrice, setCurrentAssetPrice] = useState(0)
|
const client = useStore((s) => s.client)
|
||||||
const [portfolioVisible, setPortfolioVisible] = useState(false)
|
const marketInfo = useStore((s) => s.marketInfo)
|
||||||
const [chartsDataLoaded, setChartsDataLoaded] = useState(false)
|
const networkConfig = useStore((s) => s.networkConfig)
|
||||||
|
const otherAssets = useStore((s) => s.otherAssets)
|
||||||
|
const redBankAssets = useStore((s) => s.redBankAssets)
|
||||||
|
const userBalances = useStore((s) => s.userBalances)
|
||||||
|
const userCollateral = useStore((s) => s.userCollateral)
|
||||||
|
const whitelistedAssets = useStore((s) => s.whitelistedAssets)
|
||||||
|
const executeMsg = useStore((s) => s.executeMsg)
|
||||||
|
|
||||||
const { data: userBalances } = useUserBalance()
|
// ------------------
|
||||||
|
// LOCAL STATE
|
||||||
|
// ------------------
|
||||||
|
const [amount, setAmount] = useState(0)
|
||||||
|
const [submitted, setSubmitted] = useState(false)
|
||||||
|
const [response, setResponse] = useState<TxBroadcastResult>()
|
||||||
|
const [error, setError] = useState<string>()
|
||||||
|
const [isMax, setIsMax] = useState<boolean>(false)
|
||||||
|
const [capHit, setCapHit] = useState<boolean>(false)
|
||||||
|
|
||||||
/// ------------------
|
// ------------------
|
||||||
// VARIABLES
|
// VARIABLES
|
||||||
// ------------------
|
// ------------------
|
||||||
const walletBalance = Number(findByDenom(userBalances || [], denom)?.amount.toString()) || 0
|
const assets = [...whitelistedAssets, ...otherAssets]
|
||||||
const assetBorrowBalance = findUserDebt(denom)
|
const denom = assets.find((asset) => asset.id === id)?.denom || ''
|
||||||
const availableBalanceBaseCurrency = Math.max(
|
const decimals = lookupDecimals(denom, whitelistedAssets || []) || 6
|
||||||
ltvScaledDepositAmount - totalBorrowBaseCurrencyAmount,
|
const symbol = assets.find((asset) => asset.id === id)?.symbol || ''
|
||||||
0,
|
const walletBallance = Number(findByDenom(userBalances, denom)?.amount.toString())
|
||||||
)
|
|
||||||
const currentAsset = redBankAssets.find((asset) => asset.denom === denom)
|
|
||||||
|
|
||||||
// -------------------------
|
// Read only states
|
||||||
// calculate
|
const borrowAssetName = redBankAssets.find((asset) => asset.denom === denom)
|
||||||
// -------------------------
|
const redBankContractAddress = networkConfig?.contracts.redBank
|
||||||
const relevantAssetData = useMemo(
|
const totalScaledDepositbaseCurrencyBalance = useMemo(() => {
|
||||||
() =>
|
if (!userCollateral) return 0
|
||||||
activeView === ViewType.Deposit || activeView === ViewType.Withdraw
|
return ltvWeightedDepositValue(
|
||||||
? depositAssets
|
|
||||||
: borrowAssets,
|
|
||||||
[depositAssets, borrowAssets, activeView],
|
|
||||||
)
|
|
||||||
|
|
||||||
const relevantBalanceKey = useMemo(
|
|
||||||
() =>
|
|
||||||
activeView === ViewType.Deposit || activeView === ViewType.Withdraw
|
|
||||||
? 'depositBalanceBaseCurrency'
|
|
||||||
: 'borrowBalanceBaseCurrency',
|
|
||||||
[activeView],
|
|
||||||
)
|
|
||||||
|
|
||||||
const amountAdjustedAssetData = useMemo(
|
|
||||||
() =>
|
|
||||||
produceUpdatedAssetData(
|
|
||||||
redBankAssets,
|
redBankAssets,
|
||||||
[...relevantAssetData],
|
marketInfo,
|
||||||
denom,
|
userCollateral,
|
||||||
amount * currentAssetPrice, // amount in display currency
|
'depositBalanceBaseCurrency',
|
||||||
activeView,
|
)
|
||||||
relevantBalanceKey,
|
}, [redBankAssets, marketInfo, userCollateral])
|
||||||
baseCurrencyDecimals,
|
|
||||||
),
|
|
||||||
[
|
|
||||||
activeView,
|
|
||||||
amount,
|
|
||||||
relevantAssetData,
|
|
||||||
currentAssetPrice,
|
|
||||||
denom,
|
|
||||||
redBankAssets,
|
|
||||||
relevantBalanceKey,
|
|
||||||
baseCurrencyDecimals,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
const percentData = producePercentData(
|
const totalMMScaledDepositbaseCurrencyBalance = useMemo(() => {
|
||||||
produceUpdatedAssetData(
|
if (!userCollateral) return 0
|
||||||
redBankAssets,
|
return maintainanceMarginWeightedDepositValue(
|
||||||
[...relevantAssetData],
|
redBankAssets,
|
||||||
denom,
|
marketInfo,
|
||||||
0.0,
|
userCollateral,
|
||||||
activeView,
|
'depositBalanceBaseCurrency',
|
||||||
relevantBalanceKey,
|
)
|
||||||
baseCurrencyDecimals,
|
}, [redBankAssets, marketInfo, userCollateral])
|
||||||
),
|
|
||||||
relevantBalanceKey,
|
|
||||||
)
|
|
||||||
const updatedData = producePercentData(amountAdjustedAssetData, relevantBalanceKey)
|
|
||||||
|
|
||||||
// ---------------------
|
const totalBorrowBaseCurrencyAmount = redBankAssets.reduce(
|
||||||
// logic
|
(total, asset) => total + (Number(asset.borrowBalanceBaseCurrency) || 0),
|
||||||
// ---------------------
|
0,
|
||||||
const newTotalMMScaledSupplyBalance = useMemo(
|
)
|
||||||
() =>
|
|
||||||
// For deposits and withdraws, we need to recalculate the loan limit
|
|
||||||
{
|
|
||||||
if (!userCollateral) return 0
|
|
||||||
// On first deposit of asset, SC does not hold state of collateral.enabled
|
|
||||||
// Therefore, we need to emulate this state
|
|
||||||
const isFirstDeposit =
|
|
||||||
!relevantAssetData.find((asset) => asset.denom === denom) &&
|
|
||||||
activeView === ViewType.Deposit
|
|
||||||
|
|
||||||
return activeView === ViewType.Deposit || activeView === ViewType.Withdraw
|
// --------------------------------
|
||||||
? maintainanceMarginWeightedDepositValue(
|
// Transaction objects
|
||||||
amountAdjustedAssetData,
|
// --------------------------------
|
||||||
marketInfo,
|
|
||||||
userCollateral,
|
|
||||||
relevantBalanceKey,
|
|
||||||
isFirstDeposit ? denom : '',
|
|
||||||
)
|
|
||||||
: mmScaledDepositAmount
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
[activeView, amountAdjustedAssetData, mmScaledDepositAmount],
|
|
||||||
)
|
|
||||||
|
|
||||||
const newTotalLTVScaledSupplyBalance = useMemo(
|
const txMsgOptions = useMemo(() => {
|
||||||
() =>
|
if (!redBankContractAddress || amount <= 0 || !denom) return
|
||||||
// For deposits and withdraws, we need to recalculate the loan limit
|
|
||||||
{
|
|
||||||
if (!userCollateral) return 0
|
|
||||||
// On first deposit of asset, SC does not hold state of collateral.enabled
|
|
||||||
// Therefore, we need to emulate this state
|
|
||||||
const isFirstDeposit =
|
|
||||||
!relevantAssetData.find((asset) => asset.denom === denom) &&
|
|
||||||
activeView === ViewType.Deposit
|
|
||||||
|
|
||||||
return activeView === ViewType.Deposit || activeView === ViewType.Withdraw
|
switch (activeView) {
|
||||||
? ltvWeightedDepositValue(
|
case ViewType.Deposit:
|
||||||
amountAdjustedAssetData,
|
return getRedbankDepositMsgOptions(amount, denom)
|
||||||
marketInfo,
|
case ViewType.Withdraw:
|
||||||
userCollateral,
|
return getRedbankWithdrawMsgOptions(amount, denom)
|
||||||
relevantBalanceKey,
|
case ViewType.Repay:
|
||||||
isFirstDeposit ? denom : '',
|
return getRedbankRepayMsgOptions(
|
||||||
)
|
amount,
|
||||||
: ltvScaledDepositAmount
|
denom,
|
||||||
},
|
Number(findByDenom(userBalances, denom)?.amount) || 0,
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
isMax,
|
||||||
[activeView, amountAdjustedAssetData, ltvScaledDepositAmount],
|
)
|
||||||
)
|
case ViewType.Borrow:
|
||||||
|
return getRedbankBorrowMsgOptions(amount, denom)
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}, [activeView, amount, redBankContractAddress, denom, isMax, userBalances])
|
||||||
|
|
||||||
const debtValue =
|
const { data: fee, error: feeError } = useEstimateFee({
|
||||||
activeView === ViewType.Borrow || activeView === ViewType.Repay
|
msg: txMsgOptions?.msg,
|
||||||
? balanceSum(amountAdjustedAssetData, relevantBalanceKey)
|
funds:
|
||||||
: totalBorrowBaseCurrencyAmount
|
activeView === ViewType.Deposit || activeView === ViewType.Repay
|
||||||
|
? [{ denom, amount: amount > 0 ? amount.toFixed(0) : '1' }]
|
||||||
|
: undefined,
|
||||||
|
contract: redBankContractAddress,
|
||||||
|
})
|
||||||
|
|
||||||
const calculateMaxBorrowableAmount = useMemo((): number => {
|
const produceActionButtonSpec = (): ModalActionButton => {
|
||||||
const assetLiquidity = Number(findByDenom(marketAssetLiquidity, denom)?.amount || 0)
|
return {
|
||||||
|
disabled: amount === 0 || capHit,
|
||||||
return maxBorrowableAmount(assetLiquidity, availableBalanceBaseCurrency, currentAssetPrice)
|
fetching: (amount > 0 && typeof fee === 'undefined') || submitted,
|
||||||
}, [denom, availableBalanceBaseCurrency, currentAssetPrice, marketAssetLiquidity])
|
text: t(`redbank.${activeView.toLowerCase()}`),
|
||||||
|
clickHandler: handleAction,
|
||||||
const repayMax = useMemo((): number => {
|
color: 'primary',
|
||||||
return Math.min(assetBorrowBalance, walletBalance)
|
}
|
||||||
}, [assetBorrowBalance, walletBalance, denom, baseCurrency.denom])
|
|
||||||
|
|
||||||
const maxWithdrawableAmount = useMemo((): number => {
|
|
||||||
const assetLtvRatio = findByDenom(marketInfo, denom)?.max_loan_to_value || 0
|
|
||||||
const assetLiquidity = Number(findByDenom(marketAssetLiquidity, denom)?.amount || 0)
|
|
||||||
const asset = depositAssets.find((asset) => asset.denom === denom)
|
|
||||||
const assetBalanceOrAvailableLiquidity = Math.min(Number(asset?.depositBalance), assetLiquidity)
|
|
||||||
|
|
||||||
if (totalBorrowBaseCurrencyAmount === 0) {
|
|
||||||
return assetBalanceOrAvailableLiquidity
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we did not receive a usable asset there is nothing more to do.
|
const handleAction = async () => {
|
||||||
if (!asset || !asset.depositBalance || !asset.denom) return 0
|
if (!redBankContractAddress || !client) {
|
||||||
|
alert('Uh oh, operation failed')
|
||||||
const withdrawableAmountOfAsset =
|
return
|
||||||
availableBalanceBaseCurrency / (currentAssetPrice * assetLtvRatio)
|
|
||||||
|
|
||||||
return withdrawableAmountOfAsset < assetBalanceOrAvailableLiquidity
|
|
||||||
? withdrawableAmountOfAsset
|
|
||||||
: assetBalanceOrAvailableLiquidity
|
|
||||||
}, [
|
|
||||||
denom,
|
|
||||||
currentAssetPrice,
|
|
||||||
depositAssets,
|
|
||||||
availableBalanceBaseCurrency,
|
|
||||||
totalBorrowBaseCurrencyAmount,
|
|
||||||
marketInfo,
|
|
||||||
marketAssetLiquidity,
|
|
||||||
])
|
|
||||||
|
|
||||||
const maxUsableAmount = useMemo(() => {
|
|
||||||
if (!currentAsset) return 0
|
|
||||||
return activeView === ViewType.Deposit
|
|
||||||
? walletBalance
|
|
||||||
: activeView === ViewType.Withdraw
|
|
||||||
? maxWithdrawableAmount
|
|
||||||
: activeView === ViewType.Borrow
|
|
||||||
? calculateMaxBorrowableAmount
|
|
||||||
: repayMax
|
|
||||||
}, [
|
|
||||||
walletBalance,
|
|
||||||
maxWithdrawableAmount,
|
|
||||||
calculateMaxBorrowableAmount,
|
|
||||||
repayMax,
|
|
||||||
activeView,
|
|
||||||
currentAsset,
|
|
||||||
])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCurrentAssetPrice(convertToBaseCurrency({ denom: denom || '', amount: '1' }))
|
|
||||||
}, [denom, convertToBaseCurrency])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!chartsDataLoaded && percentData[0] != 0) {
|
|
||||||
setChartsDataLoaded(true)
|
|
||||||
}
|
|
||||||
}, [percentData, chartsDataLoaded])
|
|
||||||
|
|
||||||
const chartRefBefore = useRef(null)
|
|
||||||
const chartRefAfter = useRef(null)
|
|
||||||
|
|
||||||
// -----------
|
|
||||||
// callbacks
|
|
||||||
// -----------
|
|
||||||
const handleInputAmount = useCallback(
|
|
||||||
(inputAmount: number) => {
|
|
||||||
if (inputAmount >= maxUsableAmount * 0.99) {
|
|
||||||
setIsMax(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setAmountCallback(Number(formatValue(inputAmount, 0, 0, false, false, false, false, false)))
|
setSubmitted(true)
|
||||||
},
|
|
||||||
[maxUsableAmount, setIsMax, setAmountCallback],
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!currentAsset) return <></>
|
if (!fee || !txMsgOptions) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const amountUntilDepositCap = currentAsset.depositCap - Number(currentAsset.depositLiquidity)
|
try {
|
||||||
|
const res = await executeMsg({
|
||||||
const onValueEntered = (microValue: number) => {
|
msg: txMsgOptions.msg,
|
||||||
if (microValue >= maxUsableAmount) microValue = maxUsableAmount
|
// @ts-ignore
|
||||||
setAmountCallback(Number(formatValue(microValue, 0, 0, false, false, false, false, false)))
|
funds: txMsgOptions.funds || [],
|
||||||
setCapHit(amount > amountUntilDepositCap && activeView === ViewType.Deposit)
|
contract: redBankContractAddress,
|
||||||
}
|
fee: fee,
|
||||||
|
|
||||||
const produceTabActionButton = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
color='primary'
|
|
||||||
className={styles.submitButton}
|
|
||||||
disabled={actionButtonSpec.disabled}
|
|
||||||
onClick={() => actionButtonSpec.clickHandler()}
|
|
||||||
showProgressIndicator={actionButtonSpec.fetching}
|
|
||||||
text={actionButtonSpec.text}
|
|
||||||
/>
|
|
||||||
<ErrorMessage message={feeError} alignment='center' />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onEnterAction = () => {
|
|
||||||
if (!actionButtonSpec.disabled) actionButtonSpec.clickHandler()
|
|
||||||
}
|
|
||||||
|
|
||||||
const produceAvailableText = () => {
|
|
||||||
switch (activeView) {
|
|
||||||
case ViewType.Borrow:
|
|
||||||
return t('common.maxLimitAmountSymbol', {
|
|
||||||
amount: formatValue(
|
|
||||||
lookup(maxUsableAmount, denom, decimals),
|
|
||||||
0,
|
|
||||||
decimals,
|
|
||||||
true,
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
symbol: lookupSymbol(denom, whitelistedAssets || []),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
case ViewType.Deposit:
|
if (res?.response.code !== 0) {
|
||||||
return t('common.inWalletAmountSymbol', {
|
setError(res?.rawLogs)
|
||||||
amount: formatValue(
|
} else {
|
||||||
lookup(walletBalance, denom, decimals),
|
setResponse(res)
|
||||||
0,
|
|
||||||
decimals,
|
|
||||||
true,
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
symbol: lookupSymbol(denom, whitelistedAssets || []),
|
|
||||||
})
|
|
||||||
|
|
||||||
case ViewType.Withdraw:
|
|
||||||
// Find amount of asset deposited
|
|
||||||
const asset: RedBankAsset | undefined = depositAssets.find((asset) => asset.denom === denom)
|
|
||||||
return t('common.depositedAmountSymbol', {
|
|
||||||
amount: formatValue(
|
|
||||||
lookup(Number(asset?.depositBalance), denom, decimals),
|
|
||||||
0,
|
|
||||||
decimals,
|
|
||||||
true,
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
symbol: lookupSymbol(denom, whitelistedAssets || []),
|
|
||||||
})
|
|
||||||
|
|
||||||
case ViewType.Repay:
|
|
||||||
return t('redbank.borrowedAmountSymbol', {
|
|
||||||
amount: formatValue(
|
|
||||||
lookup(findUserDebt(denom), denom, decimals),
|
|
||||||
0,
|
|
||||||
decimals,
|
|
||||||
true,
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
symbol: lookupSymbol(denom, whitelistedAssets || []),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
// Presentation
|
|
||||||
// -------------
|
|
||||||
|
|
||||||
const produceBarChartData = (percentData: Array<number>, labels: string[]) => {
|
|
||||||
const barColors: string[] = []
|
|
||||||
labels.forEach((label) => {
|
|
||||||
barColors.push(colors[label.toLowerCase()])
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
axis: 'x',
|
|
||||||
barPercentage: 0.8,
|
|
||||||
maxBarThickness: 50,
|
|
||||||
data: percentData,
|
|
||||||
fill: true,
|
|
||||||
backgroundColor: barColors,
|
|
||||||
borderWidth: 1,
|
|
||||||
animation: {
|
|
||||||
duration: enableAnimations ? 800 : 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const barChartHeight = 40 * percentData.length + 10
|
|
||||||
|
|
||||||
const actionButton = !userWalletAddress ? (
|
|
||||||
<ConnectButton color={'secondary'} />
|
|
||||||
) : (
|
|
||||||
produceTabActionButton()
|
|
||||||
)
|
|
||||||
|
|
||||||
const adjustedLabels = amountAdjustedAssetData.map((asset) =>
|
|
||||||
lookupSymbol(asset.denom || '', whitelistedAssets || []),
|
|
||||||
)
|
|
||||||
|
|
||||||
const getTooltip = (): string | undefined => {
|
|
||||||
switch (activeView) {
|
|
||||||
case ViewType.Borrow:
|
|
||||||
return t('redbank.tooltips.borrow.action')
|
|
||||||
case ViewType.Deposit:
|
|
||||||
return t('redbank.tooltips.deposit.action')
|
|
||||||
case ViewType.Withdraw:
|
|
||||||
return t('redbank.tooltips.withdraw.action')
|
|
||||||
case ViewType.Repay:
|
|
||||||
return t('redbank.tooltips.repay.action')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const collapsableStyles = classNames(styles.collapsable, !portfolioVisible && styles.collapsed)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card onClick={handleClose} title={activeView} tooltip={getTooltip()}>
|
|
||||||
<InputSection
|
|
||||||
actionButton={actionButton}
|
|
||||||
amount={amount}
|
|
||||||
availableText={produceAvailableText()}
|
|
||||||
checkForMaxValue={activeView === ViewType.Deposit || activeView === ViewType.Repay}
|
|
||||||
asset={currentAsset}
|
|
||||||
disabled={
|
|
||||||
submitted ||
|
|
||||||
(amountUntilDepositCap <= 0 && activeView === ViewType.Deposit) ||
|
|
||||||
maxUsableAmount < 1
|
|
||||||
}
|
}
|
||||||
inputCallback={onValueEntered}
|
} catch (error) {
|
||||||
maxUsableAmount={maxUsableAmount}
|
const e = error as { message: string }
|
||||||
onEnterHandler={onEnterAction}
|
setError(e.message as string)
|
||||||
setAmountCallback={handleInputAmount}
|
}
|
||||||
amountUntilDepositCap={amountUntilDepositCap}
|
}
|
||||||
activeView={activeView}
|
|
||||||
walletBalance={walletBalance}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* SITUATION COMPARISON */}
|
const reset = () => {
|
||||||
<div className={styles.newSituation}>
|
setAmount(0)
|
||||||
<div className={styles.borrowCapacityContainer}>
|
setSubmitted(false)
|
||||||
<div className={styles.borrowCapacity}>
|
setError(undefined)
|
||||||
<div className={styles.borrowCapacityTitle}>
|
setIsMax(false)
|
||||||
<span className={`overline ${styles.title}`}>
|
}
|
||||||
{activeView === ViewType.Withdraw || activeView === ViewType.Deposit
|
|
||||||
? t('common.currentDepositBalance')
|
const handleClose = () => {
|
||||||
: t('common.currentBorrowBalance')}
|
reset()
|
||||||
</span>
|
|
||||||
<DisplayCurrency
|
// path on redbank action will always be /redbank/deposit/<denom> etce
|
||||||
className={styles.value}
|
router.push(`/${router.pathname.split('/')[1]}`)
|
||||||
coin={{
|
}
|
||||||
denom: baseCurrency.denom,
|
|
||||||
amount: balanceSum(relevantAssetData, relevantBalanceKey).toString(),
|
const removeZeroBalanceValues = (
|
||||||
}}
|
assets: RedBankAsset[],
|
||||||
prefixClass='sub2'
|
key: 'borrowBalance' | 'depositBalance',
|
||||||
valueClass='h4'
|
) => {
|
||||||
/>
|
const finalisedArray: RedBankAsset[] = []
|
||||||
</div>
|
for (let i = 0; i < assets.length; i++) {
|
||||||
<BorrowCapacity
|
if (Number(assets[i][key] ?? 0) > 0) {
|
||||||
balance={totalBorrowBaseCurrencyAmount}
|
finalisedArray.push(assets[i])
|
||||||
barHeight={'17px'}
|
}
|
||||||
limit={ltvScaledDepositAmount}
|
}
|
||||||
max={mmScaledDepositAmount}
|
|
||||||
showPercentageText
|
return finalisedArray
|
||||||
fadeTitle
|
}
|
||||||
/>
|
|
||||||
</div>
|
const { depositAssets, borrowAssets } = redBankAssets.reduce(
|
||||||
<div className={styles.borrowCapacity}>
|
(
|
||||||
<div className={styles.borrowCapacityTitle}>
|
prev: {
|
||||||
<span className={`overline ${styles.title}`}>
|
depositAssets: RedBankAsset[]
|
||||||
{activeView === ViewType.Withdraw || activeView === ViewType.Deposit
|
borrowAssets: RedBankAsset[]
|
||||||
? t('common.newDepositBalance')
|
},
|
||||||
: t('common.newBorrowBalance')}
|
curr,
|
||||||
</span>
|
) => {
|
||||||
<DisplayCurrency
|
if (Number(curr.depositBalance) > 0) {
|
||||||
className={styles.value}
|
prev.depositAssets.push(curr)
|
||||||
coin={{
|
}
|
||||||
denom: baseCurrency.denom,
|
if (Number(curr.borrowBalance) > 0) {
|
||||||
amount: balanceSum(amountAdjustedAssetData, relevantBalanceKey).toString(),
|
prev.borrowAssets.push(curr)
|
||||||
}}
|
}
|
||||||
prefixClass='sub2'
|
return prev
|
||||||
valueClass='h4'
|
},
|
||||||
/>
|
{ depositAssets: [], borrowAssets: [] },
|
||||||
</div>
|
)
|
||||||
<BorrowCapacity
|
|
||||||
balance={debtValue}
|
return (
|
||||||
barHeight={'17px'}
|
<div className={styles.cardContainer}>
|
||||||
limit={newTotalLTVScaledSupplyBalance}
|
<Notification
|
||||||
max={newTotalMMScaledSupplyBalance}
|
content={t('redbank.noFundsForRepay', {
|
||||||
showPercentageText
|
symbol: borrowAssetName?.symbol || '',
|
||||||
fadeTitle
|
})}
|
||||||
/>
|
showNotification={
|
||||||
</div>
|
walletBallance === 0 && activeView === ViewType.Repay && !response && !error
|
||||||
</div>
|
}
|
||||||
{chartsDataLoaded && (
|
type={NotificationType.Warning}
|
||||||
<div className={collapsableStyles}>
|
/>
|
||||||
<div className={styles.portfolio}>
|
|
||||||
<div className={styles.portfolioWrapper}>
|
{response || submitted || error ? (
|
||||||
<span className={`overline ${styles.title}`}>
|
<TxResponse
|
||||||
{t('redbank.currentComposition')}
|
error={error}
|
||||||
</span>
|
handleClose={handleClose}
|
||||||
<div className={styles.chartWrapper}>
|
onSuccess={() => {
|
||||||
<Bar
|
queryClient.invalidateQueries([QUERY_KEYS.USER_DEPOSIT])
|
||||||
data={produceBarChartData(percentData, adjustedLabels)}
|
queryClient.invalidateQueries([QUERY_KEYS.REDBANK])
|
||||||
height={barChartHeight}
|
queryClient.invalidateQueries([QUERY_KEYS.USER_BALANCE])
|
||||||
options={produceBarChartConfig(percentData)}
|
queryClient.invalidateQueries([QUERY_KEYS.USER_DEBT])
|
||||||
ref={chartRefBefore}
|
}}
|
||||||
/>
|
response={response}
|
||||||
</div>
|
title={t('common.summaryOfTheTransaction')}
|
||||||
</div>
|
actions={[
|
||||||
<div className={styles.portfolioWrapper}>
|
{
|
||||||
<span className={`overline ${styles.title}`}>{t('redbank.newComposition')}</span>
|
label: activeView,
|
||||||
<div className={styles.chartWrapper}>
|
values: [`${lookup(amount, denom, decimals).toString()} ${symbol}`],
|
||||||
<Bar
|
},
|
||||||
data={produceBarChartData(updatedData, adjustedLabels)}
|
]}
|
||||||
height={barChartHeight}
|
/>
|
||||||
options={produceBarChartConfig(updatedData)}
|
) : (
|
||||||
ref={chartRefAfter}
|
<Action
|
||||||
/>
|
actionButtonSpec={produceActionButtonSpec()}
|
||||||
</div>
|
feeError={!fee ? (feeError as string) : undefined}
|
||||||
</div>
|
activeView={activeView}
|
||||||
</div>
|
amount={Number(amount)}
|
||||||
</div>
|
borrowAssets={removeZeroBalanceValues(borrowAssets, 'borrowBalance')}
|
||||||
|
decimals={decimals}
|
||||||
|
denom={denom}
|
||||||
|
depositAssets={removeZeroBalanceValues(depositAssets, 'depositBalance')}
|
||||||
|
handleClose={handleClose}
|
||||||
|
ltvScaledDepositAmount={totalScaledDepositbaseCurrencyBalance}
|
||||||
|
mmScaledDepositAmount={totalMMScaledDepositbaseCurrencyBalance}
|
||||||
|
redBankAssets={redBankAssets}
|
||||||
|
setAmountCallback={setAmount}
|
||||||
|
setIsMax={setIsMax}
|
||||||
|
submitted={submitted}
|
||||||
|
totalBorrowBaseCurrencyAmount={totalBorrowBaseCurrencyAmount}
|
||||||
|
setCapHit={setCapHit}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(prev, next) => isEqual(prev, next),
|
||||||
|
)
|
||||||
|
|
||||||
{chartsDataLoaded && (
|
RedbankAction.displayName = 'RedbankAction'
|
||||||
<div className={styles.showPortfolio}>
|
|
||||||
<Button
|
|
||||||
onClick={() => setPortfolioVisible(!portfolioVisible)}
|
|
||||||
size='medium'
|
|
||||||
text={!portfolioVisible ? t('common.showComposition') : t('common.closeComposition')}
|
|
||||||
variant='transparent'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user