release v1.4.4

This commit is contained in:
Linkie Link 2023-04-21 09:01:38 +08:00
parent 7fc6bea7f6
commit 01fc911c34
No known key found for this signature in database
GPG Key ID: 5318B0F2564D38EA
2 changed files with 248 additions and 557 deletions

View File

@ -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

View File

@ -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>
)
}