releave v.1.4.0

This commit is contained in:
bwvdhelm 2023-03-13 23:13:10 +01:00
parent d028d61a11
commit 6b86879fad
No known key found for this signature in database
GPG Key ID: 59FC90B476A8CB39
67 changed files with 1165 additions and 512 deletions

View File

@ -7,7 +7,7 @@ import {
WalletConnectionStatus, WalletConnectionStatus,
} from '@marsprotocol/wallet-connector' } from '@marsprotocol/wallet-connector'
import { useQueryClient } from '@tanstack/react-query' import { useQueryClient } from '@tanstack/react-query'
import { MARS_SYMBOL, USDC_SYMBOL } from 'constants/appConstants' import { MARS_SYMBOL } from 'constants/appConstants'
import { IS_TESTNET } from 'constants/env' import { IS_TESTNET } from 'constants/env'
import { import {
useBlockHeight, useBlockHeight,
@ -155,7 +155,6 @@ export const CommonContainer = ({ children }: CommonContainerProps) => {
useUserDebt() useUserDebt()
useMarsOracle() useMarsOracle()
useSpotPrice(MARS_SYMBOL) useSpotPrice(MARS_SYMBOL)
useSpotPrice(USDC_SYMBOL)
useDepositAndDebt() useDepositAndDebt()
useRedBank() useRedBank()

View File

@ -1,5 +1,6 @@
import { Coin } from '@cosmjs/stargate' import { Coin } from '@cosmjs/stargate'
import { AnimatedNumber } from 'components/common' import { AnimatedNumber } from 'components/common'
import { useEffect, useState } from 'react'
import useStore from 'store' import useStore from 'store'
interface Props { interface Props {
@ -20,7 +21,15 @@ export const DisplayCurrency = ({
const networkConfig = useStore((s) => s.networkConfig) const networkConfig = useStore((s) => s.networkConfig)
const convertToDisplayCurrency = useStore((s) => s.convertToDisplayCurrency) const convertToDisplayCurrency = useStore((s) => s.convertToDisplayCurrency)
const amount = convertToDisplayCurrency(coin) const amount = convertToDisplayCurrency(coin)
const displayCurrency = networkConfig?.displayCurrency const [displayCurrency, setDisplayCurrency] = useState<DisplayCurrency>(
networkConfig?.displayCurrency,
)
useEffect(() => {
if (!networkConfig) return
if (displayCurrency.denom !== networkConfig?.displayCurrency.denom)
setDisplayCurrency(networkConfig?.displayCurrency)
}, [networkConfig?.displayCurrency, displayCurrency.denom, networkConfig])
if (!displayCurrency) return null if (!displayCurrency) return null

View File

@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'
import useStore from 'store' import useStore from 'store'
import { DocURL } from 'types/enums/docURL' import { DocURL } from 'types/enums/docURL'
import { version } from '../../../../package.json' import packageInfo from '../../../../package.json'
import styles from './Footer.module.scss' import styles from './Footer.module.scss'
export const Footer = () => { export const Footer = () => {
@ -211,7 +211,7 @@ export const Footer = () => {
</div> </div>
</div> </div>
<div className={styles.version}> <div className={styles.version}>
<p className='faded xs'>Mars Protocol v{version}</p> <p className='faded xs'>Mars Protocol v{packageInfo.version}</p>
</div> </div>
</div> </div>
</footer> </footer>

View File

@ -18,6 +18,10 @@
outline: none; outline: none;
background: $alphaBlack10; background: $alphaBlack10;
.marsAmount {
margin: 0 space(1);
}
svg { svg {
margin-top: space(-0.5); margin-top: space(-0.5);
height: rem-calc(19); height: rem-calc(19);

View File

@ -153,13 +153,15 @@ export const IncentivesButton = () => {
}} }}
> >
<SVG.Logo /> <SVG.Logo />
<DisplayCurrency <span>
className={styles.balance} <AnimatedNumber
coin={{ amount={Number(unclaimedRewards) / 1e6}
amount: unclaimedRewards, minDecimals={2}
denom: marsDenom, maxDecimals={2}
}} className={styles.marsAmount}
/> />
{MARS_SYMBOL}
</span>
</button> </button>
{showDetails && ( {showDetails && (

View File

@ -43,6 +43,17 @@
flex: 0 0 100%; flex: 0 0 100%;
flex-wrap: wrap; flex-wrap: wrap;
display: flex; display: flex;
flex-direction: column;
.select {
border-radius: $borderRadiusS;
border: rem-calc(1) solid $alphaBlack20;
@include padding(1, 2);
color: $colorSecondaryDark;
background-color: $fontColorLightPrimary;
outline: none;
width: 100%;
}
.name { .name {
@include margin(1, 0); @include margin(1, 0);
@ -62,12 +73,16 @@
} }
} }
&.reduceMotion {
flex-direction: row;
}
.content { .content {
@include margin(1, 0); @include margin(1, 0);
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
flex: 1; flex: 1;
justify-content: flex-end; justify-content: space-between;
gap: space(2); gap: space(2);
.button { .button {

View File

@ -1,4 +1,5 @@
import { useWalletManager, WalletConnectionStatus } from '@marsprotocol/wallet-connector' import { useWalletManager, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
import { useQueryClient } from '@tanstack/react-query'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import classNames from 'classnames' import classNames from 'classnames'
import { Button, NumberInput, SVG, Toggle, Tooltip } from 'components/common' import { Button, NumberInput, SVG, Toggle, Tooltip } from 'components/common'
@ -12,15 +13,39 @@ import styles from './Settings.module.scss'
export const Settings = () => { export const Settings = () => {
const { t } = useTranslation() const { t } = useTranslation()
const inputPlaceholder = '...' const inputPlaceholder = '...'
const queryClient = useQueryClient()
const slippages = [0.02, 0.03] const slippages = [0.02, 0.03]
const [showDetails, setShowDetails] = useState(false) const [showDetails, setShowDetails] = useState(false)
const slippage = useStore((s) => s.slippage) const slippage = useStore((s) => s.slippage)
const networkConfig = useStore((s) => s.networkConfig)
const baseCurrency = useStore((s) => s.baseCurrency)
const whitelistedAssets = useStore((s) => s.whitelistedAssets)
const otherAssets = useStore((s) => s.otherAssets)
const assets: Asset[] = [...whitelistedAssets, ...otherAssets]
const [customSlippage, setCustomSlippage] = useState<string>(inputPlaceholder) const [customSlippage, setCustomSlippage] = useState<string>(inputPlaceholder)
const [inputRef, setInputRef] = useState<React.RefObject<HTMLInputElement>>() const [inputRef, setInputRef] = useState<React.RefObject<HTMLInputElement>>()
const [isCustom, setIsCustom] = useState(false) const [isCustom, setIsCustom] = useState(false)
const enableAnimations = useStore((s) => s.enableAnimations) const enableAnimations = useStore((s) => s.enableAnimations)
const { status } = useWalletManager() const { status } = useWalletManager()
const exchangeRates = useStore((s) => s.exchangeRates)
const [displayCurrency, setDisplayCurrency] = useState<DisplayCurrency>(() => {
const currency = {
denom: baseCurrency.denom,
prefix: '',
suffix: baseCurrency.symbol,
decimals: 2,
}
const currentCurrency = assets.find(
(asset) => asset.denom === networkConfig?.displayCurrency.denom,
)
if (currentCurrency) {
currency.denom = currentCurrency.denom
currency.prefix = ''
currency.suffix = currentCurrency.symbol
}
return currency
})
const onInputChange = (value: number) => { const onInputChange = (value: number) => {
setCustomSlippage(value.toString()) setCustomSlippage(value.toString())
@ -57,6 +82,24 @@ export const Settings = () => {
localStorage.setItem('enableAnimations', reduce ? 'false' : 'true') localStorage.setItem('enableAnimations', reduce ? 'false' : 'true')
} }
const changeDisplayCurrency = (denom: string) => {
const selectedAsset = assets.find((asset) => asset.denom === denom)
if (!selectedAsset || !networkConfig || !exchangeRates?.length) return
const newDisplayCurrency = {
denom: selectedAsset.denom,
prefix: '',
suffix: selectedAsset.symbol,
decimals: 2,
}
const exchangeRate = exchangeRates.find((rate) => rate.denom === newDisplayCurrency.denom)
if (!exchangeRate) return
setDisplayCurrency(newDisplayCurrency)
useStore.setState({ networkConfig: { ...networkConfig, displayCurrency: newDisplayCurrency } })
useStore.setState({ baseToDisplayCurrencyRatio: 1 / Number(exchangeRate.amount) })
localStorage.setItem('displayCurrency', JSON.stringify(newDisplayCurrency))
queryClient.invalidateQueries()
}
if (status !== WalletConnectionStatus.Connected) return null if (status !== WalletConnectionStatus.Connected) return null
return ( return (
@ -75,7 +118,7 @@ export const Settings = () => {
<p className={styles.text}>{t('common.settings')}</p> <p className={styles.text}>{t('common.settings')}</p>
</div> </div>
<div className={styles.settings}> <div className={styles.settings}>
<div className={styles.setting}> <div className={`${styles.setting} ${styles.reduceMotion}`}>
<div className={styles.name}> <div className={styles.name}>
{t('common.reduceMotion')} {t('common.reduceMotion')}
<Tooltip content={t('common.tooltips.reduceMotion')} className={styles.tooltip} /> <Tooltip content={t('common.tooltips.reduceMotion')} className={styles.tooltip} />
@ -88,6 +131,31 @@ export const Settings = () => {
/> />
</div> </div>
</div> </div>
<div className={styles.setting}>
<div className={styles.name}>
{t('common.displayCurrency')}
<Tooltip
content={t('common.tooltips.displayCurrency', {
baseCurrencySymbol: baseCurrency.symbol,
})}
className={styles.tooltip}
/>
</div>
<div className={styles.content}>
<select
onChange={(e) => changeDisplayCurrency(e.target.value)}
className={classNames([styles.select, 's'])}
tabIndex={2}
value={displayCurrency.denom}
>
{assets.map((currency) => (
<option key={currency.denom} value={currency.denom}>
{`${currency.name} (${currency.symbol})`}
</option>
))}
</select>
</div>
</div>
</div> </div>
{FIELDS_FEATURE && ( {FIELDS_FEATURE && (
<> <>

View File

@ -1,4 +1,5 @@
import Tippy from '@tippyjs/react' import Tippy from '@tippyjs/react'
import classNames from 'classnames'
import styles from './TextTooltip.module.scss' import styles from './TextTooltip.module.scss'
@ -7,6 +8,7 @@ interface Props {
tooltip: string | React.ReactNode tooltip: string | React.ReactNode
hideUnderline?: boolean hideUnderline?: boolean
hideStyling?: boolean hideStyling?: boolean
className?: string
} }
export const TextTooltip = (props: Props) => { export const TextTooltip = (props: Props) => {
return ( return (
@ -23,7 +25,13 @@ export const TextTooltip = (props: Props) => {
) )
}} }}
> >
<span className={props.hideUnderline ? styles.pointer : styles.tooltip} style={{}}> <span
className={classNames(
props.hideUnderline ? styles.pointer : styles.tooltip,
props.className,
)}
style={{}}
>
{props.text} {props.text}
</span> </span>
</Tippy> </Tippy>

View File

@ -66,7 +66,7 @@ export const Tutorial = (props: Props) => {
} }
const maxLeverage = props.availableVault const maxLeverage = props.availableVault
? formatValue(ltvToLeverage(props.availableVault?.ltv.max), 2, 2) ? formatValue(ltvToLeverage(props.availableVault?.ltv.contract), 2, 2)
: '' : ''
const content = ( const content = (

View File

@ -15,11 +15,16 @@ export const EditContent = (props: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const convertValueToAmount = useStore((s) => s.convertValueToAmount) const convertValueToAmount = useStore((s) => s.convertValueToAmount)
const borrowKey =
props.position.borrowDenom === props.vault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const primaryAmount = props.position.amounts.primary - (props.prevPosition?.amounts.primary || 0) const primaryAmount = props.position.amounts.primary - (props.prevPosition?.amounts.primary || 0)
const secondaryAmount = const secondaryAmount =
props.position.amounts.secondary - (props.prevPosition?.amounts.secondary || 0) props.position.amounts.secondary - (props.prevPosition?.amounts.secondary || 0)
const borrowedAmount = const borrowedAmount =
props.position.amounts.borrowed - (props.prevPosition?.amounts.borrowed || 0) props.position.amounts[borrowKey] - (props.prevPosition?.amounts[borrowKey] || 0)
const depositPrimary = ( const depositPrimary = (
<TokenBalance <TokenBalance
@ -43,10 +48,10 @@ export const EditContent = (props: Props) => {
/> />
) )
const borrowSecondary = ( const borrow = (
<TokenBalance <TokenBalance
coin={{ coin={{
denom: props.vault.denoms.secondary, denom: props.position.borrowDenom || props.vault.denoms.secondary,
amount: borrowedAmount.toString(), amount: borrowedAmount.toString(),
}} }}
className={styles.marginRight} className={styles.marginRight}
@ -78,14 +83,14 @@ export const EditContent = (props: Props) => {
return ( return (
<li> <li>
<span className={styles.marginRight}>{t('redbank.borrow')}</span> <span className={styles.marginRight}>{t('redbank.borrow')}</span>
{borrowSecondary} {borrow}
</li> </li>
) )
} }
const getSwapMessage = () => { const getSwapMessage = () => {
const primaryValue = props.position.values.primary const primaryValue = props.position.values.primary + props.position.values.borrowedPrimary
const secondaryValue = props.position.values.secondary + props.position.values.borrowed const secondaryValue = props.position.values.secondary + props.position.values.borrowedSecondary
const difference = Math.abs(primaryValue - secondaryValue) const difference = Math.abs(primaryValue - secondaryValue)
if (difference < SWAP_THRESHOLD) return null if (difference < SWAP_THRESHOLD) return null

View File

@ -15,14 +15,21 @@ export const UnlockContent = (props: Props) => {
<> <>
<li>{t('fields.removeLiquidity', { vault: props.vault.provider })}</li> <li>{t('fields.removeLiquidity', { vault: props.vault.provider })}</li>
<li> <li>
<span className={styles.marginRight}>{t('redbank.repay')}</span> {props.position.borrowDenom && (
<TokenBalance <>
coin={{ <span className={styles.marginRight}>{t('redbank.repay')}</span>
denom: props.vault.denoms.secondary, <TokenBalance
amount: props.position.amounts.borrowed.toString(), coin={{
}} denom: props.position.borrowDenom,
showSymbol amount: Math.max(
/> props.position.amounts.borrowedPrimary,
props.position.amounts.borrowedSecondary,
).toString(),
}}
showSymbol
/>
</>
)}
</li> </li>
<li> <li>
<span className={styles.marginRight}>{t('redbank.withdraw')}</span> <span className={styles.marginRight}>{t('redbank.withdraw')}</span>

View File

@ -123,7 +123,10 @@ export const ActiveVaultsTableMobile = () => {
<DisplayCurrency <DisplayCurrency
coin={{ coin={{
denom: baseCurrency.denom, denom: baseCurrency.denom,
amount: vault.position.values.borrowed.toString(), amount: (vault.position.borrowDenom === vault.denoms.primary
? vault.position.amounts.borrowedPrimary
: vault.position.amounts.borrowedSecondary
).toString(),
}} }}
className={styles.inline} className={styles.inline}
/> />
@ -136,9 +139,13 @@ export const ActiveVaultsTableMobile = () => {
<div className={styles.borrowCapacity}> <div className={styles.borrowCapacity}>
<BorrowCapacity <BorrowCapacity
showPercentageText={true} showPercentageText={true}
max={getLiqBorrowValue(vault, maxBorrowValue)} max={getLiqBorrowValue(vault, vault.position.values.net)}
limit={maxBorrowValue} limit={maxBorrowValue}
balance={vault.position.values.borrowed} balance={
vault.position.borrowDenom === vault.denoms.primary
? vault.position.values.borrowedPrimary
: vault.position.values.borrowedSecondary
}
showTitle={false} showTitle={false}
barHeight={'16px'} barHeight={'16px'}
hideValues hideValues

View File

@ -75,13 +75,16 @@ export const useActiveVaultsColumns = () => {
cell: ({ row }) => { cell: ({ row }) => {
const primaryCoin = { const primaryCoin = {
denom: row.original.denoms.primary, denom: row.original.denoms.primary,
amount: row.original.position.amounts.primary.toString(), amount: (
row.original.position.amounts.primary + row.original.position.amounts.borrowedPrimary
).toString(),
} }
const secondaryCoin = { const secondaryCoin = {
denom: row.original.denoms.secondary, denom: row.original.denoms.secondary,
amount: ( amount: (
row.original.position.amounts.secondary + row.original.position.amounts.borrowed row.original.position.amounts.secondary +
row.original.position.amounts.borrowedSecondary
).toString(), ).toString(),
} }
@ -97,9 +100,13 @@ export const useActiveVaultsColumns = () => {
} }
tooltip={ tooltip={
<> <>
<TokenBalance coin={primaryCoin} maxDecimals={2} showSymbol /> {Number(primaryCoin.amount) > 0 && (
<TokenBalance coin={primaryCoin} maxDecimals={2} showSymbol />
)}
<br /> <br />
<TokenBalance coin={secondaryCoin} maxDecimals={2} showSymbol /> {Number(secondaryCoin.amount) > 0 && (
<TokenBalance coin={secondaryCoin} maxDecimals={2} showSymbol />
)}
</> </>
} }
/> />
@ -134,41 +141,50 @@ export const useActiveVaultsColumns = () => {
} }
tooltip={ tooltip={
<> <>
<TokenBalance coin={coins[0]} maxDecimals={2} showSymbol /> {Number(coins[0].amount) > 0 && (
<TokenBalance coin={coins[0]} maxDecimals={2} showSymbol />
)}
<br /> <br />
<TokenBalance coin={coins[1]} maxDecimals={2} showSymbol /> {Number(coins[1].amount) > 0 && (
<TokenBalance coin={coins[1]} maxDecimals={2} showSymbol />
)}{' '}
</> </>
} }
/> />
) )
}, },
}), }),
columnHelper.accessor('position.values.borrowed', { columnHelper.accessor('position.values.borrowedPrimary', {
enableSorting: true, enableSorting: true,
header: () => ( header: () => (
<TextTooltip text={t('common.borrowed')} tooltip={t('fields.tooltips.borrowValue')} /> <TextTooltip text={t('common.borrowed')} tooltip={t('fields.tooltips.borrowValue')} />
), ),
cell: (info) => { cell: ({ row }) => {
const borrowAsset = whitelistedAssets.find( const borrowAsset = whitelistedAssets.find(
(asset) => asset.denom === info.row.original.denoms.secondary, (asset) => asset.denom === row.original.position.borrowDenom,
) )
if (!borrowAsset) return if (!borrowAsset) return
const borrowKey =
row.original.position.borrowDenom === row.original.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
return ( return (
<TextTooltip <TextTooltip
text={ text={
<DisplayCurrency <DisplayCurrency
coin={{ coin={{
denom: baseCurrency.denom, denom: baseCurrency.denom,
amount: info.row.original.position.values.borrowed.toString(), amount: row.original.position.values[borrowKey].toString(),
}} }}
/> />
} }
tooltip={ tooltip={
<TokenBalance <TokenBalance
coin={{ coin={{
denom: info.row.original.denoms.secondary, denom: borrowAsset.denom,
amount: info.row.original.position.amounts.borrowed.toString(), amount: row.original.position.amounts[borrowKey].toString(),
}} }}
maxDecimals={2} maxDecimals={2}
showSymbol showSymbol
@ -291,7 +307,7 @@ export const useActiveVaultsColumns = () => {
</p> </p>
<p className='s faded'> <p className='s faded'>
{formatValue( {formatValue(
ltvToLeverage(row.original.ltv.max), ltvToLeverage(row.original.ltv.contract),
2, 2,
2, 2,
false, false,
@ -303,7 +319,7 @@ export const useActiveVaultsColumns = () => {
) )
}, },
}), }),
columnHelper.accessor('position.amounts.borrowed', { columnHelper.accessor('position.amounts.borrowedPrimary', {
enableSorting: false, enableSorting: false,
header: () => ( header: () => (
<TextTooltip <TextTooltip
@ -313,13 +329,19 @@ export const useActiveVaultsColumns = () => {
), ),
cell: ({ row }) => { cell: ({ row }) => {
const maxBorrowValue = getMaxBorrowValue(row.original, row.original.position) const maxBorrowValue = getMaxBorrowValue(row.original, row.original.position)
const borrowKey =
row.original.position.borrowDenom === row.original.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const liqBorrowValue = getLiqBorrowValue(row.original, row.original.position.values.net)
return ( return (
<BorrowCapacity <BorrowCapacity
showPercentageText={true} showPercentageText={true}
max={getLiqBorrowValue(row.original, maxBorrowValue)} max={liqBorrowValue}
limit={maxBorrowValue} limit={maxBorrowValue}
balance={row.original.position.values.borrowed} balance={row.original.position.values[borrowKey]}
showTitle={false} showTitle={false}
barHeight={'16px'} barHeight={'16px'}
hideValues hideValues

View File

@ -24,11 +24,20 @@ export const AvailableVaultsTableMobile = () => {
> >
<div className={styles.container}> <div className={styles.container}>
{availableVaults.map((vault, i) => { {availableVaults.map((vault, i) => {
const borrowAsset = redBankAssets.find((asset) => asset.denom === vault.denoms.secondary) const primaryBorrowAsset = redBankAssets.find(
const maxBorrowRate = Number(borrowAsset?.borrowRate ?? 0) * vault.ltv.max (asset) => asset.denom === vault.denoms.primary,
)
const secondaryBorrowAsset = redBankAssets.find(
(asset) => asset.denom === vault.denoms.secondary,
)
const borrowRate = Math.min(
Number(primaryBorrowAsset?.borrowRate ?? 0),
Number(secondaryBorrowAsset?.borrowRate ?? 0),
)
const maxBorrowRate = borrowRate * (ltvToLeverage(vault.ltv.contract) - 1)
const minAPY = new BigNumber(vault.apy || 0).toNumber() const minAPY = new BigNumber(vault.apy || 0).toNumber()
const leverage = ltvToLeverage(vault.ltv.max) const leverage = ltvToLeverage(vault.ltv.contract)
const maxAPY = const maxAPY =
new BigNumber(minAPY).times(leverage).decimalPlaces(2).toNumber() - maxBorrowRate new BigNumber(minAPY).times(leverage).decimalPlaces(2).toNumber() - maxBorrowRate
const apyDataNoLev = { total: vault.apy || 0, borrow: 0 } const apyDataNoLev = { total: vault.apy || 0, borrow: 0 }
@ -60,7 +69,10 @@ export const AvailableVaultsTableMobile = () => {
hideStyling hideStyling
text={<AnimatedNumber amount={maxAPY} suffix='%' />} text={<AnimatedNumber amount={maxAPY} suffix='%' />}
tooltip={ tooltip={
<Apy apyData={apyDataLev} leverage={ltvToLeverage(vault.ltv.max)} /> <Apy
apyData={apyDataLev}
leverage={ltvToLeverage(vault.ltv.contract)}
/>
} }
/> />
</span> </span>

View File

@ -69,7 +69,7 @@ export const useAvailableVaultsColumns = () => {
return ( return (
<> <>
<p className='m'> <p className='m'>
{formatValue(ltvToLeverage(row.original.ltv.max), 2, 2, false, false, 'x')} {formatValue(ltvToLeverage(row.original.ltv.contract), 2, 2, false, false, 'x')}
</p> </p>
<p className='s faded'>{t('global.max_lower')}</p> <p className='s faded'>{t('global.max_lower')}</p>
</> </>
@ -87,12 +87,20 @@ export const useAvailableVaultsColumns = () => {
return <Loading /> return <Loading />
} }
const maxLeverage = ltvToLeverage(row.original.ltv.max) const maxLeverage = ltvToLeverage(row.original.ltv.contract)
const borrowAsset = redBankAssets.find( const primaryBorrowAsset = redBankAssets.find(
(asset) => asset.denom === row.original.denoms.primary,
)
const secondaryBorrowAsset = redBankAssets.find(
(asset) => asset.denom === row.original.denoms.secondary, (asset) => asset.denom === row.original.denoms.secondary,
) )
const maxBorrowRate =
Number(borrowAsset?.borrowRate ?? 0) * (ltvToLeverage(row.original.ltv.max) - 1) const borrowRate = Math.min(
Number(primaryBorrowAsset?.borrowRate ?? 0),
Number(secondaryBorrowAsset?.borrowRate ?? 0),
)
const maxBorrowRate = borrowRate * (ltvToLeverage(row.original.ltv.contract) - 1)
const minAPY = new BigNumber(row.original.apy).toNumber() const minAPY = new BigNumber(row.original.apy).toNumber()
@ -128,7 +136,7 @@ export const useAvailableVaultsColumns = () => {
/> />
} }
tooltip={ tooltip={
<Apy apyData={apyDataLev} leverage={ltvToLeverage(row.original.ltv.max)} /> <Apy apyData={apyDataLev} leverage={ltvToLeverage(row.original.ltv.contract)} />
} }
/> />

View File

@ -18,7 +18,11 @@ export const BreakdownGraph = (props: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const convertToDisplayCurrency = useStore((s) => s.convertToDisplayCurrency) const convertToDisplayCurrency = useStore((s) => s.convertToDisplayCurrency)
const baseCurrency = useStore((s) => s.baseCurrency) const baseCurrency = useStore((s) => s.baseCurrency)
const yAxisLimit = Math.max(props.position.values.net, props.position.values.borrowed) const borrowKey =
props.position.borrowDenom === props.vault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const yAxisLimit = Math.max(props.position.values.net, props.position.values[borrowKey])
const containerClasses = classNames([ const containerClasses = classNames([
styles.container, styles.container,
@ -40,7 +44,7 @@ export const BreakdownGraph = (props: Props) => {
denom: props.vault.denoms.primary, denom: props.vault.denoms.primary,
}), }),
convertToDisplayCurrency({ convertToDisplayCurrency({
amount: props.position.values.borrowed.toString(), amount: props.position.values[borrowKey].toString(),
denom: props.vault.denoms.primary, denom: props.vault.denoms.primary,
}), }),
], ],
@ -123,7 +127,11 @@ export const BreakdownGraph = (props: Props) => {
<div className={`${styles.bar3}`} style={{ height: `${getBarHeightPercentage(3)}%` }}> <div className={`${styles.bar3}`} style={{ height: `${getBarHeightPercentage(3)}%` }}>
<AssetBar <AssetBar
type='debt' type='debt'
symbol={props.vault.symbols.secondary} symbol={
borrowKey === 'borrowedPrimary'
? props.vault.symbols.primary
: props.vault.symbols.secondary
}
height={getBarHeightPercentage(3)} height={getBarHeightPercentage(3)}
showLabel={hasSpaceForLabel('debt')} showLabel={hasSpaceForLabel('debt')}
/> />

View File

@ -29,6 +29,10 @@
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
td {
min-width: space(12);
}
tr { tr {
td:nth-child(2) { td:nth-child(2) {
width: 20px; width: 20px;

View File

@ -47,10 +47,16 @@ export const BreakdownTable = (props: Props) => {
const primaryPrice = usePrice(props.vault.denoms.primary) const primaryPrice = usePrice(props.vault.denoms.primary)
const secondaryPrice = usePrice(props.vault.denoms.secondary) const secondaryPrice = usePrice(props.vault.denoms.secondary)
const primaryRedBankAsset = useRedBankAsset(props.vault.denoms.primary)
const secondaryRedBankAsset = useRedBankAsset(props.vault.denoms.secondary) const secondaryRedBankAsset = useRedBankAsset(props.vault.denoms.secondary)
const primaryChange = props.newPosition.amounts.primary - props.prevPosition.amounts.primary const primaryChange = props.newPosition.amounts.primary - props.prevPosition.amounts.primary
const secondaryChange = props.newPosition.amounts.secondary - props.prevPosition.amounts.secondary const secondaryChange = props.newPosition.amounts.secondary - props.prevPosition.amounts.secondary
const borrowedChange = props.newPosition.amounts.borrowed - props.prevPosition.amounts.borrowed const borrowKey =
props.newPosition.borrowDenom === props.vault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const borrowedChange =
props.newPosition.amounts[borrowKey] - props.prevPosition.amounts[borrowKey]
const containerClasses = classNames([ const containerClasses = classNames([
props.className, props.className,
@ -71,15 +77,15 @@ export const BreakdownTable = (props: Props) => {
denom = props.vault.denoms.secondary denom = props.vault.denoms.secondary
break break
case AmountType.DEBT: case AmountType.DEBT:
amount = props.newPosition.amounts.borrowed amount = props.newPosition.amounts[borrowKey]
denom = props.vault.denoms.secondary denom = props.vault.denoms.secondary
break break
case AmountType.POSITION_PRIMARY: case AmountType.POSITION_PRIMARY:
amount = props.newPosition.amounts.primary amount = props.newPosition.amounts.primary + props.newPosition.amounts.borrowedPrimary
denom = props.vault.denoms.primary denom = props.vault.denoms.primary
break break
case AmountType.POSITION_SECONDARY: case AmountType.POSITION_SECONDARY:
amount = props.newPosition.amounts.secondary + props.newPosition.amounts.borrowed amount = props.newPosition.amounts.secondary + props.newPosition.amounts.borrowedSecondary
denom = props.vault.denoms.secondary denom = props.vault.denoms.secondary
break break
} }
@ -122,7 +128,9 @@ export const BreakdownTable = (props: Props) => {
) )
} }
const getValueText = (type: 'net' | 'borrowed' | 'total') => ( const getValueText = (
type: 'primary' | 'secondary' | 'net' | 'borrowedPrimary' | 'borrowedSecondary' | 'total',
) => (
<DisplayCurrency <DisplayCurrency
prefixClass='s faded' prefixClass='s faded'
valueClass='m faded' valueClass='m faded'
@ -152,7 +160,8 @@ export const BreakdownTable = (props: Props) => {
) )
} }
const isReducingDebt = props.newPosition.amounts.borrowed < props.prevPosition.amounts.borrowed const isReducingDebt =
props.newPosition.amounts[borrowKey] < props.prevPosition.amounts[borrowKey]
if (isReducingDebt) { if (isReducingDebt) {
return ( return (
<> <>
@ -208,8 +217,12 @@ export const BreakdownTable = (props: Props) => {
/* APY CALCULATION */ /* APY CALCULATION */
const currentLeverage = props.newPosition.currentLeverage const currentLeverage = props.newPosition.currentLeverage
const trueBorrowRate = const borrowRate = Number(
Number(secondaryRedBankAsset?.borrowRate ?? 0) * (Number(currentLeverage) - 1) borrowKey === 'borrowedPrimary'
? primaryRedBankAsset?.borrowRate
: secondaryRedBankAsset?.borrowRate,
)
const trueBorrowRate = borrowRate * (Number(currentLeverage) - 1)
const apy = (props.vault.apy || 0) * currentLeverage - trueBorrowRate const apy = (props.vault.apy || 0) * currentLeverage - trueBorrowRate
@ -291,9 +304,11 @@ export const BreakdownTable = (props: Props) => {
<tr className={styles.debtRow}> <tr className={styles.debtRow}>
<td className={`${styles.showDesktop} faded`}>{t('common.debt')}</td> <td className={`${styles.showDesktop} faded`}>{t('common.debt')}</td>
<td className={styles.alignRight}>{getTokenBalance(AmountType.DEBT)}</td> <td className={styles.alignRight}>{getTokenBalance(AmountType.DEBT)}</td>
<td>{secondaryAsset?.symbol}</td> <td>
{borrowKey === 'borrowedPrimary' ? primaryAsset?.symbol : secondaryAsset?.symbol}
</td>
<td>{getChangeText(borrowedChange, 'secondary', true)}</td> <td>{getChangeText(borrowedChange, 'secondary', true)}</td>
<td>{getValueText('borrowed')}</td> <td>{getValueText(borrowKey)}</td>
</tr> </tr>
<tr className={`${styles.labelRow} faded`}> <tr className={`${styles.labelRow} faded`}>
@ -320,11 +335,14 @@ export const BreakdownTable = (props: Props) => {
</tbody> </tbody>
</table> </table>
{!props.isRepay && <div className={styles.reduceMessage}>{getWarningMessage()}</div>} {!props.isRepay && <div className={styles.reduceMessage}>{getWarningMessage()}</div>}
<BorrowCapacity <BorrowCapacity
className={styles.borrowCapacity} className={styles.borrowCapacity}
limit={maxBorrowValue} limit={maxBorrowValue}
max={getLiqBorrowValue(props.vault, maxBorrowValue)} max={getLiqBorrowValue(props.vault, props.newPosition.values.net)}
balance={props.newPosition.values.borrowed} balance={
props.newPosition.values.borrowedPrimary + props.newPosition.values.borrowedSecondary
}
barHeight={'24px'} barHeight={'24px'}
showPercentageText showPercentageText
/> />

View File

@ -2,6 +2,7 @@ import classNames from 'classnames'
import { Tutorial } from 'components/common' import { Tutorial } from 'components/common'
import { TokenInput } from 'components/fields' import { TokenInput } from 'components/fields'
import { FIELDS_TUTORIAL_KEY } from 'constants/appConstants' import { FIELDS_TUTORIAL_KEY } from 'constants/appConstants'
import { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useStore from 'store' import useStore from 'store'
@ -9,33 +10,106 @@ import styles from './BorrowInput.module.scss'
interface Props { interface Props {
vault: Vault vault: Vault
borrowAmount: number borrowedPrimaryAmount: number
borrowedSecondaryAmount: number
maxAmount: number maxAmount: number
onChange: (amount: number) => void prevPosition?: Position
onChangePrimary: (amount: number) => void
onChangeSecondary: (amount: number) => void
} }
export const BorrowInput = (props: Props) => { export const BorrowInput = (props: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const redBankAssets = useStore((s) => s.redBankAssets) const redBankAssets = useStore((s) => s.redBankAssets)
const showTutorial = !localStorage.getItem(FIELDS_TUTORIAL_KEY) const showTutorial = !localStorage.getItem(FIELDS_TUTORIAL_KEY)
const asset = redBankAssets.find((asset) => asset.denom === props.vault.denoms.secondary) const primaryAsset = redBankAssets.find((asset) => asset.denom === props.vault.denoms.primary)
const secondaryAsset = redBankAssets.find((asset) => asset.denom === props.vault.denoms.secondary)
const containerClasses = classNames([styles.container]) const containerClasses = classNames([styles.container])
const input: Input = { const [cachedPrimaryAmount, setCachedPrimaryAmount] = useState(props.borrowedPrimaryAmount)
visible: true, const [cachedSecondaryAmount, setCachedSecondaryAmount] = useState(props.borrowedSecondaryAmount)
const primaryInputVisisble =
props.borrowedPrimaryAmount > 0 ||
props.prevPosition?.borrowDenom === props.vault.denoms.primary
? true
: false
const [primaryInput, setPrimaryInput] = useState<Input>({
visible: primaryInputVisisble,
denom: props.vault.denoms.primary,
symbol: props.vault.symbols.primary,
})
const [secondaryInput, setSecondaryInput] = useState<Input>({
visible: !primaryInputVisisble,
denom: props.vault.denoms.secondary, denom: props.vault.denoms.secondary,
symbol: props.vault.symbols.secondary, symbol: props.vault.symbols.secondary,
})
const selectInput = (symbol: string) => {
if (symbol === primaryInput.symbol) {
primaryInput.visible = true
secondaryInput.visible = false
setCachedSecondaryAmount(props.borrowedSecondaryAmount)
props.onChangePrimary(cachedPrimaryAmount)
} else {
primaryInput.visible = false
secondaryInput.visible = true
setCachedPrimaryAmount(props.borrowedPrimaryAmount)
props.onChangeSecondary(cachedSecondaryAmount)
}
setPrimaryInput({ ...primaryInput })
setSecondaryInput({ ...secondaryInput })
}
const onChangePrimary = (amount: number) => {
setCachedPrimaryAmount(amount)
props.onChangePrimary(amount)
}
const onChangeSecondary = (amount: number) => {
setCachedSecondaryAmount(amount)
props.onChangeSecondary(amount)
} }
const tokenInput = ( const tokenInput = (
<TokenInput <>
input={input} {primaryInput.visible && (
amount={props.borrowAmount} <TokenInput
maxAmount={props.maxAmount} input={primaryInput}
maxAmountLabel={t('global.max')} amount={props.borrowedPrimaryAmount}
onChange={props.onChange} onChange={onChangePrimary}
tokens={[props.vault.symbols.secondary]} tokens={
borrowRate={asset?.borrowRate} props.prevPosition?.borrowDenom === props.vault.denoms.primary
/> ? [primaryInput.symbol]
: [primaryInput.symbol, secondaryInput.symbol]
}
onSelect={selectInput}
maxAmountLabel={t('global.max')}
maxAmount={props.maxAmount}
borrowRate={primaryAsset?.borrowRate}
disableGasWarning
/>
)}
{secondaryInput.visible && (
<TokenInput
input={secondaryInput}
amount={props.borrowedSecondaryAmount}
onChange={onChangeSecondary}
tokens={
props.prevPosition?.borrowDenom === props.vault.denoms.secondary
? [secondaryInput.symbol]
: [primaryInput.symbol, secondaryInput.symbol]
}
onSelect={selectInput}
maxAmountLabel={t('global.max')}
maxAmount={props.maxAmount}
borrowRate={secondaryAsset?.borrowRate}
disableGasWarning
/>
)}
</>
) )
return ( return (

View File

@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js'
import classNames from 'classnames' import classNames from 'classnames'
import { InputSlider, Tutorial } from 'components/common' import { InputSlider, Tutorial } from 'components/common'
import { FIELDS_TUTORIAL_KEY } from 'constants/appConstants' import { FIELDS_TUTORIAL_KEY } from 'constants/appConstants'
import { formatValue, ltvToLeverage } from 'libs/parse' import { formatValue, leverageToLtv, ltvToLeverage } from 'libs/parse'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import colors from 'styles/_assets.module.scss' import colors from 'styles/_assets.module.scss'
@ -29,7 +29,7 @@ export const LeverageSlider = (props: Props) => {
isLeverage isLeverage
value={props.leverage} value={props.leverage}
maxValue={props.leverageMax} maxValue={props.leverageMax}
leverageMax={ltvToLeverage(props.vault.ltv.max)} leverageMax={ltvToLeverage(props.vault.ltv.contract)}
leverageLimit={props.leverageLimit} leverageLimit={props.leverageLimit}
onChange={props.onChange} onChange={props.onChange}
sliderColor={colors.secondary} sliderColor={colors.secondary}
@ -51,8 +51,11 @@ export const LeverageSlider = (props: Props) => {
) : ( ) : (
<>{slider}</> <>{slider}</>
)} )}
{leverageToLtv(props.leverage) > props.vault.ltv.max && (
<span className={styles.warning}>{t('fields.messages.closeToMaxLtv')}</span>
)}
{props.leverage >= props.leverageLimit && {props.leverage >= props.leverageLimit &&
props.leverageLimit < ltvToLeverage(props.vault.ltv.max) && ( props.leverageLimit < ltvToLeverage(props.vault.ltv.contract) && (
<span className={styles.warning}> <span className={styles.warning}>
{t('fields.messages.unableToIncreaseLeverage', { {t('fields.messages.unableToIncreaseLeverage', {
leverage: formatValue(props.leverageLimit, 2, 2), leverage: formatValue(props.leverageLimit, 2, 2),

View File

@ -54,6 +54,6 @@
@media only screen and (min-width: $bpMediumHigh) { @media only screen and (min-width: $bpMediumHigh) {
.grid { .grid {
grid-template-areas: 'supply leverage borrow'; grid-template-areas: 'supply leverage borrow';
grid-template-columns: auto 2fr 1fr; grid-auto-columns: auto;
} }
} }

View File

@ -20,7 +20,9 @@ export const PositionInput = (props: Props) => {
const marketAssetLiquidity = useStore((s) => s.marketAssetLiquidity) const marketAssetLiquidity = useStore((s) => s.marketAssetLiquidity)
const convertToBaseCurrency = useStore((s) => s.convertToBaseCurrency) const convertToBaseCurrency = useStore((s) => s.convertToBaseCurrency)
const convertValueToAmount = useStore((s) => s.convertValueToAmount) const convertValueToAmount = useStore((s) => s.convertValueToAmount)
const [maxAllowedLeverage, setMaxAllowedLeverage] = useState(ltvToLeverage(props.vault.ltv.max)) const [maxAllowedLeverage, setMaxAllowedLeverage] = useState(
ltvToLeverage(props.vault.ltv.contract),
)
const tutorialStep = useStore((s) => s.tutorialSteps['fields']) const tutorialStep = useStore((s) => s.tutorialSteps['fields'])
const showTutorial = !localStorage.getItem(FIELDS_TUTORIAL_KEY) const showTutorial = !localStorage.getItem(FIELDS_TUTORIAL_KEY)
@ -33,13 +35,26 @@ export const PositionInput = (props: Props) => {
denom: props.vault.denoms.secondary, denom: props.vault.denoms.secondary,
amount: position.amounts.secondary.toString(), amount: position.amounts.secondary.toString(),
}) })
const borrowValue = convertToBaseCurrency({ const borrowedPrimaryValue = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.vault.denoms.primary,
amount: position.amounts.borrowed.toString(), amount: position.amounts.borrowedPrimary.toString(),
}) })
position.values.borrowed = borrowValue const borrowedSecondaryValue = convertToBaseCurrency({
position.values.total = borrowValue + primaryValue + secondaryValue denom: props.vault.denoms.secondary,
amount: position.amounts.borrowedSecondary.toString(),
})
position.values.borrowedPrimary = borrowedPrimaryValue
position.values.borrowedSecondary = borrowedSecondaryValue
position.values.total =
borrowedPrimaryValue + borrowedSecondaryValue + primaryValue + secondaryValue
position.values.net = primaryValue + secondaryValue position.values.net = primaryValue + secondaryValue
if (borrowedPrimaryValue > 0) {
props.position.borrowDenom = props.vault.denoms.primary
} else if (borrowedSecondaryValue > 0) {
props.position.borrowDenom = props.vault.denoms.secondary
}
return position return position
} }
@ -53,20 +68,27 @@ export const PositionInput = (props: Props) => {
computeBorrowAmount() computeBorrowAmount()
} }
const onBorrowChange = (amount: number) => { const onBorrowChange = (amount: number, type: 'primary' | 'secondary') => {
props.position.borrowDenom =
type === 'primary' ? props.vault.denoms.primary : props.vault.denoms.secondary
const borrowValue = convertToBaseCurrency({ const borrowValue = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.position.borrowDenom,
amount: amount.toString(), amount: amount.toString(),
}) })
props.position.amounts.borrowed = amount const borrowKey = type === 'primary' ? 'borrowedPrimary' : 'borrowedSecondary'
props.position.values.borrowed = borrowValue const secondaryBorrowKey = type !== 'primary' ? 'borrowedPrimary' : 'borrowedSecondary'
props.position.amounts[borrowKey] = amount
props.position.amounts[secondaryBorrowKey] = 0
props.position.values[borrowKey] = borrowValue
props.position.values[secondaryBorrowKey] = 0
props.position.currentLeverage = getLeverageFromValues(props.position.values) props.position.currentLeverage = getLeverageFromValues(props.position.values)
props.setPosition({ ...updateValues(props.position) }) props.setPosition({ ...updateValues(props.position) })
computeBorrowAmount()
} }
const computeMaxAllowedLeverage = () => { const computeMaxAllowedLeverage = () => {
const maxBorrowValue = convertToBaseCurrency({ const maxBorrowValue = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.position.borrowDenom || props.vault.denoms.secondary,
amount: computeMaxBorrowAmount().toString(), amount: computeMaxBorrowAmount().toString(),
}) })
@ -76,16 +98,20 @@ export const PositionInput = (props: Props) => {
props.position.values.primary, props.position.values.primary,
props.position.values.secondary, props.position.values.secondary,
) )
: ltvToLeverage(props.vault.ltv.max) : ltvToLeverage(props.vault.ltv.contract)
} }
const computeBorrowAmount = (leverage?: number) => { const computeBorrowAmount = (leverage?: number) => {
const supplyBorrowRatio = leverage ? leverage - 1 : props.position.currentLeverage - 1 const supplyBorrowRatio = leverage ? leverage - 1 : props.position.currentLeverage - 1
const supplyValue = props.position.values.primary + props.position.values.secondary const supplyValue = props.position.values.primary + props.position.values.secondary
const borrowValue = new BigNumber(supplyValue).times(supplyBorrowRatio).toNumber() const borrowValue = new BigNumber(supplyValue).times(supplyBorrowRatio).toNumber()
const borrowDenom = props.position.borrowDenom
? props.position.borrowDenom
: props.vault.denoms.secondary
const borrowAmount = Math.floor( const borrowAmount = Math.floor(
convertValueToAmount({ convertValueToAmount({
denom: props.vault.denoms.secondary, denom: borrowDenom,
amount: borrowValue.toString(), amount: borrowValue.toString(),
}), }),
) )
@ -97,12 +123,15 @@ export const PositionInput = (props: Props) => {
: props.position.currentLeverage : props.position.currentLeverage
const maxAllowedLeverage = computeMaxAllowedLeverage() const maxAllowedLeverage = computeMaxAllowedLeverage()
const borrowKey =
borrowDenom === props.vault.denoms.primary ? 'borrowedPrimary' : 'borrowedSecondary'
if (targetLeverage > maxAllowedLeverage) { if (targetLeverage > maxAllowedLeverage) {
const borrowAmount = computeMaxBorrowAmount() const borrowAmount = computeMaxBorrowAmount()
props.position.amounts.borrowed = borrowAmount props.position.amounts[borrowKey] = borrowAmount
props.position.currentLeverage = maxAllowedLeverage props.position.currentLeverage = maxAllowedLeverage
} else { } else {
props.position.amounts.borrowed = borrowAmount props.position.amounts[borrowKey] = borrowAmount
props.position.currentLeverage = targetLeverage props.position.currentLeverage = targetLeverage
} }
@ -111,25 +140,28 @@ export const PositionInput = (props: Props) => {
} }
const computeMaxBorrowAmount = () => { const computeMaxBorrowAmount = () => {
const borrowDenom = props.position.borrowDenom || props.vault.denoms.secondary
const maxAmount = Math.floor( const maxAmount = Math.floor(
convertValueToAmount({ convertValueToAmount({
denom: props.vault.denoms.secondary, denom: borrowDenom,
amount: getMaxBorrowValue(props.vault, props.position).toString(), amount: getMaxBorrowValue(props.vault, props.position).toString(),
}), }),
) )
const marketLiquidity = Number( const marketLiquidity = Number(
marketAssetLiquidity.find((market) => market.denom === props.vault.denoms.secondary) marketAssetLiquidity.find((market) => market.denom === borrowDenom)?.amount || 0,
?.amount || 0,
) )
const borrowKey =
borrowDenom === props.vault.denoms.primary ? 'borrowedPrimary' : 'borrowedSecondary'
const maxBorrowAmount = Math.min( const maxBorrowAmount = Math.min(
maxAmount, maxAmount,
(props.prevPosition?.amounts.borrowed || 0) + marketLiquidity, (props.prevPosition?.amounts[borrowKey] || 0) + marketLiquidity,
) )
if (props.prevPosition) { if (props.prevPosition) {
return Math.max(maxBorrowAmount, props.prevPosition.amounts.borrowed) return Math.max(maxBorrowAmount, props.prevPosition.amounts[borrowKey])
} }
return maxBorrowAmount return maxBorrowAmount
@ -154,7 +186,7 @@ export const PositionInput = (props: Props) => {
leverage={props.position.currentLeverage || 1} leverage={props.position.currentLeverage || 1}
leverageLimit={maxAllowedLeverage} leverageLimit={maxAllowedLeverage}
leverageMax={Math.max( leverageMax={Math.max(
ltvToLeverage(props.vault.ltv.max), ltvToLeverage(props.vault.ltv.contract),
props.prevPosition?.currentLeverage || 1, props.prevPosition?.currentLeverage || 1,
)} )}
onChange={computeBorrowAmount} onChange={computeBorrowAmount}
@ -162,10 +194,13 @@ export const PositionInput = (props: Props) => {
</Highlight> </Highlight>
<Highlight show={tutorialStep === 3 || !showTutorial} className={styles.borrow}> <Highlight show={tutorialStep === 3 || !showTutorial} className={styles.borrow}>
<BorrowInput <BorrowInput
borrowAmount={props.position.amounts.borrowed} borrowedPrimaryAmount={props.position.amounts.borrowedPrimary}
onChange={onBorrowChange} borrowedSecondaryAmount={props.position.amounts.borrowedSecondary}
onChangePrimary={(amount) => onBorrowChange(amount, 'primary')}
onChangeSecondary={(amount) => onBorrowChange(amount, 'secondary')}
maxAmount={computeMaxBorrowAmount()} maxAmount={computeMaxBorrowAmount()}
vault={props.vault} vault={props.vault}
prevPosition={props.prevPosition}
/> />
</Highlight> </Highlight>
</div> </div>

View File

@ -5,6 +5,7 @@
flex-direction: column; flex-direction: column;
gap: space(2); gap: space(2);
flex: 1; flex: 1;
min-width: rem-calc(160);
.input { .input {
display: flex; display: flex;

View File

@ -16,6 +16,7 @@ interface Props {
maxAmount?: number maxAmount?: number
maxAmountLabel: string maxAmountLabel: string
borrowRate?: number borrowRate?: number
disableGasWarning?: boolean
onChange: (amount: number) => void onChange: (amount: number) => void
onSelect?: (denom: string) => void onSelect?: (denom: string) => void
} }
@ -62,7 +63,10 @@ export const TokenInput = (props: Props) => {
10 ** asset.decimals 10 ** asset.decimals
const showGasWarning = const showGasWarning =
props.maxAmount && props.amount >= props.maxAmount && asset.denom === baseCurrency.denom props.maxAmount &&
props.amount >= props.maxAmount &&
asset.denom === baseCurrency.denom &&
!props.disableGasWarning
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>

View File

@ -19,18 +19,28 @@ interface Props {
export const RepayInput = (props: Props) => { export const RepayInput = (props: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const convertToBaseCurrency = useStore((s) => s.convertToBaseCurrency) const convertToBaseCurrency = useStore((s) => s.convertToBaseCurrency)
const debtAmount = props.prevPosition.amounts.borrowed const borrowKey =
props.position.borrowDenom === props.vault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const supplyKey = borrowKey === 'borrowedPrimary' ? 'primary' : 'secondary'
const debtAmount = props.prevPosition.amounts[borrowKey]
const userBalances = useStore((s) => s.userBalances) const userBalances = useStore((s) => s.userBalances)
const borrowSymbol =
props.position.borrowDenom === props.vault.denoms.primary
? props.vault.symbols.primary
: props.vault.symbols.secondary
const walletBalance = Number( const walletBalance = Number(
(findByDenom(userBalances, props.vault.denoms.secondary) as Coin)?.amount || 0, (findByDenom(userBalances, props.vault.denoms.secondary) as Coin)?.amount || 0,
) )
const maxRepayAmount = Math.min(walletBalance, debtAmount) const maxRepayAmount = Math.min(walletBalance, debtAmount)
const amount = props.prevPosition.amounts.borrowed - props.position.amounts.borrowed const amount = props.prevPosition.amounts[borrowKey] - props.position.amounts[borrowKey]
const maxValue = Math.max( const maxValue = Math.max(
getLeverageFromValues(props.prevPosition.values), getLeverageFromValues(props.prevPosition.values),
ltvToLeverage(props.vault.ltv.max), ltvToLeverage(props.vault.ltv.contract),
) )
const updateValues = (position: Position) => { const updateValues = (position: Position) => {
@ -42,21 +52,29 @@ export const RepayInput = (props: Props) => {
denom: props.vault.denoms.secondary, denom: props.vault.denoms.secondary,
amount: position.amounts.secondary.toString(), amount: position.amounts.secondary.toString(),
}) })
const borrowValue = convertToBaseCurrency({ const borrowedPrimaryValue = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.vault.denoms.primary,
amount: position.amounts.borrowed.toString(), amount: position.amounts.borrowedPrimary.toString(),
}) })
const borrowedSecondaryValue = convertToBaseCurrency({
denom: props.vault.denoms.secondary,
amount: position.amounts.borrowedSecondary.toString(),
})
position.values.primary = primaryValue
position.values.secondary = secondaryValue position.values.secondary = secondaryValue
position.values.borrowed = borrowValue position.values.borrowedPrimary = borrowedPrimaryValue
position.values.total = borrowValue + primaryValue + secondaryValue position.values.borrowedSecondary = borrowedSecondaryValue
position.values.total =
borrowedPrimaryValue + borrowedSecondaryValue + primaryValue + secondaryValue
position.values.net = primaryValue + secondaryValue position.values.net = primaryValue + secondaryValue
position.currentLeverage = getLeverageFromValues(position.values) position.currentLeverage = getLeverageFromValues(position.values)
return position return position
} }
const handleChange = (amount: number) => { const handleChange = (amount: number) => {
props.position.amounts.borrowed = props.prevPosition.amounts.borrowed - amount props.position.amounts[borrowKey] = props.prevPosition.amounts[borrowKey] - amount
props.position.amounts.secondary = props.prevPosition.amounts.secondary + amount props.position.amounts[supplyKey] = props.prevPosition.amounts[supplyKey] + amount
props.setPosition({ ...updateValues(props.position) }) props.setPosition({ ...updateValues(props.position) })
} }
@ -66,21 +84,22 @@ export const RepayInput = (props: Props) => {
<p className={styles.headline}>{t('fields.repayDebt')}</p> <p className={styles.headline}>{t('fields.repayDebt')}</p>
<TokenInput <TokenInput
amount={amount} amount={amount}
tokens={[props.vault.symbols.secondary]} tokens={[borrowSymbol]}
input={{ input={{
denom: props.vault.denoms.secondary, denom: props.position.borrowDenom || props.vault.denoms.secondary,
symbol: props.vault.symbols.secondary, symbol: borrowSymbol,
visible: true, visible: true,
}} }}
maxAmount={maxRepayAmount} maxAmount={maxRepayAmount}
maxAmountLabel={t('global.max')} maxAmountLabel={t('global.max')}
onChange={handleChange} onChange={handleChange}
disableGasWarning
/> />
</div> </div>
<RepayLeverage <RepayLeverage
value={props.position.currentLeverage} value={props.position.currentLeverage}
maxValue={maxValue} maxValue={maxValue}
leverageMax={ltvToLeverage(props.vault.ltv.max)} leverageMax={ltvToLeverage(props.vault.ltv.contract)}
/> />
<div> <div>
<strong className='m'>{t('fields.repayingDebtFromWallet')}</strong> <strong className='m'>{t('fields.repayingDebtFromWallet')}</strong>

View File

@ -91,6 +91,12 @@ export const AssetTable = ({ data, columns, type, disabled = false }: Props) =>
</thead> </thead>
<tbody> <tbody>
{table.getRowModel().rows.map((row) => { {table.getRowModel().rows.map((row) => {
if (
(type === 'deposit' && !row.original.depositEnabled) ||
(type === 'borrow' && !row.original.borrowEnabled)
)
return null
if (row.depth === 1) { if (row.depth === 1) {
return ( return (
<React.Fragment key={`${row.id}_subrow`}> <React.Fragment key={`${row.id}_subrow`}>

View File

@ -86,14 +86,16 @@ export const MetricsRow = ({ row, type }: Props) => {
valueClass='s' valueClass='s'
labelClass='xs faded' labelClass='xs faded'
/> />
<ValueWithLabel {row.original.borrowEnabled && (
percent={utilizationRatePercent} <ValueWithLabel
label={t('redbank.utilizationRate')} percent={utilizationRatePercent}
orientation='left' label={t('redbank.utilizationRate')}
prefixClass='xxs faded prefix' orientation='left'
valueClass='s' prefixClass='xxs faded prefix'
labelClass='xs faded' valueClass='s'
/> labelClass='xs faded'
/>
)}
</div> </div>
</div> </div>
</td> </td>

View File

@ -70,17 +70,15 @@ export const useBorrowColumns = () => {
header: () => ( header: () => (
<TextTooltip text={t('common.rate')} tooltip={t('redbank.tooltips.borrow.rate')} /> <TextTooltip text={t('common.rate')} tooltip={t('redbank.tooltips.borrow.rate')} />
), ),
cell: (info) => { cell: (info) => (
return ( <AnimatedNumber
<AnimatedNumber amount={info.getValue()}
amount={info.getValue()} suffix='%'
suffix='%' abbreviated={false}
abbreviated={false} rounded={false}
rounded={false} className='m'
className='m' />
/> ),
)
},
}), }),
columnHelper.accessor('marketLiquidity', { columnHelper.accessor('marketLiquidity', {
enableSorting: enableSorting, enableSorting: enableSorting,
@ -100,15 +98,13 @@ export const useBorrowColumns = () => {
}), }),
columnHelper.display({ columnHelper.display({
id: 'actions', id: 'actions',
cell: ({ row }) => { cell: ({ row }) => (
return ( <Button
<Button color='quaternary'
color='quaternary' prefix={row.getIsExpanded() ? <SVG.Collapse /> : <SVG.Expand />}
prefix={row.getIsExpanded() ? <SVG.Collapse /> : <SVG.Expand />} variant='round'
variant='round' />
/> ),
)
},
}), }),
], ],
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps

View File

@ -18,6 +18,10 @@
&.axlUSDC { &.axlUSDC {
background-image: $colorGradientAxlUSDC; background-image: $colorGradientAxlUSDC;
} }
&.stATOM {
background-image: $colorGradientStATOM;
}
} }
.logo { .logo {
@ -25,3 +29,8 @@
margin: auto; margin: auto;
width: rem-calc(32); width: rem-calc(32);
} }
.notBorrowable {
width: 100%;
display: block;
}

View File

@ -59,37 +59,45 @@ export const useDepositColumns = () => {
tooltip={t('redbank.tooltips.deposit.deposited')} tooltip={t('redbank.tooltips.deposit.deposited')}
/> />
), ),
cell: (info) => { cell: (info) => (
return ( <CellAmount
<CellAmount amount={Number(info.row.original.depositBalance)}
amount={Number(info.row.original.depositBalance)} decimals={info.row.original.decimals}
decimals={info.row.original.decimals} denom={info.row.original.denom}
denom={info.row.original.denom} noBalanceText={t('common.noDeposit')}
noBalanceText={t('common.noDeposit')} />
/> ),
)
},
}), }),
columnHelper.accessor('apy', { columnHelper.accessor('apy', {
enableSorting: enableSorting, enableSorting: enableSorting,
header: () => ( header: () => (
<TextTooltip text={t('common.apr')} tooltip={t('redbank.tooltips.deposit.apy')} /> <TextTooltip text={t('common.apr')} tooltip={t('redbank.tooltips.deposit.apy')} />
), ),
cell: (info) => ( cell: (info) =>
<TextTooltip info.row.original.borrowEnabled ? (
hideStyling <TextTooltip
text={ hideStyling
<AnimatedNumber text={
amount={info.getValue() + Number(info.row.original.incentiveInfo?.apy || 0)} <AnimatedNumber
suffix='%' amount={info.getValue() + Number(info.row.original.incentiveInfo?.apy || 0)}
abbreviated={false} suffix='%'
rounded={false} abbreviated={false}
className='m' rounded={false}
/> className='m'
} />
tooltip={<Apr data={info.row.original} />} }
/> tooltip={<Apr data={info.row.original} />}
), />
) : (
<TextTooltip
text=''
hideUnderline
className={styles.notBorrowable}
tooltip={t('redbank.tooltips.deposit.notBorrowable', {
symbol: info.row.original.symbol,
})}
/>
),
}), }),
columnHelper.accessor('depositCap', { columnHelper.accessor('depositCap', {
enableSorting: enableSorting, enableSorting: enableSorting,
@ -108,7 +116,6 @@ export const useDepositColumns = () => {
'faded', 'faded',
percent >= 100 ? 'colorInfoLoss' : '', percent >= 100 ? 'colorInfoLoss' : '',
) )
return ( return (
<> <>
<p className='number'> <p className='number'>
@ -129,15 +136,13 @@ export const useDepositColumns = () => {
}), }),
columnHelper.display({ columnHelper.display({
id: 'actions', id: 'actions',
cell: ({ row }) => { cell: ({ row }) => (
return ( <Button
<Button color='quaternary'
color='quaternary' prefix={row.getIsExpanded() ? <SVG.Collapse /> : <SVG.Expand />}
prefix={row.getIsExpanded() ? <SVG.Collapse /> : <SVG.Expand />} variant='round'
variant='round' />
/> ),
)
},
}), }),
] ]
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps

View File

@ -42,6 +42,8 @@ export const RedbankNotConnected = () => {
depositBalanceBaseCurrency: 0, depositBalanceBaseCurrency: 0,
depositCap: 0, depositCap: 0,
depositLiquidity: 0, depositLiquidity: 0,
borrowEnabled: true,
depositEnabled: true,
}) })
}) })

View File

@ -14,7 +14,6 @@ export const ASSETS: { [denom: string]: Asset } = {
denom: 'uosmo', denom: 'uosmo',
color: colors.osmo, color: colors.osmo,
decimals: 6, decimals: 6,
hasOraclePrice: true,
logo: osmo, logo: osmo,
poolId: 678, poolId: 678,
}, },
@ -25,7 +24,6 @@ export const ASSETS: { [denom: string]: Asset } = {
color: colors.atom, color: colors.atom,
logo: atom, logo: atom,
decimals: 6, decimals: 6,
hasOraclePrice: true,
}, },
juno: { juno: {
symbol: 'JUNO', symbol: 'JUNO',
@ -34,7 +32,6 @@ export const ASSETS: { [denom: string]: Asset } = {
color: colors.juno, color: colors.juno,
logo: juno, logo: juno,
decimals: 6, decimals: 6,
hasOraclePrice: true,
}, },
} }
@ -46,7 +43,6 @@ const OTHER_ASSETS: { [denom: string]: OtherAsset } = {
color: colors.mars, color: colors.mars,
logo: mars, logo: mars,
decimals: 6, decimals: 6,
hasOraclePrice: true,
poolId: 768, poolId: 768,
}, },
axlusdc: { axlusdc: {
@ -57,7 +53,6 @@ const OTHER_ASSETS: { [denom: string]: OtherAsset } = {
color: colors.axlusdc, color: colors.axlusdc,
logo: axlusdc, logo: axlusdc,
decimals: 6, decimals: 6,
hasOraclePrice: false,
poolId: 674, poolId: 674,
}, },
} }
@ -70,6 +65,7 @@ export const NETWORK_CONFIG: NetworkConfig = {
rpcUrl: URL_RPC ?? 'https://rpc-test.osmosis.zone/', rpcUrl: URL_RPC ?? 'https://rpc-test.osmosis.zone/',
restUrl: URL_REST ?? 'https://lcd-test.osmosis.zone/', restUrl: URL_REST ?? 'https://lcd-test.osmosis.zone/',
apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmo-test-4', apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmo-test-4',
priceApiUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
contracts: { contracts: {
redBank: 'osmo1t0dl6r27phqetfu0geaxrng0u9zn8qgrdwztapt5xr32adtwptaq6vwg36', redBank: 'osmo1t0dl6r27phqetfu0geaxrng0u9zn8qgrdwztapt5xr32adtwptaq6vwg36',
incentives: 'osmo1zxs8fry3m8j94pqg7h4muunyx86en27cl0xgk76fc839xg2qnn6qtpjs48', incentives: 'osmo1zxs8fry3m8j94pqg7h4muunyx86en27cl0xgk76fc839xg2qnn6qtpjs48',
@ -93,30 +89,6 @@ export const NETWORK_CONFIG: NetworkConfig = {
} }
export const VAULT_CONFIGS: Vault[] = [ export const VAULT_CONFIGS: Vault[] = [
{
address: 'osmo1zktjv92f76epswjvyxzzt3yyskpw7k6jsyu0kmq4zzc5fphrjumqlahctp',
name: 'OSMO-ATOM LP (1 day)',
denoms: {
primary: 'uosmo',
secondary: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
lpToken: 'gamm/pool/1',
},
symbols: {
primary: 'OSMO',
secondary: 'ATOM',
},
color: '#DD5B65',
lockup: 86400,
provider: 'Apollo vault',
description:
'Up to 2.67× leveraged yield farming with auto compounding of the OSMO-ATOM LP tokens.',
ltv: {
max: 0.625,
contract: 0.63,
liq: 0.65,
},
apy: 0,
},
{ {
address: 'osmo1tp2m6g39h8mvhnu3plqjyen5s63023gj8w873l8wvly0cd77l6hsaa73wt', address: 'osmo1tp2m6g39h8mvhnu3plqjyen5s63023gj8w873l8wvly0cd77l6hsaa73wt',
name: 'OSMO-ATOM LP (14 day)', name: 'OSMO-ATOM LP (14 day)',
@ -133,11 +105,11 @@ export const VAULT_CONFIGS: Vault[] = [
lockup: 86400 * 14, lockup: 86400 * 14,
provider: 'Apollo vault', provider: 'Apollo vault',
description: description:
'Up to 2.67× leveraged yield farming with auto compounding of the OSMO-ATOM LP tokens.', 'Up to 1.43× leveraged yield farming with auto compounding of the OSMO-ATOM LP tokens.',
ltv: { ltv: {
max: 0.625, max: 0.295,
contract: 0.63, contract: 0.3,
liq: 0.65, liq: 0.4,
}, },
apy: 0, apy: 0,
}, },
@ -157,11 +129,11 @@ export const VAULT_CONFIGS: Vault[] = [
lockup: 86400 * 1, lockup: 86400 * 1,
provider: 'Apollo vault', provider: 'Apollo vault',
description: description:
'Up to 1.67× leveraged yield farming with auto compounding of the OSMO-JUNO LP tokens.', 'Up to 1.43× leveraged yield farming with auto compounding of the OSMO-JUNO LP tokens.',
ltv: { ltv: {
max: 0.4, max: 0.295,
contract: 0.4115, contract: 0.3,
liq: 0.441, liq: 0.4,
}, },
apy: 0, apy: 0,
}, },
@ -181,11 +153,11 @@ export const VAULT_CONFIGS: Vault[] = [
lockup: 86400 * 14, lockup: 86400 * 14,
provider: 'Apollo vault', provider: 'Apollo vault',
description: description:
'Up to 1.67× leveraged yield farming with auto compounding of the OSMO-JUNO LP tokens.', 'Up to 1.43× leveraged yield farming with auto compounding of the OSMO-JUNO LP tokens.',
ltv: { ltv: {
max: 0.4, max: 0.295,
contract: 4.115, contract: 0.3,
liq: 0.441, liq: 0.4,
}, },
apy: 0, apy: 0,
}, },

View File

@ -4,6 +4,7 @@ import atom from 'images/atom.svg'
import axlusdc from 'images/axlusdc.svg' import axlusdc from 'images/axlusdc.svg'
import mars from 'images/mars.svg' import mars from 'images/mars.svg'
import osmo from 'images/osmo.svg' import osmo from 'images/osmo.svg'
import statom from 'images/statom.svg'
import colors from 'styles/_assets.module.scss' import colors from 'styles/_assets.module.scss'
export const ASSETS: { [denom: string]: Asset } = { export const ASSETS: { [denom: string]: Asset } = {
@ -13,17 +14,15 @@ export const ASSETS: { [denom: string]: Asset } = {
denom: 'uosmo', denom: 'uosmo',
color: colors.osmo, color: colors.osmo,
decimals: 6, decimals: 6,
hasOraclePrice: true,
logo: osmo, logo: osmo,
}, },
axlusdc: { axlusdc: {
symbol: 'axlUSDC', symbol: 'axlUSDC',
name: 'Axelar USDC', name: 'Axelar USDC',
denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858', denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858',
color: colors.axlUSDC, color: colors.axlusdc,
logo: axlusdc, logo: axlusdc,
decimals: 6, decimals: 6,
hasOraclePrice: true,
poolId: 678, poolId: 678,
}, },
atom: { atom: {
@ -33,7 +32,16 @@ export const ASSETS: { [denom: string]: Asset } = {
color: colors.atom, color: colors.atom,
logo: atom, logo: atom,
decimals: 6, decimals: 6,
hasOraclePrice: true, },
statom: {
symbol: 'stATOM',
name: 'Stride Atom',
denom: 'ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901',
color: colors.statom,
logo: statom,
decimals: 6,
poolId: 803,
poolBase: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
}, },
} }
@ -45,7 +53,6 @@ const OTHER_ASSETS: { [denom: string]: OtherAsset } = {
color: colors.mars, color: colors.mars,
logo: mars, logo: mars,
decimals: 6, decimals: 6,
hasOraclePrice: true,
poolId: 907, poolId: 907,
}, },
} }
@ -57,6 +64,7 @@ export const NETWORK_CONFIG: NetworkConfig = {
rpcUrl: URL_RPC ?? 'https://rpc-osmosis.blockapsis.com/', rpcUrl: URL_RPC ?? 'https://rpc-osmosis.blockapsis.com/',
restUrl: URL_REST ?? 'https://lcd-osmosis.blockapsis.com/', restUrl: URL_REST ?? 'https://lcd-osmosis.blockapsis.com/',
apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmosis-1', apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmosis-1',
priceApiUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
contracts: { contracts: {
redBank: 'osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p9tenkrryasrle5sqf3ftpg', redBank: 'osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p9tenkrryasrle5sqf3ftpg',
incentives: 'osmo1nkahswfr8shg8rlxqwup0vgahp0dk4x8w6tkv3rra8rratnut36sk22vrm', incentives: 'osmo1nkahswfr8shg8rlxqwup0vgahp0dk4x8w6tkv3rra8rratnut36sk22vrm',
@ -66,7 +74,7 @@ export const NETWORK_CONFIG: NetworkConfig = {
}, },
assets: { assets: {
base: ASSETS.osmo, base: ASSETS.osmo,
whitelist: [ASSETS.osmo, ASSETS.atom, ASSETS.axlusdc], whitelist: [ASSETS.osmo, ASSETS.atom, ASSETS.axlusdc, ASSETS.statom],
other: [OTHER_ASSETS.mars], other: [OTHER_ASSETS.mars],
}, },
displayCurrency: { displayCurrency: {
@ -129,7 +137,7 @@ export const VAULT_CONFIGS: Vault[] = [
description: description:
'Up to 2.78× leveraged yield farming with auto compounding of the OSMO-axlUSDC LP tokens.', 'Up to 2.78× leveraged yield farming with auto compounding of the OSMO-axlUSDC LP tokens.',
ltv: { ltv: {
max: 0.64, max: 0.645,
contract: 0.65, contract: 0.65,
liq: 0.66, liq: 0.66,
}, },

View File

@ -5,6 +5,7 @@ export const FORUM_URL = 'https://forum.marsprotocol.io/'
export const MARS_SYMBOL = 'MARS' export const MARS_SYMBOL = 'MARS'
export const MARS_DECIMALS = 6 export const MARS_DECIMALS = 6
export const USDC_SYMBOL = 'axlUSDC' export const USDC_SYMBOL = 'axlUSDC'
export const STATOM_SYMBOL = 'stATOM'
/* borrow capacity */ /* borrow capacity */
export const DEFAULT_SLIPPAGE = 0.01 export const DEFAULT_SLIPPAGE = 0.01

View File

@ -4,7 +4,8 @@ export const DEFAULT_POSITION: Position = {
amounts: { amounts: {
primary: 0, primary: 0,
secondary: 0, secondary: 0,
borrowed: 0, borrowedPrimary: 0,
borrowedSecondary: 0,
lp: { lp: {
amount: '0', amount: '0',
primary: 0, primary: 0,
@ -15,7 +16,8 @@ export const DEFAULT_POSITION: Position = {
values: { values: {
primary: 0, primary: 0,
secondary: 0, secondary: 0,
borrowed: 0, borrowedPrimary: 0,
borrowedSecondary: 0,
total: 0, total: 0,
net: 0, net: 0,
}, },
@ -26,4 +28,5 @@ export const DEFAULT_POSITION: Position = {
}, },
ltv: 0.5, ltv: 0.5,
currentLeverage: 1, currentLeverage: 1,
borrowDenom: null,
} }

View File

@ -8,7 +8,10 @@ export const getClosePositionActions = (
const swapMessage: Action[] = [] const swapMessage: Action[] = []
// Increase the borrow amount by factor to account for an increase of borrow over time // Increase the borrow amount by factor to account for an increase of borrow over time
const borrowAmount = Math.ceil(vault.position.amounts.borrowed * 1.001) const borrowAmount = Math.ceil(
Math.max(vault.position.amounts.borrowedPrimary, vault.position.amounts.borrowedSecondary) *
1.001,
)
const secondaryAmount = vault.position.amounts.lp.secondary const secondaryAmount = vault.position.amounts.lp.secondary
if (secondaryAmount < borrowAmount) { if (secondaryAmount < borrowAmount) {
@ -46,11 +49,11 @@ export const getClosePositionActions = (
}, },
}, },
...swapMessage, ...swapMessage,
...(vault.position.amounts.borrowed ...(Math.max(vault.position.amounts.borrowedPrimary, vault.position.amounts.borrowedSecondary)
? [ ? [
{ {
repay: { repay: {
denom: vault.denoms.secondary, denom: vault.position.borrowDenom || vault.denoms.secondary,
amount: 'account_balance' as ActionAmount, amount: 'account_balance' as ActionAmount,
}, },
}, },

View File

@ -1,7 +1,7 @@
export const getCoinFromPosition = ( export const getCoinFromPosition = (
position: Position, position: Position,
vault: Vault, vault: Vault,
type: 'primary' | 'secondary' | 'borrowed', type: 'primary' | 'secondary' | 'borrowedPrimary' | 'borrowedSecondary',
) => { ) => {
const denom = type === 'primary' ? vault.denoms.primary : vault.denoms.secondary const denom = type === 'primary' ? vault.denoms.primary : vault.denoms.secondary
return { return {

View File

@ -3,7 +3,17 @@ import BigNumber from 'bignumber.js'
export const getLeverageFromValues = (values: { export const getLeverageFromValues = (values: {
primary: number primary: number
secondary: number secondary: number
borrowed: number borrowedPrimary: number
borrowedSecondary: number
net: number net: number
total: number total: number
}) => Number(new BigNumber(values.borrowed).div(values.net || 1).plus(1)) }) =>
Number(
new BigNumber(
values.borrowedPrimary > values.borrowedSecondary
? values.borrowedPrimary
: values.borrowedSecondary,
)
.div(values.net || 1)
.plus(1),
)

View File

@ -1,3 +1,8 @@
export const getLiqBorrowValue = (vault: Vault, maxBorrowValue: number) => { import BigNumber from 'bignumber.js'
return ((vault.ltv.liq - vault.ltv.max) / vault.ltv.max + 1) * maxBorrowValue import { ltvToLeverage } from 'libs/parse'
export const getLiqBorrowValue = (vault: Vault, netValue: number) => {
const liqLev = ltvToLeverage(vault.ltv.liq)
return new BigNumber(netValue).times(liqLev - 1).toNumber()
} }

View File

@ -9,5 +9,5 @@ export const getMaxAllowedLeverage = (
new BigNumber(borrowValue) new BigNumber(borrowValue)
.div(new BigNumber(primaryValue).plus(secondaryValue)) .div(new BigNumber(primaryValue).plus(secondaryValue))
.plus(1) .plus(1)
.toPrecision(2), .toPrecision(4),
) )

View File

@ -2,5 +2,8 @@ import BigNumber from 'bignumber.js'
import { ltvToLeverage } from 'libs/parse' import { ltvToLeverage } from 'libs/parse'
export const getMaxBorrowValue = (vault: Vault, position: Position): number => { export const getMaxBorrowValue = (vault: Vault, position: Position): number => {
return new BigNumber(ltvToLeverage(vault.ltv.max)).minus(1).times(position.values.net).toNumber() return new BigNumber(ltvToLeverage(vault.ltv.contract))
.minus(1)
.times(position.values.net)
.toNumber()
} }

View File

@ -9,7 +9,7 @@ import { vault } from 'mocks/vault'
describe('getMaxBorrowValue', () => { describe('getMaxBorrowValue', () => {
test('should return 0 when netValue = 0', () => { test('should return 0 when netValue = 0', () => {
vault.ltv.max = 0.5 vault.ltv.contract = 0.5
position.values.net = 0 position.values.net = 0
const maxBorrowValue = getMaxBorrowValue(vault, position) const maxBorrowValue = getMaxBorrowValue(vault, position)
@ -17,7 +17,7 @@ describe('getMaxBorrowValue', () => {
}) })
test('should return 0 when maxLTV = 0', () => { test('should return 0 when maxLTV = 0', () => {
vault.ltv.max = 0 vault.ltv.contract = 0
position.values.net = 100 position.values.net = 100
const maxBorrowValue = getMaxBorrowValue(vault, position) const maxBorrowValue = getMaxBorrowValue(vault, position)
@ -25,7 +25,7 @@ describe('getMaxBorrowValue', () => {
}) })
test('should return 1x netValue when maxLTV = 0.5', () => { test('should return 1x netValue when maxLTV = 0.5', () => {
vault.ltv.max = 0.5 vault.ltv.contract = 0.5
position.values.net = 100 position.values.net = 100
const maxBorrowValue = getMaxBorrowValue(vault, position) const maxBorrowValue = getMaxBorrowValue(vault, position)
@ -33,7 +33,7 @@ describe('getMaxBorrowValue', () => {
}) })
test('should return 4.5x netValue when maxLTV = ', () => { test('should return 4.5x netValue when maxLTV = ', () => {
vault.ltv.max = 0.75 vault.ltv.contract = 0.75
position.values.net = 100 position.values.net = 100
const maxBorrowValue = getMaxBorrowValue(vault, position) const maxBorrowValue = getMaxBorrowValue(vault, position)
@ -62,7 +62,8 @@ describe('getLeverageFromValues', () => {
const values = { const values = {
primary: 0, primary: 0,
secondary: 0, secondary: 0,
borrowed: 0, borrowedPrimary: 0,
borrowedSecondary: 0,
net: 0, net: 0,
total: 0, total: 0,
} }
@ -73,14 +74,14 @@ describe('getLeverageFromValues', () => {
}) })
test('should return 1.5 when borrowed = 50 and net = 100', () => { test('should return 1.5 when borrowed = 50 and net = 100', () => {
values.borrowed = 50 values.borrowedPrimary = 50
values.net = 100 values.net = 100
const leverage = getLeverageFromValues(values) const leverage = getLeverageFromValues(values)
expect(leverage).toBe(1.5) expect(leverage).toBe(1.5)
}) })
test('should return 2.25 when borrowed = 125 and net = 100', () => { test('should return 2.25 when borrowed = 125 and net = 100', () => {
values.borrowed = 125 values.borrowedPrimary = 125
values.net = 100 values.net = 100
const leverage = getLeverageFromValues(values) const leverage = getLeverageFromValues(values)
expect(leverage).toBe(2.25) expect(leverage).toBe(2.25)

View File

@ -3,9 +3,10 @@ import { Coin } from '@cosmjs/proto-signing'
export const updateExchangeRate = (coin: Coin, exchangeRates: Coin[]) => { export const updateExchangeRate = (coin: Coin, exchangeRates: Coin[]) => {
const assetIndex = exchangeRates.findIndex((xAsset) => xAsset.denom === coin.denom) const assetIndex = exchangeRates.findIndex((xAsset) => xAsset.denom === coin.denom)
if (assetIndex > -1) { if (assetIndex > -1) {
exchangeRates[assetIndex] = coin if (coin.amount !== '0.00') exchangeRates[assetIndex] = coin
} else { } else {
exchangeRates.push(coin) exchangeRates.push(coin)
} }
return exchangeRates return exchangeRates
} }

View File

@ -12,6 +12,7 @@ export { useRepayPosition } from './useRepayPosition'
export { useRequestUnlockPosition } from './useRequestUnlockPosition' export { useRequestUnlockPosition } from './useRequestUnlockPosition'
export { useSpotPrice } from './useSpotPrice' export { useSpotPrice } from './useSpotPrice'
export { useUnlockMessages } from './useUnlockMessages' export { useUnlockMessages } from './useUnlockMessages'
export { useUsdPrice } from './useUsdPrice'
export { useUserBalance } from './useUserBalance' export { useUserBalance } from './useUserBalance'
export { useUserDebt } from './useUserDebt' export { useUserDebt } from './useUserDebt'
export { useUserDeposit } from './useUserDeposit' export { useUserDeposit } from './useUserDeposit'

View File

@ -15,6 +15,8 @@ export interface DepositAndDebtData {
JUNODebt: string JUNODebt: string
axlUSDCDeposits: string axlUSDCDeposits: string
axlUSDCDebt: string axlUSDCDebt: string
stATOMDeposits: string
stATOMDebt: string
} }
} }

View File

@ -27,15 +27,20 @@ export const useEditPosition = (props: Props) => {
props.position.amounts.primary - (props.prevPosition?.amounts.primary || 0) props.position.amounts.primary - (props.prevPosition?.amounts.primary || 0)
const secondaryAmount = const secondaryAmount =
props.position.amounts.secondary - (props.prevPosition?.amounts.secondary || 0) props.position.amounts.secondary - (props.prevPosition?.amounts.secondary || 0)
const borrowedAmount = const borrowedPrimaryAmount =
props.position.amounts.borrowed - (props.prevPosition?.amounts.borrowed || 0) props.position.amounts.borrowedPrimary - (props.prevPosition?.amounts.borrowedPrimary || 0)
const borrowedSecondaryAmount =
props.position.amounts.borrowedSecondary -
(props.prevPosition?.amounts.borrowedSecondary || 0)
const editPosition = { const editPosition = {
...props.position, ...props.position,
amounts: { amounts: {
primary: primaryAmount, primary: primaryAmount,
secondary: secondaryAmount, secondary: secondaryAmount,
borrowed: borrowedAmount, borrowedPrimary: borrowedPrimaryAmount,
borrowedSecondary: borrowedSecondaryAmount,
lp: { lp: {
amount: '0', amount: '0',
primary: 0, primary: 0,
@ -47,15 +52,15 @@ export const useEditPosition = (props: Props) => {
const primaryBaseAmount = convertToBaseCurrency({ const primaryBaseAmount = convertToBaseCurrency({
denom: props.vault.denoms.primary, denom: props.vault.denoms.primary,
amount: primaryAmount.toString(), amount: (primaryAmount + borrowedPrimaryAmount).toString(),
}) })
const secondaryBaseAmount = convertToBaseCurrency({ const secondaryBaseAmount = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.vault.denoms.secondary,
amount: (secondaryAmount + borrowedAmount).toString(), amount: (secondaryAmount + borrowedSecondaryAmount).toString(),
}) })
let primaryAfterSwap = primaryAmount let primaryAfterSwap = primaryAmount + borrowedPrimaryAmount
let secondaryAfterSwap = secondaryAmount + borrowedAmount let secondaryAfterSwap = secondaryAmount + borrowedSecondaryAmount
// If difference is larger than threshold, initiate a swap // If difference is larger than threshold, initiate a swap
const difference = primaryBaseAmount - secondaryBaseAmount const difference = primaryBaseAmount - secondaryBaseAmount
@ -105,7 +110,8 @@ export const useEditPosition = (props: Props) => {
}, [ }, [
props.position.amounts.primary, props.position.amounts.primary,
props.position.amounts.secondary, props.position.amounts.secondary,
props.position.amounts.borrowed, props.position.amounts.borrowedPrimary,
props.position.amounts.borrowedSecondary,
]) ])
const { data: minLpToReceive } = useProvideLiquidity({ const { data: minLpToReceive } = useProvideLiquidity({
@ -128,9 +134,12 @@ export const useEditPosition = (props: Props) => {
amount: editPosition.amounts.secondary.toString(), amount: editPosition.amounts.secondary.toString(),
} }
const borrow = editPosition.amounts.borrowed && { const borrow = editPosition.borrowDenom && {
denom: props.vault.denoms.secondary, denom: editPosition.borrowDenom,
amount: editPosition.amounts.borrowed.toString(), amount: Math.max(
editPosition.amounts.borrowedPrimary,
editPosition.amounts.borrowedSecondary,
).toString(),
} }
if (primary) coins.supply.push(primary) if (primary) coins.supply.push(primary)
@ -139,12 +148,12 @@ export const useEditPosition = (props: Props) => {
const primaryBaseAmount = convertToBaseCurrency({ const primaryBaseAmount = convertToBaseCurrency({
denom: props.vault.denoms.primary, denom: props.vault.denoms.primary,
amount: String(editPosition.amounts.primary), amount: String(editPosition.amounts.primary + editPosition.amounts.borrowedPrimary),
}) })
const secondaryBaseAmount = convertToBaseCurrency({ const secondaryBaseAmount = convertToBaseCurrency({
denom: props.vault.denoms.secondary, denom: props.vault.denoms.secondary,
amount: String(editPosition.amounts.secondary + editPosition.amounts.borrowed), amount: String(editPosition.amounts.secondary + editPosition.amounts.borrowedSecondary),
}) })
const swapMessage: Action[] = [] const swapMessage: Action[] = []

View File

@ -14,16 +14,29 @@ export const useRepayPosition = (props: Props) => {
const [amount, setAmount] = useState(0) const [amount, setAmount] = useState(0)
useEffect(() => { useEffect(() => {
setAmount(props.prevPosition.amounts.borrowed - props.repayPosition.amounts.borrowed) const borrowKey =
}, [props.repayPosition.amounts.borrowed, props.prevPosition.amounts.borrowed]) props.prevPosition.borrowDenom === props.activeVault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
setAmount(props.prevPosition.amounts[borrowKey] - props.repayPosition.amounts[borrowKey])
}, [
props.repayPosition.amounts.borrowedPrimary,
props.repayPosition.amounts.borrowedSecondary,
props.prevPosition.amounts.borrowedPrimary,
props.prevPosition.amounts.borrowedSecondary,
props.activeVault.denoms.primary,
props.prevPosition.amounts,
props.prevPosition.borrowDenom,
props.repayPosition.amounts,
])
const [actions, funds] = useMemo(() => { const [actions, funds] = useMemo(() => {
if (!amount) return [[], []] if (!amount) return [[], []]
return getRepayActionsAndFunds({ return getRepayActionsAndFunds({
denom: props.activeVault.denoms.secondary, denom: props.activeVault.position.borrowDenom || props.activeVault.denoms.secondary,
amount: amount.toString(), amount: amount.toString(),
}) })
}, [amount, props.activeVault.denoms.secondary]) }, [amount, props.activeVault.denoms.secondary, props.activeVault.position.borrowDenom])
const { data: fee } = useEstimateFarmFee({ const { data: fee } = useEstimateFarmFee({
accountId: props.prevPosition.accountId, accountId: props.prevPosition.accountId,

View File

@ -9,15 +9,16 @@ const poolsEndpoint = 'osmosis/gamm/v1beta1/pools/'
export const useSpotPrice = (symbol: string) => { export const useSpotPrice = (symbol: string) => {
const networkConfig = useStore((s) => s.networkConfig) const networkConfig = useStore((s) => s.networkConfig)
const displayCurrency = networkConfig?.displayCurrency
const lcd = useStore((s) => s.chainInfo?.rest) const lcd = useStore((s) => s.chainInfo?.rest)
const exchangeRates = useStore((s) => s.exchangeRates) const exchangeRates = useStore((s) => s.exchangeRates)
const asset = useAsset({ symbol }) const asset = useAsset({ symbol })
const poolBase = asset?.poolBase
const displayCurrency = networkConfig?.displayCurrency ? exchangeRates?.find((ratesAsset) => ratesAsset.denom === asset.poolBase)
: true
useQuery<PoolResponse>( useQuery<PoolResponse>(
[QUERY_KEYS.MARS_PRICE, asset?.poolId], [QUERY_KEYS.SPOT_PRICE, asset?.poolId],
async () => { async () => {
return fetch(`${lcd}${poolsEndpoint}${asset?.poolId}`).then(async (response) => { return fetch(`${lcd}${poolsEndpoint}${asset?.poolId}`).then(async (response) => {
const data = await response.json() const data = await response.json()
@ -25,7 +26,7 @@ export const useSpotPrice = (symbol: string) => {
}) })
}, },
{ {
enabled: !!lcd && !!asset && !!asset.poolId, enabled: !!lcd && !!asset && !!asset.poolId && !!poolBase,
staleTime: 30000, staleTime: 30000,
refetchInterval: 30000, refetchInterval: 30000,
onSuccess: (data) => { onSuccess: (data) => {
@ -44,11 +45,22 @@ export const useSpotPrice = (symbol: string) => {
.div(targetAssetAmount) .div(targetAssetAmount)
.multipliedBy(otherAssetWeight.div(targetAssetWeight)) .multipliedBy(otherAssetWeight.div(targetAssetWeight))
if (displayCurrency.denom === asset.denom) { const hasDisplayCurrency = exchangeRates?.find(
(ratesAsset) => ratesAsset.denom === displayCurrency.denom,
)
if (displayCurrency.denom === asset.denom && !hasDisplayCurrency) {
useStore.setState({ baseToDisplayCurrencyRatio: 1 / rate.toNumber() }) useStore.setState({ baseToDisplayCurrencyRatio: 1 / rate.toNumber() })
} else { } else {
const coin = { denom: asset.denom, amount: rate.toString() } const coin = { denom: asset.denom, amount: rate.toString() }
useStore.setState({ exchangeRates: updateExchangeRate(coin, exchangeRates || []) })
if (typeof poolBase === 'object') {
const baseRate = Number(rate.toString()) * Number(poolBase.amount)
coin.amount = baseRate.toString()
useStore.setState({ exchangeRates: updateExchangeRate(coin, exchangeRates || []) })
} else {
useStore.setState({ exchangeRates: updateExchangeRate(coin, exchangeRates || []) })
}
} }
}, },
}, },

View File

@ -0,0 +1,46 @@
import { useQuery } from '@tanstack/react-query'
import { updateExchangeRate } from 'functions'
import useStore from 'store'
import { QUERY_KEYS } from 'types/enums/queryKeys'
interface CoinPriceData {
price: number
denom: string
symbol: string
liquidity: number
liquidity_24h_change: number
volume_24h: number
volume_24h_change: number
name: string
price_24h_change: number
exponent: number
display: string
}
export const useUsdPrice = () => {
const apiUrl = useStore((s) => s.networkConfig?.priceApiUrl ?? '')
const exchangeRates = useStore((s) => s.exchangeRates ?? [])
const networkConfig = useStore((s) => s.networkConfig)
const displayCurrency = networkConfig?.displayCurrency
useQuery<CoinPriceData[]>(
[QUERY_KEYS.USD_PRICE],
async () => {
const res = await fetch(apiUrl)
return res.json()
},
{
enabled: !!apiUrl && !!exchangeRates.length && !!displayCurrency,
staleTime: 30000,
refetchInterval: 30000,
onSuccess: (data) => {
const coin = { denom: 'usd', amount: (1 / data[0].price).toString() }
if (displayCurrency.denom === coin.denom) {
useStore.setState({ baseToDisplayCurrencyRatio: data[0].price })
}
updateExchangeRate(coin, exchangeRates)
},
},
)
}

38
src/images/statom.svg Normal file
View File

@ -0,0 +1,38 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2500 2500" style="enable-background:new 0 0 2500 2500;" xml:space="preserve">
<circle style="fill:#E50571;" cx="1250" cy="1250" r="1250"/>
<circle style="fill:#FFFFFF;" cx="1250" cy="1250" r="128.6"/>
<path style="fill:#FFFFFF;" d="M1709.1,1253.5c336.5-233.9,543.2-454.9,491.6-544.9c-33.3-58.1-168.1-50.8-359.4,8.1
c-13-22.6-36.8-37.7-64.1-37.7c-41.2,0-74.6,34.5-74.6,77.2c0,2.8,0.2,5.6,0.4,8.3c-69.8,26.5-144.5,58.1-222.5,94.3
c-35.3-409.1-124.1-699.3-228-699.3c-103.7,0-192.4,289.3-227.8,697.4c-370.9-173.9-665.9-242-718-152.1
c-32.5,56.3,35.9,164.2,173.9,294.7c-1.5,6.1-2.3,12.5-2.3,19.1c0,42.6,33.4,77.2,74.6,77.2c10.5,0,20.5-2.3,29.6-6.3
c62.9,52.3,134.6,106.9,213.5,162.2c-336.6,233.9-543.3,454.9-491.6,544.9c51.7,90.1,347.6,22.7,720.2-150.2
c7.9,91.7,18.5,177.4,31.4,255.2c-19.5,13.9-32.3,37.2-32.3,63.5c0,37.3,25.6,68.4,59.6,75.6c43.9,188.9,103.6,305.1,169.3,305.1
c103.8,0,192.4-289.4,227.8-697.6c371,174,665.9,242.2,717.9,152.3C2250.4,1710.6,2044.5,1488.8,1709.1,1253.5z M1725.6,811.8
c13.4,13.3,31.6,21.5,51.7,21.5c37.1,0,67.9-28,73.6-64.8c190.7-59.8,268.1-52.8,295.1-45.4c9.1,2.5,15,11.2,14,20.6
c-5.1,56-104.2,157-104.2,157c-132.1,131.9-271.4,241.7-387.7,324.4c-54.8-37.5-112.7-75.2-173.3-112.6
c-2-69.4-5.4-136.8-10.2-201.5C1576.7,870.1,1656.5,837.6,1725.6,811.8z M1398,1397.6c-47.4,29.1-96.7,57-146.1,83.3
c-33.6-18.8-52-30.1-52-30.1c-46.3-25-92.5-52-137.6-79.9c-2.2-85.5-2.7-164-2.4-227.6c71-43.2,136.9-81.4,190.9-112.1
c76.2,41.6,145,81.1,199.8,113.2c0.4,34.7-0.1,54.1-0.1,54.1c1.7,55.9,1.3,112.8-0.5,169.1C1417,1387.3,1398,1397.6,1398,1397.6z
M1448,1421.5c-2.5,53.4-6.2,105.5-10.4,154.9c-54.3-25.8-101-49.7-138.3-69.6c24.9-13.7,50-27.8,75.2-42.2
C1399.3,1450.2,1423.8,1435.9,1448,1421.5z M1203.7,1506c-45.2,23.2-90.1,44.9-133,65c-3-49.4-5.2-98.4-6.8-145.8
c21.7,13.1,43.8,26.1,66.1,39C1154.8,1478.5,1179.3,1492.4,1203.7,1506z M1009,1337.3c-43.2-27.8-85-56-124.2-83.4
c41.7-27.4,83.5-53.9,124.1-79.1c-0.4,25.7-0.6,51.7-0.6,77.9C1008.2,1281.1,1008.5,1309.3,1009,1337.3z M1066.8,934.6
c44.8,22.5,88.9,45.4,131.2,68c-22.3,12.4-44.8,25-67.3,37.9c-23.7,13.6-47.2,27.3-70.2,41.1c0.8-61.8,2.1-99.1,2.1-99.1
C1063.9,966.2,1065.4,950.3,1066.8,934.6z M1304.9,1000.9c54.2-30.2,87.3-47.7,87.3-47.7c16.4-7.6,32.4-15,48-22.1
c4.9,59.5,7.5,111.6,9,153.5c-24.3-14.6-48.9-29.2-73.9-43.7C1351.8,1027.3,1328.3,1013.9,1304.9,1000.9z M1496.2,1171.4
c53.4,31.9,85.3,51.8,85.3,51.8c15.2,10.6,30,21.1,44.5,31.4c-49.7,34.2-93.9,62.7-129.8,85c0.5-28.7,0.8-57.8,0.8-87.1
C1496.9,1225.3,1496.7,1198.2,1496.2,1171.4z M1238.2,214.2c6.7-6.6,17.1-7.4,24.7-2c45.9,32.5,84.4,168.5,84.4,168.5
c48.7,180.9,74.7,357.1,88.4,499.3c-59.3,28.4-120.2,59.3-182.3,92.6c-61.6-33.4-122.2-64.5-181.2-93
C1124.6,369.7,1208.5,243.6,1238.2,214.2z M619.2,1054c5.3-10.6,8.4-22.7,8.4-35.5c0-42.6-33.4-77.2-74.6-77.2
c-16.7,0-32,5.7-44.5,15.2C364.1,818,351.7,750.1,351.7,750.1l-0.1-0.3c-10-23.7,11.1-29.4,11.1-29.4
c93.5-17.6,224.7,22.6,224.7,22.6c123.5,28.1,280.4,94.2,432.9,168.6c-4.7,64.4-8.1,131.3-10.1,200.3
c-59.6,36.5-116.7,73.2-170.8,109.8C736.8,1148.2,656.4,1084.2,619.2,1054z M736.1,1711.7c-280.1,100.9-369.7,68.8-369.7,68.8h0
c-25.7-3.2-19.9-24.4-19.9-24.4c31.5-89.7,132-183.2,132-183.2c86.2-92.8,222-195.4,362.8-290c53.6,36.5,110.1,73.2,169,109.7
c2,69.5,5.4,136.9,10.2,201.7C859.5,1666.9,736.1,1711.7,736.1,1711.7z M1393.7,1929c-51.8,293.2-124.2,355-124.2,355
c-15.4,20.6-30.9,5.1-30.9,5.1c-62.1-72-93.2-205.8-93.2-205.8c-4.9-15.7-9.5-32.1-13.8-49.3c24.5-12.7,41.3-38.8,41.3-69
c0-41.1-31-74.7-70.2-77c-12.9-83.4-22.1-174.2-28.5-265.2c57.8-27.8,117.3-58,177.7-90.4c61.7,33.4,122.3,64.5,181.2,93.1
C1416.1,1800.5,1393.7,1929,1393.7,1929z M2147.6,1782.8c-51.1,23.4-188.1-11.5-188.1-11.5c-180.4-48.4-345.3-113.9-475.1-173.2
c4.9-65.8,8.4-134.4,10.5-205.1c59.6-36.5,116.7-73.3,170.8-109.9c414.9,300.9,482,436.8,492.5,477.1
C2160.7,1769.5,2156.1,1778.9,2147.6,1782.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,5 +1,6 @@
// @index(['./*.ts'], f => `export { ${f.name.split('.')[0]} } from '${f.path}'`) // @index(['./*.ts'], f => `export { ${f.name.split('.')[0]} } from '${f.path}'`)
export { position } from './position' export { position } from './position'
export { redBankAssets } from './redBankAssets' export { redBankAssets } from './redBankAssets'
export { redBankData } from './redBankData'
export { vault } from './vault' export { vault } from './vault'
// @endindex // @endindex

View File

@ -4,7 +4,8 @@ export const position: Position = {
amounts: { amounts: {
primary: 0, primary: 0,
secondary: 0, secondary: 0,
borrowed: 0, borrowedPrimary: 0,
borrowedSecondary: 0,
lp: { lp: {
amount: '0', amount: '0',
primary: 0, primary: 0,
@ -15,7 +16,8 @@ export const position: Position = {
values: { values: {
primary: 0, primary: 0,
secondary: 0, secondary: 0,
borrowed: 0, borrowedPrimary: 0,
borrowedSecondary: 0,
total: 0, total: 0,
net: 0, net: 0,
}, },
@ -26,4 +28,5 @@ export const position: Position = {
}, },
ltv: 0.5, ltv: 0.5,
currentLeverage: 1, currentLeverage: 1,
borrowDenom: null,
} }

View File

@ -11,13 +11,14 @@ export const redBankAssets: RedBankAsset[] = [
depositBalanceBaseCurrency: 0, depositBalanceBaseCurrency: 0,
depositCap: 1_000_000, depositCap: 1_000_000,
depositLiquidity: 5_000, depositLiquidity: 5_000,
hasOraclePrice: true,
isCollateral: true, isCollateral: true,
logo: '', logo: '',
marketLiquidity: '5000', marketLiquidity: '5000',
name: 'Atom', name: 'Atom',
symbol: 'ATOM', symbol: 'ATOM',
walletBalance: '100', walletBalance: '100',
borrowEnabled: true,
depositEnabled: true,
}, },
{ {
borrowRate: 30, borrowRate: 30,
@ -31,12 +32,13 @@ export const redBankAssets: RedBankAsset[] = [
depositBalanceBaseCurrency: 0, depositBalanceBaseCurrency: 0,
depositCap: 1_000_000, depositCap: 1_000_000,
depositLiquidity: 5_000, depositLiquidity: 5_000,
hasOraclePrice: true,
isCollateral: true, isCollateral: true,
logo: '', logo: '',
marketLiquidity: '5000', marketLiquidity: '5000',
name: 'Osmo', name: 'Osmo',
symbol: 'OSMO', symbol: 'OSMO',
walletBalance: '100', walletBalance: '100',
borrowEnabled: true,
depositEnabled: true,
}, },
] ]

150
src/mocks/redBankData.ts Normal file
View File

@ -0,0 +1,150 @@
export const redBankData: RedBankData = {
//@ts-ignore
rbwasmkey: {
OSMOMarket: {
denom: 'uosmo',
max_loan_to_value: '0.59',
liquidation_threshold: '0.61',
liquidation_bonus: '0.15',
reserve_factor: '0.2',
interest_rate_model: {
optimal_utilization_rate: '0.6',
base: '0',
slope_1: '0.15',
slope_2: '3',
},
borrow_index: '1.007594298500875037',
liquidity_index: '1.002246982368900673',
borrow_rate: '0.093460151948703559',
liquidity_rate: '0.027951360007279224',
indexes_last_updated: 1678369905,
collateral_total_scaled: '9114923539298761562',
debt_total_scaled: '3389444761162622058',
deposit_enabled: true,
borrow_enabled: true,
deposit_cap: '10000000000000',
},
OSMOMarketIncentive: {
denom: 'uosmo',
emission_per_second: '231482',
start_time: 1675793700,
duration: 2592000,
index: '0.000000139928505817',
last_updated: 1678369905,
},
ATOMMarket: {
denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
max_loan_to_value: '0.68',
liquidation_threshold: '0.7',
liquidation_bonus: '0.15',
reserve_factor: '0.2',
interest_rate_model: {
optimal_utilization_rate: '0.6',
base: '0',
slope_1: '0.15',
slope_2: '3',
},
borrow_index: '1.007258580949970929',
liquidity_index: '1.002076728614660732',
borrow_rate: '0.09442052103774879',
liquidity_rate: '0.028528751337727877',
indexes_last_updated: 1678368967,
collateral_total_scaled: '349274630628750224',
debt_total_scaled: '131236134520805186',
deposit_enabled: true,
borrow_enabled: true,
deposit_cap: '350000000000',
},
ATOMMarketIncentive: {
denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
emission_per_second: '106095',
start_time: 1675793700,
duration: 2592000,
index: '0.000001514531327288',
last_updated: 1678369638,
},
stATOMMarket: {
denom: 'ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901',
max_loan_to_value: '0.68',
liquidation_threshold: '0.7',
liquidation_bonus: '0.15',
reserve_factor: '0.2',
interest_rate_model: {
optimal_utilization_rate: '0.6',
base: '0',
slope_1: '0.15',
slope_2: '3',
},
borrow_index: '1.007258580949970929',
liquidity_index: '1.002076728614660732',
borrow_rate: '0.09442052103774879',
liquidity_rate: '0.028528751337727877',
indexes_last_updated: 1678368967,
collateral_total_scaled: '349274630628750224',
debt_total_scaled: '131236134520805186',
deposit_enabled: true,
borrow_enabled: false,
deposit_cap: '350000000000',
},
stATOMMarketIncentive: {
denom: 'ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901',
emission_per_second: '106095',
start_time: 1675793700,
duration: 2592000,
index: '0.000001514531327288',
last_updated: 1678369638,
},
axlUSDCMarket: {
denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858',
max_loan_to_value: '0.74',
liquidation_threshold: '0.75',
liquidation_bonus: '0.1',
reserve_factor: '0.2',
interest_rate_model: {
optimal_utilization_rate: '0.8',
base: '0',
slope_1: '0.2',
slope_2: '2',
},
borrow_index: '1.010875731969102527',
liquidity_index: '1.00525118991986623',
borrow_rate: '0.193514001505802393',
liquidity_rate: '0.11983254009212061',
indexes_last_updated: 1678369620,
collateral_total_scaled: '1494717184985439254',
debt_total_scaled: '1158255523619905561',
deposit_enabled: true,
borrow_enabled: true,
deposit_cap: '1500000000000',
},
axlUSDCMarketIncentive: {
denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858',
emission_per_second: '48225',
start_time: 1675793700,
duration: 2592000,
index: '0.000000143742920378',
last_updated: 1678369620,
},
collateral: [
{
denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
amount_scaled: '2559593418324',
amount: '2564911',
enabled: true,
},
{
denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858',
amount_scaled: '20000000000000',
amount: '20105061',
enabled: true,
},
{
denom: 'uosmo',
amount_scaled: '48000037051741',
amount: '48107901',
enabled: true,
},
],
unclaimedRewards: '4679062',
},
}

View File

@ -65,6 +65,11 @@ const EditVault = (props: Props) => {
[prevPosition.values.total, position.values.total], [prevPosition.values.total, position.values.total],
) )
const borrowKey =
props.activeVault.position.borrowDenom === props.activeVault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const { repayActions, repayFunds, repayFee } = useRepayPosition({ const { repayActions, repayFunds, repayFee } = useRepayPosition({
prevPosition, prevPosition,
repayPosition, repayPosition,
@ -131,7 +136,8 @@ const EditVault = (props: Props) => {
const actionButtons = useMemo( const actionButtons = useMemo(
() => ( () => (
<> <>
{prevPosition.amounts.borrowed > 0 && ( {(prevPosition.amounts.borrowedPrimary > 0 ||
prevPosition.amounts.borrowedSecondary > 0) && (
<Button <Button
onClick={() => setIsRepay(!isRepay)} onClick={() => setIsRepay(!isRepay)}
text={isRepay ? t('fields.managePosition') : t('fields.repayDebt')} text={isRepay ? t('fields.managePosition') : t('fields.repayDebt')}
@ -158,7 +164,8 @@ const EditVault = (props: Props) => {
setIsRepay, setIsRepay,
lockupTimeAndUnit.time, lockupTimeAndUnit.time,
lockupTimeAndUnit.unit, lockupTimeAndUnit.unit,
prevPosition.amounts.borrowed, prevPosition.amounts.borrowedPrimary,
prevPosition.amounts.borrowedSecondary,
], ],
) )
@ -200,9 +207,13 @@ const EditVault = (props: Props) => {
!isRepay && !isRepay &&
(prevPosition.amounts.primary > position.amounts.primary || (prevPosition.amounts.primary > position.amounts.primary ||
prevPosition.amounts.secondary > position.amounts.secondary || prevPosition.amounts.secondary > position.amounts.secondary ||
prevPosition.amounts.borrowed > position.amounts.borrowed) prevPosition.amounts.borrowedPrimary > position.amounts.borrowedPrimary ||
prevPosition.amounts.borrowedSecondary > position.amounts.borrowedSecondary)
const isNotRepaying = isRepay && repayPosition.amounts.borrowed >= prevPosition.amounts.borrowed const isNotRepaying =
isRepay &&
repayPosition.amounts.borrowedPrimary >= prevPosition.amounts.borrowedPrimary &&
repayPosition.amounts.borrowedSecondary >= prevPosition.amounts.borrowedSecondary
const isWithoutFee = (!isRepay && !editFee) || (isRepay && !repayFee) const isWithoutFee = (!isRepay && !editFee) || (isRepay && !repayFee)
const isSameAmounts = const isSameAmounts =
(isEqual(prevPosition.amounts, position.amounts) && !isRepay) || (isEqual(prevPosition.amounts, position.amounts) && !isRepay) ||
@ -280,7 +291,7 @@ const EditVault = (props: Props) => {
type={isRepay ? 'repay' : showUnlockBtn ? 'unlock' : 'edit'} type={isRepay ? 'repay' : showUnlockBtn ? 'unlock' : 'edit'}
position={position} position={position}
prevPosition={prevPosition} prevPosition={prevPosition}
repayAmount={prevPosition.amounts.borrowed - repayPosition.amounts.borrowed} repayAmount={prevPosition.amounts[borrowKey] - repayPosition.amounts[borrowKey]}
vault={props.activeVault} vault={props.activeVault}
className={styles.tooltip} className={styles.tooltip}
/> />

View File

@ -56,6 +56,11 @@ const RepayVault = (props: Props) => {
const disableConfirmBtn = !repayFee || isSameAmounts const disableConfirmBtn = !repayFee || isSameAmounts
const borrowKey =
props.activeVault.position.borrowDenom === props.activeVault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
return ( return (
<> <>
<Notification <Notification
@ -102,7 +107,7 @@ const RepayVault = (props: Props) => {
type={'repay'} type={'repay'}
position={repayPosition} position={repayPosition}
prevPosition={prevPosition} prevPosition={prevPosition}
repayAmount={prevPosition.amounts.borrowed - repayPosition.amounts.borrowed} repayAmount={prevPosition.amounts[borrowKey] - repayPosition.amounts[borrowKey]}
vault={props.activeVault} vault={props.activeVault}
className={styles.tooltip} className={styles.tooltip}
/> />

View File

@ -115,6 +115,11 @@ const commonSlice = (
config.NETWORK_CONFIG.rpcUrl = serializeUrl(config.NETWORK_CONFIG.rpcUrl) config.NETWORK_CONFIG.rpcUrl = serializeUrl(config.NETWORK_CONFIG.rpcUrl)
config.NETWORK_CONFIG.restUrl = serializeUrl(config.NETWORK_CONFIG.restUrl) config.NETWORK_CONFIG.restUrl = serializeUrl(config.NETWORK_CONFIG.restUrl)
const storageDisplayCurrency = localStorage.getItem('displayCurrency')
if (storageDisplayCurrency) {
config.NETWORK_CONFIG.displayCurrency = JSON.parse(storageDisplayCurrency)
}
set({ set({
otherAssets: config.NETWORK_CONFIG.assets.other, otherAssets: config.NETWORK_CONFIG.assets.other,
whitelistedAssets: config.NETWORK_CONFIG.assets.whitelist, whitelistedAssets: config.NETWORK_CONFIG.assets.whitelist,

View File

@ -25,9 +25,16 @@ const oraclesSlice = (set: NamedSet<Store>, get: GetState<Store>): OraclesSlice
const baseCurrency = get().baseCurrency const baseCurrency = get().baseCurrency
const networkConfig = get().networkConfig const networkConfig = get().networkConfig
const displayCurrency = networkConfig?.displayCurrency const displayCurrency = networkConfig?.displayCurrency
const assets = [...whitelistedAssets, ...otherAssets] const exchangeRatesState = get().exchangeRatesState
const assets: Asset[] = [...whitelistedAssets, ...otherAssets]
if (!coin || !exchangeRates || !assets.length || !displayCurrency) { if (
!coin ||
exchangeRatesState === State.INITIALISING ||
!exchangeRates?.find((rate) => rate.denom === displayCurrency.denom) ||
!assets.length ||
!displayCurrency
) {
return 0 return 0
} }
@ -88,13 +95,19 @@ const oraclesSlice = (set: NamedSet<Store>, get: GetState<Store>): OraclesSlice
const wasmQueryResults = data.prices const wasmQueryResults = data.prices
const exchangeRates: Coin[] = get().exchangeRates ?? [] const exchangeRates: Coin[] = get().exchangeRates ?? []
const baseCurrency = get().baseCurrency
const networkConfig = get().networkConfig
const displayCurrency = networkConfig?.displayCurrency
get() get()
.whitelistedAssets?.filter((asset: Asset) => !!asset.denom) .whitelistedAssets?.filter((asset: Asset) => !!asset.denom)
.forEach((asset: Asset) => { .forEach((asset: Asset) => {
const denom = asset.denom const denom = asset.denom
const hasBaseCurrency = exchangeRates?.find(
(ratesAsset) => ratesAsset.denom === baseCurrency.denom,
)
if (denom === get().baseCurrency.denom) { if (denom === baseCurrency.denom && !hasBaseCurrency) {
exchangeRates.push({ denom, amount: '1' }) exchangeRates.push({ denom, amount: '1' })
return return
} }
@ -106,6 +119,11 @@ const oraclesSlice = (set: NamedSet<Store>, get: GetState<Store>): OraclesSlice
denom, denom,
amount: typeof exchangeRateResult === 'string' ? exchangeRateResult || '0.00' : '0.00', amount: typeof exchangeRateResult === 'string' ? exchangeRateResult || '0.00' : '0.00',
} }
if (asset.denom === displayCurrency.denom) {
set({
baseToDisplayCurrencyRatio: 1 / Number(exchangeRate.amount),
})
}
updateExchangeRate(exchangeRate, exchangeRates) updateExchangeRate(exchangeRate, exchangeRates)
}) })
set({ set({

View File

@ -119,6 +119,8 @@ const redBankSlice = (set: NamedSet<Store>, get: GetState<Store>): RedBankSlice
incentiveInfo, incentiveInfo,
isCollateral: true, isCollateral: true,
depositCap: depositCap, depositCap: depositCap,
borrowEnabled: marketInfo?.borrow_enabled ?? false,
depositEnabled: marketInfo?.deposit_enabled ?? false,
} }
redBankAsset.subRows = [{ ...redBankAsset }] redBankAsset.subRows = [{ ...redBankAsset }]
redBankAssets.push(redBankAsset) redBankAssets.push(redBankAsset)

View File

@ -324,25 +324,50 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
(unlockTime) => unlockTime?.vaultAddress === curr.address, (unlockTime) => unlockTime?.vaultAddress === curr.address,
)?.unlockAtTimestamp )?.unlockAtTimestamp
let primarySupplyAmount = Number( let primaryAmount = Number(
findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.primary)?.amount || 0, findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.primary)?.amount || 0,
) )
const secondaryAmount = Number( let secondaryAmount = Number(
findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.secondary)?.amount || 0, findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.secondary)?.amount || 0,
) )
const borrowedAmount = Number(creditAccountPosition.debts[0]?.amount || 0)
if (borrowedAmount > secondaryAmount) { let borrowedPrimaryAmount = 0
const swappedToPrimary = Math.round( let borrowedSecondaryAmount = 0
get().convertToBaseCurrency({
denom: curr.denoms.secondary, const debt = creditAccountPosition.debts[0]
amount: (borrowedAmount - secondaryAmount).toString(), if (debt) {
}), if (debt.denom === curr.denoms.primary) {
) borrowedPrimaryAmount = Number(debt.amount)
primarySupplyAmount -= swappedToPrimary } else {
borrowedSecondaryAmount = Number(debt.amount)
}
} }
const secondarySupplyAmount = Math.max(secondaryAmount - borrowedAmount, 0) const borrowedDenom: string = creditAccountPosition.debts[0]?.denom || ''
if (borrowedPrimaryAmount > primaryAmount) {
const swapped = Math.round(
get().convertToBaseCurrency({
denom: borrowedDenom,
amount: (borrowedPrimaryAmount - primaryAmount).toString(),
}),
)
secondaryAmount -= swapped
}
if (borrowedSecondaryAmount > secondaryAmount) {
const swapped = Math.round(
get().convertToBaseCurrency({
denom: borrowedDenom,
amount: (borrowedSecondaryAmount - secondaryAmount).toString(),
}),
)
primaryAmount -= swapped
}
const primarySupplyAmount = Math.max(primaryAmount - borrowedPrimaryAmount, 0)
const secondarySupplyAmount = Math.max(secondaryAmount - borrowedSecondaryAmount, 0)
const borrowedAmount = Math.max(borrowedPrimaryAmount, borrowedSecondaryAmount)
const convertToBaseCurrency = get().convertToBaseCurrency const convertToBaseCurrency = get().convertToBaseCurrency
const redBankAssets = get().redBankAssets const redBankAssets = get().redBankAssets
@ -357,14 +382,15 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
}) })
const borrowedValue = convertToBaseCurrency({ const borrowedValue = convertToBaseCurrency({
denom: curr.denoms.secondary, denom: borrowedDenom,
amount: borrowedAmount.toString(), amount: borrowedAmount.toString(),
}) })
const values = { const values = {
primary: primaryValue, primary: primaryValue,
secondary: secondaryValue, secondary: secondaryValue,
borrowed: borrowedValue, borrowedPrimary: borrowedDenom === curr.denoms.primary ? borrowedValue : 0,
borrowedSecondary: borrowedDenom === curr.denoms.secondary ? borrowedValue : 0,
net: primaryValue + secondaryValue, net: primaryValue + secondaryValue,
total: primaryValue + secondaryValue + borrowedValue, total: primaryValue + secondaryValue + borrowedValue,
} }
@ -390,7 +416,8 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
amounts: { amounts: {
primary: primarySupplyAmount, primary: primarySupplyAmount,
secondary: secondarySupplyAmount, secondary: secondarySupplyAmount,
borrowed: borrowedAmount, borrowedPrimary: borrowedDenom === curr.denoms.primary ? borrowedAmount : 0,
borrowedSecondary: borrowedDenom === curr.denoms.secondary ? borrowedAmount : 0,
lp: { lp: {
amount: vaultTokenAmounts.unlocking, amount: vaultTokenAmounts.unlocking,
primary: Number( primary: Number(
@ -416,6 +443,7 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
ltv: leverageToLtv(leverage), ltv: leverageToLtv(leverage),
...(unlockTime ? { unlockAtTimestamp: unlockTime } : {}), ...(unlockTime ? { unlockAtTimestamp: unlockTime } : {}),
status: getPositionStatus(unlockTime), status: getPositionStatus(unlockTime),
borrowDenom: borrowedDenom,
} }
prev.activeVaults.push({ ...curr, position }) prev.activeVaults.push({ ...curr, position })

View File

@ -7,6 +7,7 @@
atom: $colorTokenATOM; atom: $colorTokenATOM;
axlusdc: $colorTokenAxlUSDC; axlusdc: $colorTokenAxlUSDC;
juno: $colorTokenJUNO; juno: $colorTokenJUNO;
statom: $colorTokenStATOM;
/* COLORS */ /* COLORS */
success: $colorInfoProfit; success: $colorInfoProfit;

View File

@ -1,43 +1,45 @@
@use 'sass:math'; @use 'sass:math';
$rem-base: 15px; $rem-base: 16px;
/* Colors */ /* Colors */
$colorWhite: #ffffff; $colorWhite: #f5f5f5;
$colorGrey: #3a3c49; $colorGrey: #bdbdbd;
$colorGreyLight: #bfbfbf; $colorGreyLight: #e0e0e0;
$colorGreyHighlight: #4c4c4c; $colorGreyHighlight: #efefef;
$colorGreyMedium: #5f697a; $colorGreyMedium: #9e9e9e;
$colorGreyDark: #1a1c25; $colorGreyDark: #616161;
/* CI Colors */ /* CI Colors */
$colorPrimary: #14a693; $colorPrimary: #0000ff;
$colorPrimaryHighlight: #15bfa9; $colorPrimaryHighlight: #6962cc;
$colorPrimaryAlpha: rgba(20, 166, 147, 0.15); $colorPrimaryAlpha: rgba(0, 0, 255, 0.05);
$colorSecondary: #524bb1; $colorSecondary: #212121;
$colorSecondaryHighlight: #6962cc; $colorSecondaryHighlight: #424242;
$colorSecondaryDark: #440b37; $colorSecondaryDark: #111111;
$colorSecondaryAlpha: rgba(68, 11, 55, 0.7); $colorSecondaryAlpha: rgba(17, 17, 17, 0.15);
$colorAccent: #2c1b2f; $colorAccent: $colorGreyMedium;
$colorAccentHighlight: #421f32; $colorAccentHighlight: $colorGreyMedium;
$colorAccentDark: #341a2a; $colorAccentDark: $colorGreyDark;
$colorAccentInverted: #345dff; $colorAccentInverted: $colorGreyLight;
/* Info Colors */ /* Info Colors */
$colorInfoProfit: #41a4a9; $colorInfoProfit: #c4e7e9;
$colorInfoLoss: #f96363; $colorInfoLoss: #c8aaaa;
$colorInfoWarning: #c83333; $colorInfoWarning: #ffb5b5;
$colorInfoVoteAgainst: #eb9e49; $colorInfoVoteAgainst: #6c5a46;
/* Token Colors */ /* Token Colors */
$colorTokenMARS: #a03b45; $colorTokenMARS: #dd5b65;
$colorTokenOSMO: #9f1ab9; $colorTokenOSMO: #9f1ab9;
$colorTokenATOM: #6f7390; $colorTokenATOM: #6f7390;
$colorTokenAxlUSDC: #478edc; $colorTokenAxlUSDC: #478edc;
$colorTokenJUNO: black; $colorTokenJUNO: black;
$colorTokenStATOM: #e50571;
$colorGradientOSMO: linear-gradient(to bottom, #3a02e2, #e700ca); $colorGradientOSMO: linear-gradient(to bottom, #3a02e2, #e700ca);
$colorGradientATOM: linear-gradient(to bottom, #2e3148, #6f7390); $colorGradientATOM: linear-gradient(to bottom, #2e3148, #6f7390);
$colorGradientAxlUSDC: linear-gradient(to bottom, #1f5c9e, #478edc); $colorGradientAxlUSDC: linear-gradient(to bottom, #1f5c9e, #478edc);
$colorGradientStATOM: linear-gradient(to bottom, #e50571, #fb5da9);
/* Alpha Colors */ /* Alpha Colors */
$alphaWhite10: rgba(255, 255, 255, 0.1); $alphaWhite10: rgba(255, 255, 255, 0.1);
@ -60,32 +62,29 @@ $alphaBlack80: rgba(0, 0, 0, 0.8);
$alphaBlack90: rgba(0, 0, 0, 0.9); $alphaBlack90: rgba(0, 0, 0, 0.9);
/* Background Colors */ /* Background Colors */
$backgroundBody: #562a3b; $backgroundBody: $colorGrey;
$backgroundBodyDark: #141621; $backgroundBodyDark: $backgroundBody;
$backgroundInTile: $alphaBlack30; $backgroundInTile: transparent;
$backgroundFooter: $alphaBlack20; $backgroundFooter: transparent;
/* Slider Colors */ /* Slider Colors */
$sliderThumb: $colorWhite; $sliderThumb: $colorGreyDark;
$sliderMark: $colorGreyLight; $sliderMark: $colorGreyDark;
/* Tooltip Colors */ /* Tooltip Colors */
$tooltipIconColor: $alphaWhite20; $tooltipIconColor: $alphaBlack60;
$tableSort: $alphaWhite20;
$tableSortActive: $colorWhite;
$tableHeader: $alphaWhite50;
/* Table Colors */ /* Table Colors */
$tableBorder: $alphaWhite10; $tableBorder: $alphaBlack30;
$tableBorderEnd: $alphaWhite80; $tableBorderEnd: $alphaBlack80;
$tableSort: $alphaWhite20; $tableSort: $alphaBlack20;
$tableSortActive: $colorWhite; $tableSortActive: $alphaBlack90;
$tableHeader: $alphaWhite40; $tableHeader: $alphaBlack40;
$tableLabel: $alphaWhite60; $tableLabel: $colorSecondaryDark;
/* Graph Colors */ /* Graph Colors */
$graphLiquidationsLine: $alphaWhite70; $graphLiquidationsLine: $alphaBlack70;
$graphAxis: $alphaWhite40; $graphAxis: $alphaBlack40;
/* Shadows */ /* Shadows */
$shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25); $shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25);
@ -96,43 +95,40 @@ $shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25);
/* Devider */ /* Devider */
@mixin devider10 { @mixin devider10 {
border-bottom: 1px solid $alphaWhite10; border-bottom: 1px solid $alphaBlack10;
} }
@mixin devider20 { @mixin devider20 {
border-bottom: 1px solid $alphaWhite20; border-bottom: 1px solid $alphaBlack20;
} }
@mixin devider40 { @mixin devider40 {
border-bottom: 1px solid $alphaWhite40; border-bottom: 1px solid $alphaBlack40;
} }
@mixin devider60 { @mixin devider60 {
border-bottom: 1px solid $alphaWhite60; border-bottom: 1px solid $alphaBlack60;
} }
/* Backgrounds */ /* Backgrounds */
@mixin bgBody { @mixin bgBody {
background-color: $backgroundBody; background-color: $backgroundBody;
background-size: 100% auto; }
background-image: url('../images/bg.svg');
background-position: center top; @mixin bgTableHover {
background-color: transparent;
} }
@mixin bgBodyDark { @mixin bgBodyDark {
background-color: $backgroundBodyDark; background-color: $backgroundBodyDark;
} }
@mixin bgTableHover {
background-color: rgba($colorPrimary, 0.2);
}
@mixin bgProposalActive { @mixin bgProposalActive {
background: linear-gradient(90deg, #10aa93 2.6%, #248aa9 97.92%); background: linear-gradient(90deg, #10aa93 2.6%, #248aa9 97.92%);
} }
@mixin bgProposalHover { @mixin bgProposalHover {
background-color: #05252f; background-color: $colorGreyMedium;
} }
@mixin bgTile($deg: 99.79) { @mixin bgTile($deg: 99.79) {
@ -144,7 +140,7 @@ $shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25);
} }
@mixin bgInTile { @mixin bgInTile {
background: $alphaBlack30; background: $backgroundInTile;
} }
@mixin bgOverlay { @mixin bgOverlay {
@ -161,11 +157,11 @@ $shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25);
} }
@mixin bgTileDevider { @mixin bgTileDevider {
background-color: $alphaWhite60; background-color: $alphaBlack60;
} }
@mixin bgDevider { @mixin bgDevider {
background-color: $alphaWhite20; background-color: $alphaBlack20;
} }
@mixin bgInput { @mixin bgInput {
@ -174,68 +170,60 @@ $shadowInset: inset 0px 2px 2px rgba(0, 0, 0, 0.25);
@mixin bgPrimary { @mixin bgPrimary {
background-color: $colorPrimary; background-color: $colorPrimary;
color: $colorWhite;
} }
@mixin bgSecondary { @mixin bgSecondary {
background-color: $colorSecondary; background-color: $colorSecondary;
color: $colorWhite;
} }
@mixin bgTertiary { @mixin bgTertiary {
background-color: rgba(82, 75, 177, 0.5); background-color: $alphaBlack60;
color: $colorWhite;
} }
@mixin bgLimit { @mixin bgLimit {
background: linear-gradient( background: $colorPrimary;
to right,
#15bfa9 20.9%,
#5e4bb1 49.68%,
#382685 82.55%,
#c83333 100%
);
} }
@mixin bgLimitOpacity { @mixin bgLimitOpacity {
background: linear-gradient( background: $colorPrimary;
to right,
#15bfa830 20.9%,
#5e4bb130 49.68%,
#38268530 82.55%,
#c8333330 100%
);
} }
@mixin bgHatched { @mixin bgHatched {
background-image: linear-gradient( background-image: linear-gradient(
135deg, 135deg,
transparent 33.33%, #1a1c25 33.33%,
#826d6b 33.33%, rgba(255, 255, 255, 0.2) 33.33%,
#826d6b 50%, rgba(255, 255, 255, 0.2) 50%,
transparent 50%, #1a1c25 50%,
transparent 83.33%, #1a1c25 83.33%,
#826d6b 83.33%, rgba(255, 255, 255, 0.2) 83.33%,
#826d6b 100% rgba(255, 255, 255, 0.2) 100%
); );
background-size: 5px 5px; background-size: 5px 5px;
} }
/* GLOWS */
/* GLOWS */ /* GLOWS */
@mixin glowXS { @mixin glowXS {
filter: blur(1px); display: none;
} }
@mixin glowS { @mixin glowS {
filter: blur(3px); display: none;
} }
@mixin glowM { @mixin glowM {
filter: blur(4px); display: none;
} }
@mixin glowL { @mixin glowL {
filter: blur(5px); display: none;
} }
@mixin glowXL { @mixin glowXL {
filter: blur(8px); display: none;
} }
@mixin glowXXL { @mixin glowXXL {
filter: blur(24px); display: none;
} }
/* Typography */ /* Typography */
@ -243,11 +231,11 @@ $fontWeightLight: 300;
$fontWeightRegular: 400; $fontWeightRegular: 400;
$fontWeightSemibold: 600; $fontWeightSemibold: 600;
$fontColorDarkPrimary: $colorSecondaryDark; $fontColorDarkPrimary: $colorWhite;
$fontColorDarkSecondary: rgba(68, 8, 55, 0.7); $fontColorDarkSecondary: $colorSecondaryDark;
$fontColorLightPrimary: $colorWhite; $fontColorLightPrimary: $colorSecondaryDark;
$fontColorLightSecondary: $alphaWhite60; $fontColorLightSecondary: $alphaBlack30;
$fontColorLightTertiary: rgba(255, 255, 255, 0.4); $fontColorLightTertiary: $colorSecondaryDark;
$fontColorLtv: $colorWhite; $fontColorLtv: $colorWhite;
@mixin typoH1 { @mixin typoH1 {
@ -263,8 +251,6 @@ $fontColorLtv: $colorWhite;
@mixin typoH2caps { @mixin typoH2caps {
@include typoH2; @include typoH2;
text-transform: uppercase;
letter-spacing: rem-calc(9);
} }
@mixin typoH3 { @mixin typoH3 {
@ -274,8 +260,6 @@ $fontColorLtv: $colorWhite;
@mixin typoH3caps { @mixin typoH3caps {
font-size: rem-calc(30.42); font-size: rem-calc(30.42);
line-height: space(10);
text-transform: uppercase;
} }
@mixin typoH4 { @mixin typoH4 {
@ -286,8 +270,6 @@ $fontColorLtv: $colorWhite;
@mixin typoH4caps { @mixin typoH4caps {
@include typoH4; @include typoH4;
text-transform: uppercase;
letter-spacing: rem-calc(3);
} }
@mixin typoXXL { @mixin typoXXL {
@ -297,9 +279,7 @@ $fontColorLtv: $colorWhite;
@mixin typoXXLcaps { @mixin typoXXLcaps {
@include typoXXL; @include typoXXL;
font-weight: $fontWeightRegular; font-weight: $fontWeightLight;
text-transform: uppercase;
letter-spacing: rem-calc(3);
} }
@mixin typoXL { @mixin typoXL {
@ -309,8 +289,6 @@ $fontColorLtv: $colorWhite;
@mixin typoXLcaps { @mixin typoXLcaps {
@include typoXL; @include typoXL;
letter-spacing: rem-calc(5);
text-transform: uppercase;
font-weight: $fontWeightLight; font-weight: $fontWeightLight;
} }
@ -322,8 +300,6 @@ $fontColorLtv: $colorWhite;
@mixin typoLcaps { @mixin typoLcaps {
@include typoL; @include typoL;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
text-transform: uppercase;
letter-spacing: rem-calc(3);
} }
@mixin typoM { @mixin typoM {
@ -333,7 +309,6 @@ $fontColorLtv: $colorWhite;
@mixin typoMcaps { @mixin typoMcaps {
@include typoM; @include typoM;
text-transform: uppercase;
} }
@mixin typoS { @mixin typoS {
@ -344,8 +319,6 @@ $fontColorLtv: $colorWhite;
@mixin typoScaps { @mixin typoScaps {
@include typoS; @include typoS;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
text-transform: uppercase;
letter-spacing: rem-calc(3);
} }
@mixin typoXS { @mixin typoXS {
@ -356,8 +329,6 @@ $fontColorLtv: $colorWhite;
@mixin typoXScaps { @mixin typoXScaps {
@include typoXS; @include typoXS;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
text-transform: uppercase;
letter-spacing: rem-calc(3);
} }
@mixin typoXXS { @mixin typoXXS {
@ -368,8 +339,6 @@ $fontColorLtv: $colorWhite;
@mixin typoXXScaps { @mixin typoXXScaps {
@include typoXXS; @include typoXXS;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
text-transform: uppercase;
letter-spacing: rem-calc(2);
} }
@mixin typoXXXS { @mixin typoXXXS {
@ -380,20 +349,15 @@ $fontColorLtv: $colorWhite;
@mixin typoXXXScaps { @mixin typoXXXScaps {
@include typoXXXS; @include typoXXXS;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
text-transform: uppercase;
letter-spacing: rem-calc(2);
} }
@mixin typoButton { @mixin typoButton {
font-family: Inter, sans-serif;
@include typoS; @include typoS;
font-weight: $fontWeightSemibold; font-weight: $fontWeightSemibold;
} }
@mixin typoNav { @mixin typoNav {
@include typoL; @include typoL;
text-transform: uppercase;
letter-spacing: rem-calc(5);
} }
@mixin typoNetwork { @mixin typoNetwork {
@ -467,100 +431,70 @@ $spacingBase: 4;
/* LAYOUTS */ /* LAYOUTS */
@mixin layoutTile { @mixin layoutTile {
@include bgTile; padding: space(1);
border: rem-calc(7) solid $colorAccentHighlight; background: $colorGreyHighlight;
border-radius: $borderRadiusXL; border: 2px solid $colorWhite;
box-shadow: 0 0 0 3px $colorGreyHighlight, 12px 12px 0 0 rgb(0 0 0 / 50%) !important;
height: fit-content; height: fit-content;
} }
@mixin layoutTooltip { @mixin layoutTooltip {
@include padding(2, 4); padding: space(3);
@include bgTooltip; background: $colorGreyLight;
@include typoS; border: 1px solid $colorSecondaryDark;
box-shadow: 0 rem-calc(3) rem-calc(4) rgba(0, 0, 0, 0.14),
0 rem-calc(3) rem-calc(3) rgba(0, 0, 0, 0.12), 0 rem-calc(1) rem-calc(8) rgba(0, 0, 0, 0.2);
border-radius: $borderRadiusL;
max-width: rem-calc(350);
} }
@mixin layoutPopover { @mixin layoutPopover {
@include bgPopover; padding: space(3);
box-shadow: 0 rem-calc(2) rem-calc(2) rgba(0, 0, 0, 0.14), background: $colorGreyLight;
0 rem-calc(1) rem-calc(5) rgba(0, 0, 0, 0.2); border: 1px solid $colorSecondaryDark;
border-radius: $borderRadiusL;
} }
@mixin layoutIncentiveButton { @mixin layoutIncentiveButton {
--border-width: 3px;
background-color: #946582;
position: relative;
border: none;
margin: rem-calc(3) rem-calc(11) 0 0;
height: rem-calc(28);
&:hover {
border: none;
background-color: darken(#946582, 10%);
}
&::after {
border-radius: $borderRadiusXXL;
position: absolute;
content: '';
top: calc(-1 * var(--border-width));
left: calc(-1 * var(--border-width));
z-index: -1;
width: calc(100% + var(--border-width) * 2);
height: calc(100% + var(--border-width) * 2);
background: linear-gradient(
90deg,
rgba(105, 98, 204, 0.8) 0%,
rgba(105, 98, 204, 1) 40%,
rgba(255, 255, 255, 1) 50%,
rgba(105, 98, 204, 1) 60%,
rgba(105, 98, 204, 0.8) 100%
);
background-size: 300% 300%;
background-position: 0 50%;
animation: moveGradient 6s alternate infinite;
}
} }
@mixin layoutLogo { @mixin layoutLogo {
> svg { > svg {
width: rem-calc(50); width: rem-calc(57);
height: rem-calc(50); height: rem-calc(57);
path {
stroke: $fontColorLightPrimary;
}
} }
} }
@mixin layoutGlobal { @mixin layoutGlobal {
opacity: 1 !important;
box-shadow: none !important;
} }
/* Buttons */ /* Buttons */
$buttonBorder: $alphaWhite40; $buttonBorder: $alphaBlack40;
$buttonBorderHover: $colorWhite; $buttonBorderHover: $colorSecondaryDark;
@mixin buttonS { @mixin buttonS {
@include typoS; @include typoS;
@include padding(1.5, 5); @include padding(1.5, 5);
min-height: rem-calc(32); height: rem-calc(32);
} }
@mixin buttonM { @mixin buttonM {
@include typoM; @include typoM;
@include padding(2.5, 6); @include padding(2.5, 6);
min-height: rem-calc(40); height: rem-calc(40);
} }
@mixin buttonL { @mixin buttonL {
@include typoL; @include typoL;
@include padding(2.5, 6); @include padding(2.5, 6);
min-height: rem-calc(56); height: rem-calc(56);
} }
@mixin buttonSolidPrimary { @mixin buttonSolidPrimary {
&.primary { &.primary {
background-color: $colorPrimary; background-color: $colorPrimary;
color: $colorWhite;
&:hover, &:hover,
&:focus { &:focus {
@ -576,6 +510,7 @@ $buttonBorderHover: $colorWhite;
@mixin buttonSolidSecondary { @mixin buttonSolidSecondary {
&.secondary { &.secondary {
background-color: $colorSecondary; background-color: $colorSecondary;
color: $colorWhite;
&:hover, &:hover,
&:focus { &:focus {
@ -590,34 +525,33 @@ $buttonBorderHover: $colorWhite;
@mixin buttonSolidTertiary { @mixin buttonSolidTertiary {
&.tertiary { &.tertiary {
background-color: $colorSecondaryAlpha; background-color: $colorSecondaryDark;
border: 1px solid $alphaWhite60; color: $colorWhite;
border: 1px solid $alphaBlack30;
&:hover, &:hover,
&:focus { &:focus {
border: 1px solid $fontColorLightPrimary; border: 1px solid $alphaBlack20;
background-color: $colorSecondaryDark;
} }
&:active { &:active {
border: 1px solid $fontColorLightPrimary;
background-color: lighten($colorSecondaryDark, 10%); background-color: lighten($colorSecondaryDark, 10%);
} }
} }
} }
/* Border Radius */ /* Border Radius */
$borderRadiusXXXS: rem-calc(3); $borderRadiusXXXS: 0;
$borderRadiusXXS: rem-calc(4); $borderRadiusXXS: 0;
$borderRadiusXS: rem-calc(5); $borderRadiusXS: 0;
$borderRadiusS: rem-calc(8); $borderRadiusS: 0;
$borderRadiusM: rem-calc(9); $borderRadiusM: 0;
$borderRadiusL: rem-calc(12); $borderRadiusL: 0;
$borderRadiusXL: rem-calc(16); $borderRadiusXL: 0;
$borderRadiusXXL: rem-calc(20); $borderRadiusXXL: 0;
$borderRadiusXXXL: rem-calc(30); $borderRadiusXXXL: 0;
$borderRadiusXXXXL: rem-calc(100); $borderRadiusXXXXL: 0;
$borderRadiusRound: 50%; $borderRadiusRound: 0;
/* Dimensions */ /* Dimensions */
$headerHeight: rem-calc(86); $headerHeight: rem-calc(86);

View File

@ -2,7 +2,7 @@ export enum QUERY_KEYS {
BLOCK_HEIGHT = 'blockHeight', BLOCK_HEIGHT = 'blockHeight',
MARS_BALANCE = 'marsBalance', MARS_BALANCE = 'marsBalance',
MARS_ORACLE = 'marsOracle', MARS_ORACLE = 'marsOracle',
MARS_PRICE = 'marsPrice', SPOT_PRICE = 'spotPrice',
REDBANK = 'redbank', REDBANK = 'redbank',
USER_BALANCE = 'userBalance', USER_BALANCE = 'userBalance',
USER_DEBT = 'userDebt', USER_DEBT = 'userDebt',
@ -15,4 +15,5 @@ export enum QUERY_KEYS {
ESTIMATE_FARM_FEE = 'estimateFarmFee', ESTIMATE_FARM_FEE = 'estimateFarmFee',
PROVIDE_LIQUIDITY = 'provideLiquidity', PROVIDE_LIQUIDITY = 'provideLiquidity',
UNLOCK_MESSAGE = 'unlockMessage', UNLOCK_MESSAGE = 'unlockMessage',
USD_PRICE = 'usdPrice',
} }

View File

@ -2,12 +2,12 @@ interface Asset {
color: string color: string
name: string name: string
denom: string denom: string
symbol: 'OSMO' | 'ATOM' | 'JUNO' | 'axlUSDC' symbol: 'OSMO' | 'ATOM' | 'JUNO' | 'axlUSDC' | 'stATOM'
contract_addr?: string contract_addr?: string
logo: string logo: string
decimals: number decimals: number
hasOraclePrice: boolean
poolId?: number poolId?: number
poolBase?: string
} }
interface OtherAsset extends Omit<Asset, 'symbol'> { interface OtherAsset extends Omit<Asset, 'symbol'> {
@ -33,6 +33,8 @@ interface RedBankAsset extends Asset {
incentiveInfo?: IncentiveInfo incentiveInfo?: IncentiveInfo
depositCap: number depositCap: number
depositLiquidity: numnber depositLiquidity: numnber
borrowEnabled: boolean
depositEnabled: boolean
// This is a hack, subRows can only contain same data model // This is a hack, subRows can only contain same data model
subRows?: DepositAsset[] subRows?: DepositAsset[]
} }

View File

@ -38,7 +38,8 @@ interface Position {
amounts: { amounts: {
primary: number primary: number
secondary: number secondary: number
borrowed: number borrowedPrimary: number
borrowedSecondary: number
lp: { lp: {
amount: string // Need to be string as number can be extremely large amount: string // Need to be string as number can be extremely large
primary: number primary: number
@ -49,7 +50,8 @@ interface Position {
values: { values: {
primary: number primary: number
secondary: number secondary: number
borrowed: number borrowedPrimary: number
borrowedSecondary: number
total: number total: number
net: number net: number
} }
@ -61,6 +63,7 @@ interface Position {
ltv: number ltv: number
currentLeverage: number currentLeverage: number
unlockAtTimestamp?: number unlockAtTimestamp?: number
borrowDenom: string | null
} }
interface PositionBarItem { interface PositionBarItem {

View File

@ -4,6 +4,7 @@ interface NetworkConfig {
rpcUrl: string rpcUrl: string
restUrl: string restUrl: string
apolloAprUrl: string apolloAprUrl: string
priceApiUrl: string
contracts: { contracts: {
redBank: string redBank: string
incentives: string incentives: string
@ -16,12 +17,14 @@ interface NetworkConfig {
whitelist: Asset[] whitelist: Asset[]
other: OtherAsset[] other: OtherAsset[]
} }
displayCurrency: { displayCurrency: displayCurrency
denom: string
prefix: string
suffix: string
decimals: number
}
appUrl: string appUrl: string
wallets: import('@marsprotocol/wallet-connector').WalletID[] wallets: import('@marsprotocol/wallet-connector').WalletID[]
} }
interface DisplayCurrency {
denom: string
prefix: string
suffix: string
decimals: number
}

View File

@ -1,5 +1,5 @@
interface RedBankData { interface RedBankData {
balance: { balance?: {
balance: import('@cosmjs/stargate').Coin[] balance: import('@cosmjs/stargate').Coin[]
} }
rbwasmkey: { rbwasmkey: {
@ -11,6 +11,8 @@ interface RedBankData {
JUNOMarketIncentive: MarketIncentive JUNOMarketIncentive: MarketIncentive
axlUSDCMarket: Market axlUSDCMarket: Market
axlUSDCMarketIncentive: MarketIncentive axlUSDCMarketIncentive: MarketIncentive
stATOMMarket: Market
stATOMMarketIncentive: MarketIncentive
collateral: UserCollateral[] collateral: UserCollateral[]
unclaimedRewards: string unclaimedRewards: string
} }
@ -44,7 +46,9 @@ interface InterestRateModel {
interface MarketIncentive { interface MarketIncentive {
denom: string denom: string
emission_per_second: number emission_per_second: string
index: number index: string
last_updated: number last_updated: number
start_time: number
duration: number
} }