Merge pull request #20 from mars-protocol/v1.4.1

release v1.4.1
This commit is contained in:
Linkie Link 2023-03-28 09:25:54 +02:00 committed by GitHub
commit 779b7b0825
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 147 additions and 125 deletions

View File

@ -1,9 +1,9 @@
{
"name": "mars",
"homepage": "./",
"version": "1.4.0",
"private": false,
"version": "1.4.1",
"license": "SEE LICENSE IN LICENSE FILE",
"private": false,
"scripts": {
"dev": "next dev",
"build": "yarn test && next build",

View File

@ -14,6 +14,7 @@ import {
useDepositAndDebt,
useMarsOracle,
useRedBank,
useUsdPrice,
useUserBalance,
useUserDebt,
useUserDeposit,
@ -155,6 +156,7 @@ export const CommonContainer = ({ children }: CommonContainerProps) => {
useUserDebt()
useMarsOracle()
useSpotPrice(MARS_SYMBOL)
useUsdPrice()
useDepositAndDebt()
useRedBank()

View File

@ -111,6 +111,7 @@
}
.button {
font-size: rem-calc(16);
@include margin(0, 0, 0, 2);
}

View File

@ -3,9 +3,9 @@ import { useQueryClient } from '@tanstack/react-query'
import BigNumber from 'bignumber.js'
import classNames from 'classnames'
import { Button, NumberInput, SVG, Toggle, Tooltip } from 'components/common'
import { FIELDS_FEATURE } from 'constants/appConstants'
import { DISPLAY_CURRENCY_KEY, ENABLE_ANIMATIONS_KEY, FIELDS_FEATURE } from 'constants/appConstants'
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import useStore from 'store'
import styles from './Settings.module.scss'
@ -19,33 +19,17 @@ export const Settings = () => {
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 currencyAssets = useStore((s) => s.currencyAssets)
const [customSlippage, setCustomSlippage] = useState<string>(inputPlaceholder)
const [inputRef, setInputRef] = useState<React.RefObject<HTMLInputElement>>()
const [isCustom, setIsCustom] = useState(false)
const enableAnimations = useStore((s) => s.enableAnimations)
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 [displayCurrency, setDisplayCurrency] = useState<DisplayCurrency>(
networkConfig?.displayCurrency,
)
const onInputChange = (value: number) => {
setCustomSlippage(value.toString())
@ -79,24 +63,25 @@ export const Settings = () => {
const changeReduceMotion = (reduce: boolean) => {
useStore.setState({ enableAnimations: !reduce })
localStorage.setItem('enableAnimations', reduce ? 'false' : 'true')
localStorage.setItem(ENABLE_ANIMATIONS_KEY, reduce ? 'false' : 'true')
}
const changeDisplayCurrency = (denom: string) => {
const selectedAsset = assets.find((asset) => asset.denom === denom)
const selectedAsset = currencyAssets.find((asset) => asset.denom === denom)
if (!selectedAsset || !networkConfig || !exchangeRates?.length) return
const newDisplayCurrency = {
denom: selectedAsset.denom,
prefix: '',
suffix: selectedAsset.symbol,
prefix: selectedAsset.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))
localStorage.setItem(DISPLAY_CURRENCY_KEY, JSON.stringify(newDisplayCurrency))
queryClient.invalidateQueries()
}
@ -135,9 +120,7 @@ export const Settings = () => {
<div className={styles.name}>
{t('common.displayCurrency')}
<Tooltip
content={t('common.tooltips.displayCurrency', {
baseCurrencySymbol: baseCurrency.symbol,
})}
content={<Trans i18nKey='common.tooltips.displayCurrency' />}
className={styles.tooltip}
/>
</div>
@ -148,9 +131,9 @@ export const Settings = () => {
tabIndex={2}
value={displayCurrency.denom}
>
{assets.map((currency) => (
{currencyAssets.map((currency) => (
<option key={currency.denom} value={currency.denom}>
{`${currency.name} (${currency.symbol})`}
{`${currency.name} ${currency.symbol && `(${currency.symbol})`}`}
</option>
))}
</select>
@ -200,6 +183,7 @@ export const Settings = () => {
maxDecimals={1}
maxLength={3}
className={styles.customSlippageBtn}
style={{ fontSize: 16 }}
/>
%
</button>

View File

@ -12,6 +12,7 @@ interface Props {
maxLength?: number
allowNegative?: boolean
suffix?: string
style?: {}
onChange: (value: number) => void
onBlur?: () => void
onFocus?: () => void
@ -139,7 +140,8 @@ export const NumberInput = (props: Props) => {
onFocus={onInputFocus}
onChange={(e) => onInputChange(e.target.value)}
onBlur={props.onBlur}
className={`${props.className} ${styles.input}`}
className={`${styles.input} ${props.className}`}
style={props.style}
/>
)
}

View File

@ -5,9 +5,9 @@ import {
BorrowCapacity,
Card,
DisplayCurrency,
Loading,
TextTooltip,
} from 'components/common'
import { Loading } from 'components/common'
import { VaultLogo, VaultName } from 'components/fields'
import { FIELDS_TUTORIAL_KEY } from 'constants/appConstants'
import { getLiqBorrowValue, getMaxBorrowValue } from 'functions/fields'
@ -58,6 +58,10 @@ export const ActiveVaultsTableMobile = () => {
<div className={styles.container}>
{activeVaults.map((vault, i) => {
const maxBorrowValue = getMaxBorrowValue(vault, vault.position)
const borrowKey =
vault.position.borrowDenom === vault.denoms.primary
? 'borrowedPrimary'
: 'borrowedSecondary'
const content = (
<div key={`${vault.address}-${i}`} className={styles.grid}>
@ -123,10 +127,7 @@ export const ActiveVaultsTableMobile = () => {
<DisplayCurrency
coin={{
denom: baseCurrency.denom,
amount: (vault.position.borrowDenom === vault.denoms.primary
? vault.position.amounts.borrowedPrimary
: vault.position.amounts.borrowedSecondary
).toString(),
amount: vault.position.values[borrowKey].toString(),
}}
className={styles.inline}
/>
@ -141,11 +142,7 @@ export const ActiveVaultsTableMobile = () => {
showPercentageText={true}
max={getLiqBorrowValue(vault, vault.position.values.net)}
limit={maxBorrowValue}
balance={
vault.position.borrowDenom === vault.denoms.primary
? vault.position.values.borrowedPrimary
: vault.position.values.borrowedSecondary
}
balance={vault.position.values[borrowKey]}
showTitle={false}
barHeight={'16px'}
hideValues

View File

@ -142,12 +142,14 @@ export const useActiveVaultsColumns = () => {
tooltip={
<>
{Number(coins[0].amount) > 0 && (
<>
<TokenBalance coin={coins[0]} maxDecimals={2} showSymbol />
)}
<br />
</>
)}
{Number(coins[1].amount) > 0 && (
<TokenBalance coin={coins[1]} maxDecimals={2} showSymbol />
)}{' '}
)}
</>
}
/>
@ -157,7 +159,7 @@ export const useActiveVaultsColumns = () => {
columnHelper.accessor('position.values.borrowedPrimary', {
enableSorting: true,
header: () => (
<TextTooltip text={t('common.borrowed')} tooltip={t('fields.tooltips.borrowValue')} />
<TextTooltip text={t('fields.debtValue')} tooltip={t('fields.tooltips.borrowValue')} />
),
cell: ({ row }) => {
const borrowAsset = whitelistedAssets.find(

View File

@ -103,11 +103,12 @@
border-left: 1px solid $alphaWhite20;
}
}
.bottomInfo {
display: flex;
justify-content: space-between;
gap: space(4);
align-items: center;
padding-right: space(2);
line-height: 1rem;
}
}

View File

@ -122,9 +122,11 @@ export const TokenInput = (props: Props) => {
coin={{ denom: asset.denom, amount: props.amount.toString() }}
/>
{props.borrowRate && (
<div>
<span className='xxsCaps number faded'>
{formatValue(props.borrowRate, 2, 2, true, false, `% ${t('common.apr')}`)}
</span>
</div>
)}
</div>
</div>

View File

@ -1,7 +1,6 @@
import { ChainInfoID, WalletID } from '@marsprotocol/wallet-connector'
import { URL_GQL, URL_REST, URL_RPC } from 'constants/env'
import atom from 'images/atom.svg'
import axlusdc from 'images/axlusdc.svg'
import juno from 'images/juno.svg'
import mars from 'images/mars.svg'
import osmo from 'images/osmo.svg'
@ -45,15 +44,14 @@ const OTHER_ASSETS: { [denom: string]: OtherAsset } = {
decimals: 6,
poolId: 768,
},
axlusdc: {
symbol: 'axlUSDC',
name: 'axlUSDC',
// This is the address / pool of DAI, not USDC
denom: 'ibc/88D70440A05BFB25C7FF0BA62DA357EAA993CB1B036077CF1DAAEFB28721D935',
color: colors.axlusdc,
logo: axlusdc,
decimals: 6,
poolId: 674,
usd: {
symbol: '',
prefix: '$',
name: 'US Dollar',
denom: 'usd',
color: '',
logo: '',
decimals: 2,
},
}
@ -65,7 +63,7 @@ export const NETWORK_CONFIG: NetworkConfig = {
rpcUrl: URL_RPC ?? 'https://rpc-test.osmosis.zone/',
restUrl: URL_REST ?? 'https://lcd-test.osmosis.zone/',
apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmo-test-4',
priceApiUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
osmoUsdPriceUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
contracts: {
redBank: 'osmo1t0dl6r27phqetfu0geaxrng0u9zn8qgrdwztapt5xr32adtwptaq6vwg36',
incentives: 'osmo1zxs8fry3m8j94pqg7h4muunyx86en27cl0xgk76fc839xg2qnn6qtpjs48',
@ -76,14 +74,10 @@ export const NETWORK_CONFIG: NetworkConfig = {
assets: {
base: ASSETS.osmo,
whitelist: [ASSETS.osmo, ASSETS.atom, ASSETS.juno],
other: [OTHER_ASSETS.mars, OTHER_ASSETS.axlusdc],
},
displayCurrency: {
denom: 'ibc/88D70440A05BFB25C7FF0BA62DA357EAA993CB1B036077CF1DAAEFB28721D935',
prefix: '',
suffix: 'axlUSDC',
decimals: 2,
other: [OTHER_ASSETS.usd, OTHER_ASSETS.mars],
currencies: [OTHER_ASSETS.usd, ASSETS.osmo, ASSETS.atom, ASSETS.juno, OTHER_ASSETS.mars],
},
displayCurrency: OTHER_ASSETS.usd,
appUrl: 'https://testnet.osmosis.zone',
wallets: [WalletID.Keplr, WalletID.Leap, WalletID.Cosmostation],
}

View File

@ -55,6 +55,15 @@ const OTHER_ASSETS: { [denom: string]: OtherAsset } = {
decimals: 6,
poolId: 907,
},
usd: {
symbol: '',
prefix: '$',
name: 'US Dollar',
denom: 'usd',
color: '',
logo: '',
decimals: 2,
},
}
export const NETWORK_CONFIG: NetworkConfig = {
@ -64,7 +73,7 @@ export const NETWORK_CONFIG: NetworkConfig = {
rpcUrl: URL_RPC ?? 'https://rpc-osmosis.blockapsis.com/',
restUrl: URL_REST ?? 'https://lcd-osmosis.blockapsis.com/',
apolloAprUrl: 'https://api.apollo.farm/api/vault_infos/v2/osmosis-1',
priceApiUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
osmoUsdPriceUrl: 'https://api-osmosis.imperator.co/tokens/v2/OSMO',
contracts: {
redBank: 'osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p9tenkrryasrle5sqf3ftpg',
incentives: 'osmo1nkahswfr8shg8rlxqwup0vgahp0dk4x8w6tkv3rra8rratnut36sk22vrm',
@ -75,14 +84,17 @@ export const NETWORK_CONFIG: NetworkConfig = {
assets: {
base: ASSETS.osmo,
whitelist: [ASSETS.osmo, ASSETS.atom, ASSETS.axlusdc, ASSETS.statom],
other: [OTHER_ASSETS.mars],
},
displayCurrency: {
denom: 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858',
prefix: '',
suffix: 'axlUSDC',
decimals: 2,
other: [OTHER_ASSETS.usd, OTHER_ASSETS.mars],
currencies: [
OTHER_ASSETS.usd,
ASSETS.osmo,
ASSETS.atom,
ASSETS.axlusdc,
ASSETS.statom,
OTHER_ASSETS.mars,
],
},
displayCurrency: OTHER_ASSETS.usd,
appUrl: 'https://app.osmosis.zone',
wallets: [
WalletID.Keplr,

View File

@ -37,3 +37,5 @@ export const STRATEGY_CURRENT_DEBT = 'strategyTotalDebt'
export const UNLOCK_DISCLAIMER_KEY = 'hideUnlockDisclaimer'
export const FIELDS_TUTORIAL_KEY = 'fieldsHideTutorial'
export const RED_BANK_TUTORIAL_KEY = 'redbankHideTutorial'
export const DISPLAY_CURRENCY_KEY = 'displayCurrency'
export const ENABLE_ANIMATIONS_KEY = 'enableAnimations'

View File

@ -8,12 +8,8 @@ export const getLeverageFromValues = (values: {
net: number
total: number
}) =>
Number(
new BigNumber(
values.borrowedPrimary > values.borrowedSecondary
? values.borrowedPrimary
: values.borrowedSecondary,
)
new BigNumber(values.borrowedPrimary)
.plus(values.borrowedSecondary)
.div(values.net || 1)
.plus(1),
)
.plus(1)
.toNumber()

View File

@ -1,9 +1,10 @@
import { ENABLE_ANIMATIONS_KEY } from 'constants/appConstants'
import { useCallback, useEffect } from 'react'
import useStore from 'store'
export const useAnimations = () => {
const enableAnimations = useStore((s) => s.enableAnimations)
const enableAnimationsLocalStorage = localStorage.getItem('enableAnimations')
const enableAnimationsLocalStorage = localStorage.getItem(ENABLE_ANIMATIONS_KEY)
const queryChangeHandler = useCallback(
(event: MediaQueryListEvent) => {

View File

@ -18,7 +18,7 @@ interface CoinPriceData {
}
export const useUsdPrice = () => {
const apiUrl = useStore((s) => s.networkConfig?.priceApiUrl ?? '')
const osmoUsdPriceUrl = useStore((s) => s.networkConfig?.osmoUsdPriceUrl ?? '')
const exchangeRates = useStore((s) => s.exchangeRates ?? [])
const networkConfig = useStore((s) => s.networkConfig)
const displayCurrency = networkConfig?.displayCurrency
@ -26,11 +26,11 @@ export const useUsdPrice = () => {
useQuery<CoinPriceData[]>(
[QUERY_KEYS.USD_PRICE],
async () => {
const res = await fetch(apiUrl)
const res = await fetch(osmoUsdPriceUrl)
return res.json()
},
{
enabled: !!apiUrl && !!exchangeRates.length && !!displayCurrency,
enabled: !!osmoUsdPriceUrl && !!exchangeRates.length && !!displayCurrency,
staleTime: 30000,
refetchInterval: 30000,
onSuccess: (data) => {
@ -39,7 +39,7 @@ export const useUsdPrice = () => {
useStore.setState({ baseToDisplayCurrencyRatio: data[0].price })
}
updateExchangeRate(coin, exchangeRates)
useStore.setState({ exchangeRates: updateExchangeRate(coin, exchangeRates) })
},
},
)

View File

@ -27,6 +27,7 @@ export interface CommonSlice {
baseToDisplayCurrencyRatio?: number
chainInfo?: SimplifiedChainInfo
client?: WalletClient
currencyAssets: (Asset | OtherAsset)[]
currentNetwork: Network
marketDebts: Coin[]
enableAnimations?: boolean

View File

@ -7,6 +7,7 @@ import {
WalletClient,
} from '@marsprotocol/wallet-connector'
import BigNumber from 'bignumber.js'
import { DISPLAY_CURRENCY_KEY } from 'constants/appConstants'
import { BlockHeightData } from 'hooks/queries/useBlockHeight'
import { DepositAndDebtData } from 'hooks/queries/useDepositAndDebt'
import { UserBalanceData } from 'hooks/queries/useUserBalance'
@ -31,6 +32,7 @@ const commonSlice = (
symbol: 'OSMO',
decimals: 6,
},
currencyAssets: [],
currentNetwork: Network.TESTNET,
errors: {
network: false,
@ -115,7 +117,7 @@ const commonSlice = (
config.NETWORK_CONFIG.rpcUrl = serializeUrl(config.NETWORK_CONFIG.rpcUrl)
config.NETWORK_CONFIG.restUrl = serializeUrl(config.NETWORK_CONFIG.restUrl)
const storageDisplayCurrency = localStorage.getItem('displayCurrency')
const storageDisplayCurrency = localStorage.getItem(DISPLAY_CURRENCY_KEY)
if (storageDisplayCurrency) {
config.NETWORK_CONFIG.displayCurrency = JSON.parse(storageDisplayCurrency)
}
@ -123,6 +125,7 @@ const commonSlice = (
set({
otherAssets: config.NETWORK_CONFIG.assets.other,
whitelistedAssets: config.NETWORK_CONFIG.assets.whitelist,
currencyAssets: config.NETWORK_CONFIG.assets.currencies,
networkConfig: config.NETWORK_CONFIG,
isNetworkLoaded: true,
baseAsset: config.NETWORK_CONFIG.assets.base,

View File

@ -324,17 +324,20 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
(unlockTime) => unlockTime?.vaultAddress === curr.address,
)?.unlockAtTimestamp
let primaryAmount = Number(
const primaryAmount = Number(
findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.primary)?.amount || 0,
)
let secondaryAmount = Number(
const secondaryAmount = Number(
findByDenom(primaryAndSecondaryAmount.coins, curr.denoms.secondary)?.amount || 0,
)
let primarySupplyAmount = 0
let secondarySupplyAmount = 0
let borrowedPrimaryAmount = 0
let borrowedSecondaryAmount = 0
const debt = creditAccountPosition.debts[0]
if (debt) {
if (debt.denom === curr.denoms.primary) {
borrowedPrimaryAmount = Number(debt.amount)
@ -343,8 +346,9 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
}
}
const borrowedDenom: string = creditAccountPosition.debts[0]?.denom || ''
const borrowedDenom = debt?.denom || ''
if (borrowedDenom === curr.denoms.primary) {
if (borrowedPrimaryAmount > primaryAmount) {
const swapped = Math.round(
get().convertToBaseCurrency({
@ -352,9 +356,18 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
amount: (borrowedPrimaryAmount - primaryAmount).toString(),
}),
)
secondaryAmount -= swapped
}
const rate = Number(
get().exchangeRates?.find((coin) => coin.denom === curr.denoms.secondary)
?.amount ?? 0,
)
primarySupplyAmount = 0
secondarySupplyAmount = Math.floor(secondaryAmount - swapped / rate)
} else {
primarySupplyAmount = primaryAmount - borrowedPrimaryAmount
secondarySupplyAmount = secondaryAmount
}
} else if (borrowedDenom === curr.denoms.secondary) {
if (borrowedSecondaryAmount > secondaryAmount) {
const swapped = Math.round(
get().convertToBaseCurrency({
@ -362,21 +375,28 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
amount: (borrowedSecondaryAmount - secondaryAmount).toString(),
}),
)
primaryAmount -= swapped
const rate = Number(
get().exchangeRates?.find((coin) => coin.denom === curr.denoms.primary)?.amount ??
0,
)
secondarySupplyAmount = 0
primarySupplyAmount = Math.floor(primaryAmount - swapped / rate)
} else {
secondarySupplyAmount = secondaryAmount - borrowedSecondaryAmount
primarySupplyAmount = primaryAmount
}
}
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 redBankAssets = get().redBankAssets
const primaryValue = convertToBaseCurrency({
const primarySupplyValue = convertToBaseCurrency({
denom: curr.denoms.primary,
amount: primarySupplyAmount.toString(),
})
const secondaryValue = convertToBaseCurrency({
const secondarySupplyValue = convertToBaseCurrency({
denom: curr.denoms.secondary,
amount: secondarySupplyAmount.toString(),
})
@ -387,12 +407,12 @@ export const vaultsSlice = (set: NamedSet<Store>, get: GetState<Store>): VaultsS
})
const values = {
primary: primaryValue,
secondary: secondaryValue,
primary: primarySupplyValue,
secondary: secondarySupplyValue,
borrowedPrimary: borrowedDenom === curr.denoms.primary ? borrowedValue : 0,
borrowedSecondary: borrowedDenom === curr.denoms.secondary ? borrowedValue : 0,
net: primaryValue + secondaryValue,
total: primaryValue + secondaryValue + borrowedValue,
net: primarySupplyValue + secondarySupplyValue,
total: primarySupplyValue + secondarySupplyValue + borrowedValue,
}
const leverage = getLeverageFromValues(values)

View File

@ -3,6 +3,7 @@ interface Asset {
name: string
denom: string
symbol: 'OSMO' | 'ATOM' | 'JUNO' | 'axlUSDC' | 'stATOM'
prefix?: string
contract_addr?: string
logo: string
decimals: number
@ -11,7 +12,7 @@ interface Asset {
}
interface OtherAsset extends Omit<Asset, 'symbol'> {
symbol: 'MARS' | 'axlUSDC'
symbol: 'MARS' | ''
}
interface AssetPairInfo {

View File

@ -4,7 +4,7 @@ interface NetworkConfig {
rpcUrl: string
restUrl: string
apolloAprUrl: string
priceApiUrl: string
osmoUsdPriceUrl: string
contracts: {
redBank: string
incentives: string
@ -16,6 +16,7 @@ interface NetworkConfig {
base: Asset
whitelist: Asset[]
other: OtherAsset[]
currencies: (Asset | OtherAsset)[]
}
displayCurrency: displayCurrency
appUrl: string