From 0a796a3d9457066334fc8dda682939e9e20991d8 Mon Sep 17 00:00:00 2001
From: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
Date: Fri, 14 Apr 2023 14:52:44 +0200
Subject: [PATCH] Mp 2435 display currency (#155)
---
src/components/Account/AccountList.tsx | 20 +------
src/components/Account/AccountStats.tsx | 11 ++--
src/components/AmountAndValue.tsx | 8 +--
src/components/BorrowModal.tsx | 1 -
src/components/DisplayCurrency.tsx | 51 ++++++++++++++++
src/components/Settings.tsx | 53 ++++++++++++++++-
src/constants/assets.ts | 3 +
src/pages/api/prices/index.ts | 9 +++
src/store/index.ts | 6 +-
src/store/slices/common.ts | 59 +------------------
src/store/slices/currency.ts | 18 ++++++
src/store/slices/modal.ts | 23 ++++++++
src/types/interfaces/asset.d.ts | 2 +
.../interfaces/hooks/useTokenPrices.d.ts | 8 ---
src/utils/assets.ts | 4 ++
15 files changed, 180 insertions(+), 96 deletions(-)
create mode 100644 src/components/DisplayCurrency.tsx
create mode 100644 src/store/slices/currency.ts
create mode 100644 src/store/slices/modal.ts
delete mode 100644 src/types/interfaces/hooks/useTokenPrices.d.ts
diff --git a/src/components/Account/AccountList.tsx b/src/components/Account/AccountList.tsx
index 2d68786b..60d7646d 100644
--- a/src/components/Account/AccountList.tsx
+++ b/src/components/Account/AccountList.tsx
@@ -28,14 +28,6 @@ const accountCardHeaderClasses = classNames(
'border border-transparent border-b-white/20',
)
-// TODO: Make this dynamic (token select)
-const formatOptions = {
- decimals: ASSETS[0].decimals,
- minDecimals: 0,
- maxDecimals: ASSETS[0].decimals,
- suffix: ` ${ASSETS[0].symbol}`,
-}
-
export default function AccountList(props: Props) {
const router = useRouter()
const params = useParams()
@@ -108,11 +100,7 @@ export default function AccountList(props: Props) {
{isActive ? (
<>
) : (
)}
diff --git a/src/components/Account/AccountStats.tsx b/src/components/Account/AccountStats.tsx
index efe1d672..2f2d2038 100644
--- a/src/components/Account/AccountStats.tsx
+++ b/src/components/Account/AccountStats.tsx
@@ -1,10 +1,11 @@
'use client'
+import DisplayCurrency from 'components/DisplayCurrency'
import { Heart, Shield } from 'components/Icons'
import { Text } from 'components/Text'
import useStore from 'store'
interface Props {
- balance: string
+ balance: number
risk: number
health: number
}
@@ -12,12 +13,14 @@ interface Props {
export default function AccountStats(props: Props) {
const enableAnimations = useStore((s) => s.enableAnimations)
const healthBarWidth = 53 * props.health
+ const baseCurrency = useStore((s) => s.baseCurrency)
return (
-
- {props.balance}
-
+
diff --git a/src/components/AmountAndValue.tsx b/src/components/AmountAndValue.tsx
index e27fc7aa..2bbb92de 100644
--- a/src/components/AmountAndValue.tsx
+++ b/src/components/AmountAndValue.tsx
@@ -1,5 +1,6 @@
import { FormattedNumber } from 'components/FormattedNumber'
import TitleAndSubCell from 'components/TitleAndSubCell'
+import DisplayCurrency from 'components/DisplayCurrency'
interface Props {
asset: Asset
@@ -15,12 +16,7 @@ export default function AmountAndValue(props: Props) {
options={{ decimals: props.asset.decimals, abbreviated: true }}
/>
}
- sub={
-
- }
+ sub={}
className='justify-end'
/>
)
diff --git a/src/components/BorrowModal.tsx b/src/components/BorrowModal.tsx
index 29aa7cff..78e88091 100644
--- a/src/components/BorrowModal.tsx
+++ b/src/components/BorrowModal.tsx
@@ -1,4 +1,3 @@
-import BigNumber from 'bignumber.js'
import Image from 'next/image'
import { useState } from 'react'
diff --git a/src/components/DisplayCurrency.tsx b/src/components/DisplayCurrency.tsx
new file mode 100644
index 00000000..e6fb0bcc
--- /dev/null
+++ b/src/components/DisplayCurrency.tsx
@@ -0,0 +1,51 @@
+import { Coin } from '@cosmjs/stargate'
+import BigNumber from 'bignumber.js'
+
+import useStore from 'store'
+import { getMarketAssets } from 'utils/assets'
+
+import { FormattedNumber } from './FormattedNumber'
+
+interface Props {
+ coin: Coin
+ className?: string
+ prefixClassName?: string
+ valueClassName?: string
+ isApproximation?: boolean
+}
+
+export default function DisplayCurrency(props: Props) {
+ const displayCurrency = useStore((s) => s.displayCurrency)
+ const prices = useStore((s) => s.prices)
+
+ function convertToDisplayAmount(coin: Coin) {
+ const price = prices.find((price) => price.denom === coin.denom)
+ const asset = getMarketAssets().find((asset) => asset.denom === coin.denom)
+
+ const displayPrice = prices.find((price) => price.denom === displayCurrency.denom)
+
+ if (!price || !asset || !displayPrice) return '0'
+
+ return new BigNumber(coin.amount)
+ .times(price.amount)
+ .div(displayPrice.amount)
+ .integerValue(BigNumber.ROUND_HALF_DOWN)
+ .toNumber()
+ }
+
+ return (
+
+ )
+}
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
index 5f70a54f..31c65f75 100644
--- a/src/components/Settings.tsx
+++ b/src/components/Settings.tsx
@@ -8,15 +8,29 @@ import { Overlay } from 'components/Overlay/Overlay'
import Switch from 'components/Switch'
import { Text } from 'components/Text'
import { Tooltip } from 'components/Tooltip'
-import { ENABLE_ANIMATIONS_KEY } from 'constants/localStore'
+import { DISPLAY_CURRENCY_KEY, ENABLE_ANIMATIONS_KEY } from 'constants/localStore'
import { useAnimations } from 'hooks/useAnimations'
import useStore from 'store'
+import { getDisplayCurrencies } from 'utils/assets'
+import { ASSETS } from 'constants/assets'
export default function Settings() {
useAnimations()
const [showMenu, setShowMenu] = useState(false)
const enableAnimations = useStore((s) => s.enableAnimations)
+ const displayCurrency = useStore((s) => s.displayCurrency)
+ const displayCurrencies = getDisplayCurrencies()
+
+ const storageDisplayCurrency = localStorage.getItem(DISPLAY_CURRENCY_KEY)
+ if (storageDisplayCurrency) {
+ const storedDisplayCurrency = ASSETS.find(
+ (asset) => asset.symbol === JSON.parse(storageDisplayCurrency).symbol,
+ )
+ if (storedDisplayCurrency && storedDisplayCurrency !== displayCurrency) {
+ setDisplayCurrency(storedDisplayCurrency)
+ }
+ }
function handleReduceMotion(val: boolean) {
useStore.setState({ enableAnimations: !val })
@@ -24,6 +38,18 @@ export default function Settings() {
window.localStorage.setItem(ENABLE_ANIMATIONS_KEY, val ? 'false' : 'true')
}
+ function handleCurrencyChange(e: React.ChangeEvent) {
+ const displayCurrency = displayCurrencies.find((c) => c.symbol === e.target.value)
+ if (!displayCurrency) return
+
+ setDisplayCurrency(displayCurrency)
+ }
+
+ function setDisplayCurrency(displayCurrency: Asset) {
+ useStore.setState({ displayCurrency: displayCurrency })
+ localStorage.setItem(DISPLAY_CURRENCY_KEY, JSON.stringify(displayCurrency))
+ }
+
return (
+
+
+
+ Display Currency
+
+
+ Sets the denomination of values to a different currency. While OSMO is the
+ currency the TWAP oracles return. All other values are fetched from liquidity
+ pools.
+
+ }
+ />
+
+
+
diff --git a/src/constants/assets.ts b/src/constants/assets.ts
index 32b90097..f6282dc5 100644
--- a/src/constants/assets.ts
+++ b/src/constants/assets.ts
@@ -11,6 +11,7 @@ export const ASSETS: Asset[] = [
logo: '/tokens/osmo.svg',
isEnabled: true,
isMarket: true,
+ isDisplayCurrency: true,
},
{
symbol: 'ATOM',
@@ -22,6 +23,7 @@ export const ASSETS: Asset[] = [
hasOraclePrice: true,
isEnabled: IS_TESTNET ? true : false,
isMarket: true,
+ isDisplayCurrency: true,
},
{
symbol: 'CRO',
@@ -58,5 +60,6 @@ export const ASSETS: Asset[] = [
hasOraclePrice: true,
isMarket: IS_TESTNET,
isEnabled: true,
+ isDisplayCurrency: true,
},
]
diff --git a/src/pages/api/prices/index.ts b/src/pages/api/prices/index.ts
index 9982d7ec..545a7233 100644
--- a/src/pages/api/prices/index.ts
+++ b/src/pages/api/prices/index.ts
@@ -37,3 +37,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return res.status(200).json(data)
}
+
+interface TokenPricesResult {
+ prices: {
+ [key: string]: {
+ denom: string
+ price: string
+ }
+ }
+}
diff --git a/src/store/index.ts b/src/store/index.ts
index 964f8c9a..976f17ba 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -3,12 +3,16 @@ import { devtools } from 'zustand/middleware'
import { BroadcastSlice, createBroadcastSlice } from 'store/slices/broadcast'
import { CommonSlice, createCommonSlice } from 'store/slices/common'
+import { createCurrencySlice, CurrencySlice } from 'store/slices/currency'
+import { createModalSlice, ModalSlice } from 'store/slices/modal'
-export interface Store extends CommonSlice, BroadcastSlice {}
+export interface Store extends CommonSlice, BroadcastSlice, CurrencySlice, ModalSlice {}
const store = (set: SetState
, get: GetState) => ({
...createCommonSlice(set, get),
...createBroadcastSlice(set, get),
+ ...createCurrencySlice(set, get),
+ ...createModalSlice(set, get),
})
let useStore: UseBoundStore>
diff --git a/src/store/slices/common.ts b/src/store/slices/common.ts
index fdd14179..4b789241 100644
--- a/src/store/slices/common.ts
+++ b/src/store/slices/common.ts
@@ -2,78 +2,23 @@ import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { WalletClient, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
import { GetState, SetState } from 'zustand'
-import { ENV } from 'constants/env'
-import { MarsAccountNftClient } from 'types/generated/mars-account-nft/MarsAccountNft.client'
-import { MarsCreditManagerClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
-import { MarsSwapperBaseClient } from 'types/generated/mars-swapper-base/MarsSwapperBase.client'
-
export interface CommonSlice {
accounts: Account[] | null
address?: string
- borrowModal: {
- asset: Asset
- marketData: BorrowAsset | BorrowAssetActive
- isRepay?: boolean
- } | null
- client?: WalletClient
- clients: {
- accountNft?: MarsAccountNftClient
- creditManager?: MarsCreditManagerClient
- swapperBase?: MarsSwapperBaseClient
- }
- createAccountModal: boolean
- deleteAccountModal: boolean
enableAnimations: boolean
- fundAccountModal: boolean
isOpen: boolean
- prices: Coin[]
selectedAccount: string | null
- signingClient?: SigningCosmWasmClient
+ client?: WalletClient
status: WalletConnectionStatus
- withdrawModal: boolean
- initClients: (address: string, signingClient: SigningCosmWasmClient) => void
}
export function createCommonSlice(set: SetState, get: GetState) {
return {
accounts: null,
- borrowModal: null,
- createAccountModal: false,
- clients: {},
- deleteAccountModal: false,
+ creditAccounts: null,
enableAnimations: true,
- fundAccountModal: false,
isOpen: true,
- prices: [],
- repayModal: false,
selectedAccount: null,
status: WalletConnectionStatus.Unconnected,
- withdrawModal: false,
- initClients: (address: string, signingClient: SigningCosmWasmClient) => {
- if (!signingClient) return
- const accountNft = new MarsAccountNftClient(
- signingClient,
- address,
- ENV.ADDRESS_ACCOUNT_NFT || '',
- )
- const creditManager = new MarsCreditManagerClient(
- signingClient,
- address,
- ENV.ADDRESS_CREDIT_MANAGER || '',
- )
- const swapperBase = new MarsSwapperBaseClient(
- signingClient,
- address,
- ENV.ADDRESS_SWAPPER || '',
- )
-
- set(() => ({
- clients: {
- accountNft,
- creditManager,
- swapperBase,
- },
- }))
- },
}
}
diff --git a/src/store/slices/currency.ts b/src/store/slices/currency.ts
new file mode 100644
index 00000000..9925f676
--- /dev/null
+++ b/src/store/slices/currency.ts
@@ -0,0 +1,18 @@
+import { Coin } from '@cosmjs/stargate'
+import { GetState, SetState } from 'zustand'
+
+import { ASSETS } from 'constants/assets'
+
+export interface CurrencySlice {
+ baseCurrency: Asset
+ displayCurrency: Asset
+ prices: Coin[]
+}
+
+export function createCurrencySlice(set: SetState, get: GetState) {
+ return {
+ baseCurrency: ASSETS[0],
+ displayCurrency: ASSETS.find((asset) => asset.denom === ASSETS[0].denom)!,
+ prices: [],
+ }
+}
diff --git a/src/store/slices/modal.ts b/src/store/slices/modal.ts
new file mode 100644
index 00000000..f2c1582c
--- /dev/null
+++ b/src/store/slices/modal.ts
@@ -0,0 +1,23 @@
+import { GetState, SetState } from 'zustand'
+
+export interface ModalSlice {
+ borrowModal: {
+ asset: Asset
+ marketData: BorrowAsset | BorrowAssetActive
+ isRepay?: boolean
+ } | null
+ createAccountModal: boolean
+ deleteAccountModal: boolean
+ fundAccountModal: boolean
+ withdrawModal: boolean
+}
+
+export function createModalSlice(set: SetState, get: GetState) {
+ return {
+ borrowModal: null,
+ createAccountModal: false,
+ deleteAccountModal: false,
+ fundAccountModal: false,
+ withdrawModal: false,
+ }
+}
diff --git a/src/types/interfaces/asset.d.ts b/src/types/interfaces/asset.d.ts
index 4ec1c4f1..33d55d20 100644
--- a/src/types/interfaces/asset.d.ts
+++ b/src/types/interfaces/asset.d.ts
@@ -3,6 +3,7 @@ interface Asset {
name: string
denom: string
symbol: 'OSMO' | 'ATOM' | 'CRO' | 'MARS' | 'JUNO'
+ prefix?: string
contract_addr?: string
logo: string
decimals: number
@@ -10,6 +11,7 @@ interface Asset {
poolId?: number
isEnabled: boolean
isMarket: boolean
+ isDisplayCurrency?: boolean
}
interface OtherAsset extends Omit {
diff --git a/src/types/interfaces/hooks/useTokenPrices.d.ts b/src/types/interfaces/hooks/useTokenPrices.d.ts
deleted file mode 100644
index 562716e0..00000000
--- a/src/types/interfaces/hooks/useTokenPrices.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-interface TokenPricesResult {
- prices: {
- [key: string]: {
- denom: string
- price: string
- }
- }
-}
diff --git a/src/utils/assets.ts b/src/utils/assets.ts
index 524365d6..85b062ac 100644
--- a/src/utils/assets.ts
+++ b/src/utils/assets.ts
@@ -15,3 +15,7 @@ export function getMarketAssets(): Asset[] {
export function getBaseAsset() {
return ASSETS.find((asset) => asset.denom === 'uosmo')!
}
+
+export function getDisplayCurrencies() {
+ return ASSETS.filter((asset) => asset.isDisplayCurrency)
+}