MP-2891 and MP-2801 (#321)
* MP-2801: fund new credit account * tidy: cleanup * tidy: refactor * feat: replaced all possible BN(0) & BN(1) occurrences with constants * fix: adjusted according to feedback * fix: adjustments according to feedback * fix: PR comment updates * fix: reduced complexity * feat: animated the wallet balance for the demo * fix: enhanced wallet connection to select first account * fix: adjusted the calculations and added USD as displayCurrency * fix: adjusted according to feedback * feat: added TFM bridge * fix: changed forceFetchPrice --------- Co-authored-by: Yusuf Seyrek <yusuf@delphilabs.io>
This commit is contained in:
parent
bb6a9b99e3
commit
184a27e987
BIN
public/images/bridges/tfm.png
Normal file
BIN
public/images/bridges/tfm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
@ -1,11 +1,12 @@
|
|||||||
import { getAssetsMustHavePriceInfo } from 'utils/assets'
|
import getOraclePrices from 'api/prices/getOraclePrices'
|
||||||
import { partition } from 'utils/array'
|
|
||||||
import getPoolPrice from 'api/prices/getPoolPrice'
|
import getPoolPrice from 'api/prices/getPoolPrice'
|
||||||
import fetchPythPrices from 'api/prices/getPythPrices'
|
import fetchPythPrices from 'api/prices/getPythPrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import getOraclePrices from 'api/prices/getOraclePrices'
|
import { partition } from 'utils/array'
|
||||||
|
import { getAssetsMustHavePriceInfo } from 'utils/assets'
|
||||||
|
|
||||||
export default async function getPrices(): Promise<BNCoin[]> {
|
export default async function getPrices(): Promise<BNCoin[]> {
|
||||||
|
const usdPrice = new BNCoin({ denom: 'usd', amount: '1' })
|
||||||
try {
|
try {
|
||||||
const assetsToFetchPrices = getAssetsMustHavePriceInfo()
|
const assetsToFetchPrices = getAssetsMustHavePriceInfo()
|
||||||
const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] =
|
const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] =
|
||||||
@ -19,7 +20,7 @@ export default async function getPrices(): Promise<BNCoin[]> {
|
|||||||
).flat()
|
).flat()
|
||||||
const poolPrices = await requestPoolPrices(assetsWithPoolIds, pythAndOraclePrices)
|
const poolPrices = await requestPoolPrices(assetsWithPoolIds, pythAndOraclePrices)
|
||||||
|
|
||||||
return [...pythAndOraclePrices, ...poolPrices]
|
return [...pythAndOraclePrices, ...poolPrices, usdPrice]
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex)
|
console.error(ex)
|
||||||
throw ex
|
throw ex
|
||||||
|
@ -14,13 +14,14 @@ import { FormattedNumber } from 'components/FormattedNumber'
|
|||||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { ASSETS } from 'constants/assets'
|
import { ASSETS } from 'constants/assets'
|
||||||
import usePrices from 'hooks/usePrices'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { convertToDisplayAmount, demagnify } from 'utils/formatters'
|
|
||||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
|
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
import { convertToDisplayAmount, demagnify } from 'utils/formatters'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: Account
|
data: Account
|
||||||
@ -106,14 +107,15 @@ export const AccountBalancesTable = (props: Props) => {
|
|||||||
accessorKey: 'size',
|
accessorKey: 'size',
|
||||||
header: 'Size',
|
header: 'Size',
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
|
const amount = demagnify(
|
||||||
|
row.original.amount,
|
||||||
|
getAssetByDenom(row.original.denom) ?? ASSETS[0],
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className='text-right text-xs'
|
className='text-right text-xs'
|
||||||
amount={demagnify(
|
amount={Number(BN(amount).toPrecision(2))}
|
||||||
row.original.amount,
|
options={{ maxDecimals: 2, abbreviated: true }}
|
||||||
ASSETS.find((asset) => asset.denom === row.original.denom) ?? ASSETS[0],
|
|
||||||
)}
|
|
||||||
options={{ maxDecimals: 4 }}
|
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -6,14 +6,14 @@ import { FormattedNumber } from 'components/FormattedNumber'
|
|||||||
import { ArrowRight } from 'components/Icons'
|
import { ArrowRight } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import {
|
import {
|
||||||
calculateAccountApr,
|
calculateAccountApr,
|
||||||
calculateAccountBorrowRate,
|
calculateAccountBorrowRate,
|
||||||
calculateAccountDebt,
|
calculateAccountDebtValue,
|
||||||
calculateAccountDeposits,
|
calculateAccountDepositsValue,
|
||||||
calculateAccountPnL,
|
calculateAccountPnL,
|
||||||
} from 'utils/accounts'
|
} from 'utils/accounts'
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ interface ItemProps {
|
|||||||
|
|
||||||
export default function AccountComposition(props: Props) {
|
export default function AccountComposition(props: Props) {
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const balance = calculateAccountDeposits(props.account, prices)
|
const balance = calculateAccountDepositsValue(props.account, prices)
|
||||||
const balanceChange = props.change ? calculateAccountDeposits(props.change, prices) : BN_ZERO
|
const balanceChange = props.change ? calculateAccountDepositsValue(props.change, prices) : BN_ZERO
|
||||||
const debtBalance = calculateAccountDebt(props.account, prices)
|
const debtBalance = calculateAccountDebtValue(props.account, prices)
|
||||||
const debtBalanceChange = props.change ? calculateAccountDebt(props.change, prices) : BN_ZERO
|
const debtBalanceChange = props.change ? calculateAccountDebtValue(props.change, prices) : BN_ZERO
|
||||||
const pnL = calculateAccountPnL(props.account, prices)
|
const pnL = calculateAccountPnL(props.account, prices)
|
||||||
const pnLChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
const pnLChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
||||||
const apr = calculateAccountApr(props.account, prices)
|
const apr = calculateAccountApr(props.account, prices)
|
||||||
@ -78,7 +78,6 @@ export default function AccountComposition(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Item(props: ItemProps) {
|
function Item(props: ItemProps) {
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
|
||||||
const increase = props.isBadIncrease
|
const increase = props.isBadIncrease
|
||||||
? props.current.isGreaterThan(props.change)
|
? props.current.isGreaterThan(props.change)
|
||||||
: props.current.isLessThan(props.change)
|
: props.current.isLessThan(props.change)
|
||||||
@ -99,7 +98,7 @@ function Item(props: ItemProps) {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={new BNCoin({ amount: props.current.toString(), denom: baseCurrency.denom })}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.current)}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -117,7 +116,7 @@ function Item(props: ItemProps) {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={new BNCoin({ amount: props.change.toString(), denom: baseCurrency.denom })}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.change)}
|
||||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -1,25 +1,34 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
|
import AccountFundFirst from 'components/Account/AccountFund'
|
||||||
import FullOverlayContent from 'components/FullOverlayContent'
|
import FullOverlayContent from 'components/FullOverlayContent'
|
||||||
|
import WalletSelect from 'components/Wallet/WalletSelect'
|
||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
export default function AccountCreateFirst() {
|
export default function AccountCreateFirst() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { pathname } = useLocation()
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
const createAccount = useStore((s) => s.createAccount)
|
const createAccount = useStore((s) => s.createAccount)
|
||||||
const [isCreating, setIsCreating] = useToggle(false)
|
const [isCreating, setIsCreating] = useToggle(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!address) useStore.setState({ focusComponent: <WalletSelect /> })
|
||||||
|
}, [address])
|
||||||
|
|
||||||
const handleClick = useCallback(async () => {
|
const handleClick = useCallback(async () => {
|
||||||
setIsCreating(true)
|
setIsCreating(true)
|
||||||
const accountId = await createAccount({ fee: hardcodedFee })
|
const accountId = await createAccount({ fee: hardcodedFee })
|
||||||
setIsCreating(false)
|
setIsCreating(false)
|
||||||
// TODO: set focusComponent to fund account
|
if (accountId) {
|
||||||
useStore.setState({ focusComponent: null })
|
navigate(getRoute(getPage(pathname), address, accountId))
|
||||||
accountId && navigate(`/wallets/${address}/accounts/${accountId}`)
|
useStore.setState({ focusComponent: <AccountFundFirst /> })
|
||||||
}, [address, createAccount, navigate, setIsCreating])
|
}
|
||||||
|
}, [createAccount, navigate, pathname, address, setIsCreating])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullOverlayContent
|
<FullOverlayContent
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { Gauge } from 'components/Gauge'
|
import { Gauge } from 'components/Gauge'
|
||||||
import { Heart } from 'components/Icons'
|
import { Heart } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { calculateAccountBalanceValue } from 'utils/accounts'
|
||||||
import { formatHealth } from 'utils/formatters'
|
import { formatHealth } from 'utils/formatters'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account
|
account: Account
|
||||||
@ -13,27 +20,35 @@ interface Props {
|
|||||||
export default function AccountDetailsController() {
|
export default function AccountDetailsController() {
|
||||||
const account = useCurrentAccount()
|
const account = useCurrentAccount()
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
|
|
||||||
if (!account || !address) return null
|
if (!account || !address || focusComponent) return null
|
||||||
|
|
||||||
return <AccountDetails account={account} />
|
return <AccountDetails account={account} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function AccountDetails(props: Props) {
|
function AccountDetails(props: Props) {
|
||||||
const { health } = useHealthComputer(props.account)
|
const { health } = useHealthComputer(props.account)
|
||||||
|
const { data: prices } = usePrices()
|
||||||
|
const accountBalanceValue = calculateAccountBalanceValue(props.account, prices)
|
||||||
|
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
||||||
|
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid='account-details'
|
data-testid='account-details'
|
||||||
className='w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'
|
className='w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'
|
||||||
>
|
>
|
||||||
<div className='flex w-full flex-wrap justify-center py-4'>
|
<div className='flex w-full flex-wrap justify-center py-4'>
|
||||||
<Gauge tooltip='Health Factor' percentage={20} icon={<Heart />} />
|
<Gauge tooltip='Health Factor' percentage={healthFactor} icon={<Heart />} />
|
||||||
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||||
Health
|
Health
|
||||||
</Text>
|
</Text>
|
||||||
<Text size='xs' className='w-full text-center'>
|
<FormattedNumber
|
||||||
{formatHealth(health)}
|
className={'w-full text-center text-xs'}
|
||||||
</Text>
|
amount={healthFactor}
|
||||||
|
options={{ maxDecimals: 0, minDecimals: 0 }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full border border-x-0 border-white/20 py-4'>
|
<div className='w-full border border-x-0 border-white/20 py-4'>
|
||||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||||
@ -43,13 +58,11 @@ function AccountDetails(props: Props) {
|
|||||||
4.5x
|
4.5x
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full py-4'>
|
<div className='w-full px-1 py-4'>
|
||||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||||
Balance
|
Balance
|
||||||
</Text>
|
</Text>
|
||||||
<Text size='xs' className='w-full text-center'>
|
<DisplayCurrency coin={coin} className='w-full truncate text-center text-2xs ' />
|
||||||
$300M
|
|
||||||
</Text>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
170
src/components/Account/AccountFund.tsx
Normal file
170
src/components/Account/AccountFund.tsx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import FullOverlayContent from 'components/FullOverlayContent'
|
||||||
|
import { Plus } from 'components/Icons'
|
||||||
|
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||||
|
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useAccounts from 'hooks/useAccounts'
|
||||||
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
|
import useToggle from 'hooks/useToggle'
|
||||||
|
import useWalletBalances from 'hooks/useWalletBalances'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
||||||
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
|
export default function AccountFund() {
|
||||||
|
const address = useStore((s) => s.address)
|
||||||
|
const deposit = useStore((s) => s.deposit)
|
||||||
|
const walletAssetModal = useStore((s) => s.walletAssetsModal)
|
||||||
|
const { accountId } = useParams()
|
||||||
|
const { data: accounts } = useAccounts(address)
|
||||||
|
const currentAccount = useCurrentAccount()
|
||||||
|
const [isFunding, setIsFunding] = useToggle(false)
|
||||||
|
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
|
||||||
|
const [fundingAssets, setFundingAssets] = useState<Coin[]>([])
|
||||||
|
const { data: walletBalances } = useWalletBalances(address)
|
||||||
|
const baseAsset = getBaseAsset()
|
||||||
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId ?? '0')
|
||||||
|
const hasAssetSelected = fundingAssets.length > 0
|
||||||
|
const hasFundingAssets = fundingAssets.length > 0 && fundingAssets.every((a) => a.amount !== '0')
|
||||||
|
|
||||||
|
const baseBalance = useMemo(
|
||||||
|
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||||
|
[walletBalances, baseAsset],
|
||||||
|
)
|
||||||
|
|
||||||
|
const selectedDenoms = useMemo(() => {
|
||||||
|
return walletAssetModal?.selectedDenoms ?? []
|
||||||
|
}, [walletAssetModal?.selectedDenoms])
|
||||||
|
|
||||||
|
const handleClick = useCallback(async () => {
|
||||||
|
setIsFunding(true)
|
||||||
|
if (!accountId) return
|
||||||
|
const result = await deposit({
|
||||||
|
fee: hardcodedFee,
|
||||||
|
accountId,
|
||||||
|
coins: fundingAssets,
|
||||||
|
})
|
||||||
|
setIsFunding(false)
|
||||||
|
if (result) useStore.setState({ focusComponent: null, walletAssetsModal: null })
|
||||||
|
}, [fundingAssets, accountId, setIsFunding, deposit])
|
||||||
|
|
||||||
|
const handleSelectAssetsClick = useCallback(() => {
|
||||||
|
useStore.setState({
|
||||||
|
walletAssetsModal: {
|
||||||
|
isOpen: true,
|
||||||
|
selectedDenoms,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}, [selectedDenoms])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentSelectedDenom = fundingAssets.map((asset) => asset.denom)
|
||||||
|
|
||||||
|
if (
|
||||||
|
selectedDenoms.every((denom) => currentSelectedDenom.includes(denom)) &&
|
||||||
|
selectedDenoms.length === currentSelectedDenom.length
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
const newFundingAssets = selectedDenoms.map((denom) => ({
|
||||||
|
denom,
|
||||||
|
amount: fundingAssets.find((asset) => asset.denom === denom)?.amount ?? '0',
|
||||||
|
}))
|
||||||
|
|
||||||
|
setFundingAssets(newFundingAssets)
|
||||||
|
}, [selectedDenoms, fundingAssets])
|
||||||
|
|
||||||
|
const updateFundingAssets = useCallback(
|
||||||
|
(amount: BigNumber, denom: string) => {
|
||||||
|
const assetToUpdate = fundingAssets.find((asset) => asset.denom === denom)
|
||||||
|
if (assetToUpdate) {
|
||||||
|
assetToUpdate.amount = amount.toString()
|
||||||
|
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[fundingAssets],
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) {
|
||||||
|
useStore.setState({ focusComponent: <WalletBridges /> })
|
||||||
|
}
|
||||||
|
}, [baseBalance])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (accounts && !selectedAccountId && accountId)
|
||||||
|
setSelectedAccountId(currentAccount?.id ?? accountId)
|
||||||
|
}, [accounts, selectedAccountId, accountId, currentAccount])
|
||||||
|
|
||||||
|
if (!selectedAccountId) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FullOverlayContent
|
||||||
|
title={`Fund Credit Account #${selectedAccountId}`}
|
||||||
|
copy='In order to start trading with this account, you need to deposit funds.'
|
||||||
|
docs='fund'
|
||||||
|
>
|
||||||
|
<Card className='w-full bg-white/5 p-6'>
|
||||||
|
{!hasAssetSelected && <Text>Please select an asset.</Text>}
|
||||||
|
{selectedDenoms.map((denom) => {
|
||||||
|
const asset = getAssetByDenom(denom) as Asset
|
||||||
|
|
||||||
|
const balance = walletBalances.find(byDenom(asset.denom))?.amount ?? '0'
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={asset.symbol}
|
||||||
|
className='w-full rounded-base border border-white/20 bg-white/5 p-4'
|
||||||
|
>
|
||||||
|
<TokenInputWithSlider
|
||||||
|
asset={asset}
|
||||||
|
onChange={(amount) => updateFundingAssets(amount, asset.denom)}
|
||||||
|
amount={BN_ZERO}
|
||||||
|
max={BN(balance)}
|
||||||
|
balances={walletBalances}
|
||||||
|
maxText='Max'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className='mt-4 w-full'
|
||||||
|
text='Select assets'
|
||||||
|
color='tertiary'
|
||||||
|
rightIcon={<Plus />}
|
||||||
|
iconClassName='w-3'
|
||||||
|
onClick={handleSelectAssetsClick}
|
||||||
|
/>
|
||||||
|
<div className='mt-4 border border-transparent border-t-white/10 pt-4'>
|
||||||
|
<SwitchWithLabel
|
||||||
|
name='isLending'
|
||||||
|
label='Lend assets to earn yield'
|
||||||
|
value={isAutoLendEnabled}
|
||||||
|
onChange={() => toggleAutoLend(selectedAccountId)}
|
||||||
|
tooltip={`Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className='mt-4 w-full'
|
||||||
|
text='Fund account'
|
||||||
|
color='tertiary'
|
||||||
|
disabled={!hasFundingAssets}
|
||||||
|
showProgressIndicator={isFunding}
|
||||||
|
onClick={handleClick}
|
||||||
|
size='lg'
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</FullOverlayContent>
|
||||||
|
)
|
||||||
|
}
|
@ -2,6 +2,7 @@ import classNames from 'classnames'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import AccountFundFirst from 'components/Account/AccountFund'
|
||||||
import AccountStats from 'components/Account/AccountStats'
|
import AccountStats from 'components/Account/AccountStats'
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
@ -9,16 +10,18 @@ import { ArrowCircledTopRight, ArrowDownLine, ArrowUpLine, TrashBin } from 'comp
|
|||||||
import Radio from 'components/Radio'
|
import Radio from 'components/Radio'
|
||||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
|
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { calculateAccountDeposits } from 'utils/accounts'
|
import { calculateAccountBalanceValue, calculateAccountDepositsValue } from 'utils/accounts'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
import usePrices from 'hooks/usePrices'
|
|
||||||
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
setShowFundAccount: (showFundAccount: boolean) => void
|
|
||||||
accounts: Account[]
|
accounts: Account[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,18 +37,17 @@ export default function AccountList(props: Props) {
|
|||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
const deleteAccount = useStore((s) => s.deleteAccount)
|
const deleteAccount = useStore((s) => s.deleteAccount)
|
||||||
|
|
||||||
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
||||||
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
||||||
const selectedAccountBalance = selectedAccountDetails
|
const selectedAccountBalance = selectedAccountDetails
|
||||||
? calculateAccountDeposits(selectedAccountDetails, prices)
|
? calculateAccountBalanceValue(selectedAccountDetails, prices)
|
||||||
: BN_ZERO
|
: BN_ZERO
|
||||||
|
|
||||||
async function deleteAccountHandler() {
|
async function deleteAccountHandler() {
|
||||||
if (!accountSelected) return
|
if (!accountSelected) return
|
||||||
const isSuccess = await deleteAccount({ fee: hardcodedFee, accountId: accountId })
|
const isSuccess = await deleteAccount({ fee: hardcodedFee, accountId: accountId })
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
navigate(`/wallets/${address}/accounts`)
|
navigate(getRoute(getPage(pathname), address))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ export default function AccountList(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className='flex w-full flex-wrap p-4'>
|
<div className='flex w-full flex-wrap p-4'>
|
||||||
{props.accounts.map((account) => {
|
{props.accounts.map((account) => {
|
||||||
const positionBalance = calculateAccountDeposits(account, prices)
|
const positionBalance = calculateAccountDepositsValue(account, prices)
|
||||||
const isActive = accountId === account.id
|
const isActive = accountId === account.id
|
||||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||||
|
|
||||||
@ -103,6 +105,10 @@ export default function AccountList(props: Props) {
|
|||||||
color='tertiary'
|
color='tertiary'
|
||||||
leftIcon={<ArrowUpLine />}
|
leftIcon={<ArrowUpLine />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (positionBalance.isLessThanOrEqualTo(0)) {
|
||||||
|
useStore.setState({ focusComponent: <AccountFundFirst /> })
|
||||||
|
return
|
||||||
|
}
|
||||||
useStore.setState({ fundAndWithdrawModal: 'fund' })
|
useStore.setState({ fundAndWithdrawModal: 'fund' })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
||||||
|
import AccountFundFirst from 'components/Account/AccountFund'
|
||||||
import AccountList from 'components/Account/AccountList'
|
import AccountList from 'components/Account/AccountList'
|
||||||
import CreateAccount from 'components/Account/CreateAccount'
|
|
||||||
import FundAccount from 'components/Account/FundAccount'
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import { Account, Plus, PlusCircled } from 'components/Icons'
|
import { Account, Plus, PlusCircled } from 'components/Icons'
|
||||||
@ -18,7 +17,7 @@ import useStore from 'store'
|
|||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { isNumber } from 'utils/parsers'
|
import { isNumber } from 'utils/parsers'
|
||||||
|
import { getPage, getRoute } from 'utils/route'
|
||||||
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
||||||
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
||||||
|
|
||||||
@ -28,6 +27,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function AccountMenuContent(props: Props) {
|
export default function AccountMenuContent(props: Props) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { pathname } = useLocation()
|
||||||
const { accountId, address } = useParams()
|
const { accountId, address } = useParams()
|
||||||
const createAccount = useStore((s) => s.createAccount)
|
const createAccount = useStore((s) => s.createAccount)
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||||
@ -39,12 +39,8 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
const isAccountSelected = isNumber(accountId)
|
const isAccountSelected = isNumber(accountId)
|
||||||
|
|
||||||
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
||||||
const [showFundAccount, setShowFundAccount] = useState<boolean>(
|
|
||||||
isAccountSelected && !selectedAccountDetails?.deposits?.length,
|
|
||||||
)
|
|
||||||
|
|
||||||
const isLoadingAccount = isAccountSelected && selectedAccountDetails?.id !== accountId
|
const isLoadingAccount = isAccountSelected && selectedAccountDetails?.id !== accountId
|
||||||
const showCreateAccount = !hasCreditAccounts || isCreating
|
|
||||||
|
|
||||||
const checkHasFunds = useCallback(() => {
|
const checkHasFunds = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
@ -59,11 +55,15 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
const accountId = await createAccount({ fee: hardcodedFee })
|
const accountId = await createAccount({ fee: hardcodedFee })
|
||||||
setIsCreating(false)
|
setIsCreating(false)
|
||||||
|
|
||||||
accountId && navigate(`/wallets/${address}/accounts/${accountId}`)
|
if (accountId) {
|
||||||
}, [address, createAccount, navigate, setIsCreating, setShowMenu])
|
navigate(getRoute(getPage(pathname), address, accountId))
|
||||||
|
useStore.setState({ focusComponent: <AccountFundFirst /> })
|
||||||
|
}
|
||||||
|
}, [createAccount, navigate, pathname, address, setShowMenu, setIsCreating])
|
||||||
|
|
||||||
const handleCreateAccountClick = useCallback(() => {
|
const handleCreateAccountClick = useCallback(() => {
|
||||||
if (!checkHasFunds()) {
|
setShowMenu(!showMenu)
|
||||||
|
if (!checkHasFunds() && !hasCreditAccounts) {
|
||||||
useStore.setState({ focusComponent: <WalletBridges /> })
|
useStore.setState({ focusComponent: <WalletBridges /> })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -71,8 +71,6 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
useStore.setState({ focusComponent: <AccountCreateFirst /> })
|
useStore.setState({ focusComponent: <AccountCreateFirst /> })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setShowMenu(!showMenu)
|
|
||||||
}, [checkHasFunds, hasCreditAccounts, setShowMenu, showMenu])
|
}, [checkHasFunds, hasCreditAccounts, setShowMenu, showMenu])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -98,65 +96,43 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
: 'Create Account'}
|
: 'Create Account'}
|
||||||
</Button>
|
</Button>
|
||||||
<Overlay
|
<Overlay
|
||||||
className={classNames(
|
className='max-w-screen right-0 mt-2 flex h-[530px] w-[336px] overflow-hidden'
|
||||||
'max-w-screen right-0 mt-2 flex h-[530px] w-[336px]',
|
|
||||||
!showFundAccount && 'overflow-hidden',
|
|
||||||
)}
|
|
||||||
show={showMenu}
|
show={showMenu}
|
||||||
setShow={setShowMenu}
|
setShow={setShowMenu}
|
||||||
>
|
>
|
||||||
{!showFundAccount && !showCreateAccount ? (
|
<div
|
||||||
<>
|
className={classNames(
|
||||||
<div
|
'flex h-[54px] w-full items-center justify-between bg-white/5 px-4 py-3',
|
||||||
className={classNames(
|
'border border-transparent border-b-white/10',
|
||||||
'flex h-[54px] w-full items-center justify-between bg-white/5 px-4 py-3',
|
)}
|
||||||
'border border-transparent border-b-white/10',
|
>
|
||||||
)}
|
<Text size='lg' className='font-bold'>
|
||||||
>
|
Accounts
|
||||||
<Text size='lg' className='font-bold'>
|
</Text>
|
||||||
Accounts
|
<Button
|
||||||
</Text>
|
color='secondary'
|
||||||
<Button
|
className='w-[108px]'
|
||||||
color='secondary'
|
rightIcon={<Plus />}
|
||||||
className='w-[108px]'
|
iconClassName='h-2.5 w-2.5'
|
||||||
rightIcon={<Plus />}
|
text='Create'
|
||||||
iconClassName='h-2.5 w-2.5'
|
showProgressIndicator={isCreating}
|
||||||
text='Create'
|
onClick={performCreateAccount}
|
||||||
onClick={performCreateAccount}
|
/>
|
||||||
/>
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
menuClasses,
|
||||||
|
'overflow-y-scroll scroll-smooth',
|
||||||
|
'top-[54px] h-[calc(100%-54px)] items-start',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{isAccountSelected && isLoadingAccount && (
|
||||||
|
<div className='flex h-full w-full items-center justify-center p-4'>
|
||||||
|
<CircularProgress size={40} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
)}
|
||||||
className={classNames(
|
{hasCreditAccounts && !isLoadingAccount && <AccountList accounts={props.accounts} />}
|
||||||
menuClasses,
|
</div>
|
||||||
!showFundAccount && 'overflow-y-scroll scroll-smooth',
|
|
||||||
'top-[54px] h-[calc(100%-54px)] items-start',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{isAccountSelected && isLoadingAccount && (
|
|
||||||
<div className='flex h-full w-full items-center justify-center p-4'>
|
|
||||||
<CircularProgress size={40} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{hasCreditAccounts && !showFundAccount && !isLoadingAccount && (
|
|
||||||
<AccountList accounts={props.accounts} setShowFundAccount={setShowFundAccount} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
menuClasses,
|
|
||||||
!showFundAccount && 'overflow-y-scroll scroll-smooth',
|
|
||||||
'inset-0 h-full items-end bg-account',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{showCreateAccount ? (
|
|
||||||
<CreateAccount createAccount={performCreateAccount} isCreating={isCreating} />
|
|
||||||
) : showFundAccount ? (
|
|
||||||
<FundAccount setShowFundAccount={setShowFundAccount} setShowMenu={setShowMenu} />
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js'
|
|||||||
|
|
||||||
import AccountHealth from 'components/Account/AccountHealth'
|
import AccountHealth from 'components/Account/AccountHealth'
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
import useStore from 'store'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -12,12 +12,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AccountStats(props: Props) {
|
export default function AccountStats(props: Props) {
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex-wrap'>
|
<div className='w-full flex-wrap'>
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={new BNCoin({ amount: props.balance.toString(), denom: baseCurrency.denom })}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.balance)}
|
||||||
className='w-full text-xl'
|
className='w-full text-xl'
|
||||||
/>
|
/>
|
||||||
<div className='mt-1 flex w-full items-center'>
|
<div className='mt-1 flex w-full items-center'>
|
||||||
|
@ -7,11 +7,11 @@ import DisplayCurrency from 'components/DisplayCurrency'
|
|||||||
import { ArrowChartLineUp } from 'components/Icons'
|
import { ArrowChartLineUp } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { calculateAccountDeposits } from 'utils/accounts'
|
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account?: Account
|
account?: Account
|
||||||
@ -21,8 +21,9 @@ interface Props {
|
|||||||
export default function AccountSummary(props: Props) {
|
export default function AccountSummary(props: Props) {
|
||||||
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
|
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
const accountBalance = props.account
|
||||||
const accountBalance = props.account ? calculateAccountDeposits(props.account, prices) : BN_ZERO
|
? calculateAccountDepositsValue(props.account, prices)
|
||||||
|
: BN_ZERO
|
||||||
if (!props.account) return null
|
if (!props.account) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -30,7 +31,7 @@ export default function AccountSummary(props: Props) {
|
|||||||
<Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'>
|
<Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'>
|
||||||
<Item>
|
<Item>
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={new BNCoin({ amount: accountBalance.toString(), denom: baseCurrency.denom })}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalance)}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
/>
|
/>
|
||||||
</Item>
|
</Item>
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import Button from 'components/Button'
|
|
||||||
import { ArrowRight } from 'components/Icons'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
isCreating: boolean
|
|
||||||
createAccount: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CreateAccount(props: Props) {
|
|
||||||
return (
|
|
||||||
<div className='relative z-10 w-full p-4'>
|
|
||||||
<Text size='lg' className='mb-2 font-bold'>
|
|
||||||
Create a Credit Account
|
|
||||||
</Text>
|
|
||||||
<Text className='mb-4 text-white/70'>
|
|
||||||
Please approve the transaction in your wallet in order to create your first Credit Account.
|
|
||||||
</Text>
|
|
||||||
<Button
|
|
||||||
className='w-full'
|
|
||||||
showProgressIndicator={props.isCreating}
|
|
||||||
text='Create Account'
|
|
||||||
rightIcon={<ArrowRight />}
|
|
||||||
onClick={props.createAccount}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import { useCallback, useState } from 'react'
|
|
||||||
import { useParams } from 'react-router-dom'
|
|
||||||
|
|
||||||
import Button from 'components/Button'
|
|
||||||
import { ArrowRight, Cross } from 'components/Icons'
|
|
||||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import useToggle from 'hooks/useToggle'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { getAmount } from 'utils/accounts'
|
|
||||||
import { hardcodedFee } from 'utils/constants'
|
|
||||||
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
setShowFundAccount: (show: boolean) => void
|
|
||||||
setShowMenu: (show: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FundAccount(props: Props) {
|
|
||||||
const { accountId } = useParams()
|
|
||||||
const deposit = useStore((s) => s.deposit)
|
|
||||||
const balances = useStore((s) => s.balances)
|
|
||||||
|
|
||||||
const [amount, setAmount] = useState(BN_ZERO)
|
|
||||||
const [asset, setAsset] = useState<Asset>(ASSETS[0])
|
|
||||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
|
||||||
const [isFunding, setIsFunding] = useToggle()
|
|
||||||
|
|
||||||
const max = getAmount(asset.denom, balances ?? [])
|
|
||||||
|
|
||||||
const onChangeAmount = useCallback((amount: BigNumber) => {
|
|
||||||
setAmount(amount)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onChangeAsset = useCallback((asset: Asset) => {
|
|
||||||
setAsset(asset)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
async function onDeposit() {
|
|
||||||
if (!accountId) return
|
|
||||||
setIsFunding(true)
|
|
||||||
const result = await deposit({
|
|
||||||
fee: hardcodedFee,
|
|
||||||
accountId,
|
|
||||||
coin: {
|
|
||||||
denom: asset.denom,
|
|
||||||
amount: amount.toString(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
setIsFunding(false)
|
|
||||||
if (result) {
|
|
||||||
props.setShowMenu(false)
|
|
||||||
props.setShowFundAccount(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!accountId) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className='absolute right-4 top-4'>
|
|
||||||
<Button
|
|
||||||
onClick={() => props.setShowFundAccount(false)}
|
|
||||||
leftIcon={<Cross />}
|
|
||||||
className='h-8 w-8'
|
|
||||||
iconClassName='h-2 w-2'
|
|
||||||
color='tertiary'
|
|
||||||
size='xs'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='relative z-10 w-full p-4'>
|
|
||||||
<Text size='lg' className='mb-2 font-bold'>
|
|
||||||
{`Fund Account ${accountId}`}
|
|
||||||
</Text>
|
|
||||||
<Text className='mb-4 text-white/70'>
|
|
||||||
Deposit assets from your Osmosis address to your Mars credit account. Bridge assets if
|
|
||||||
your Osmosis address has no assets.
|
|
||||||
</Text>
|
|
||||||
<TokenInputWithSlider
|
|
||||||
asset={asset}
|
|
||||||
onChange={onChangeAmount}
|
|
||||||
onChangeAsset={onChangeAsset}
|
|
||||||
amount={amount}
|
|
||||||
max={max}
|
|
||||||
className='mb-4'
|
|
||||||
disabled={isFunding}
|
|
||||||
hasSelect
|
|
||||||
balances={balances}
|
|
||||||
/>
|
|
||||||
<div className='mb-4 w-full border-b border-white/10' />
|
|
||||||
<SwitchWithLabel
|
|
||||||
name='isLending'
|
|
||||||
label='Lend assets to earn yield'
|
|
||||||
value={autoLendEnabledAccountIds.includes(accountId)}
|
|
||||||
onChange={() => toggleAutoLend(accountId)}
|
|
||||||
className='mb-4'
|
|
||||||
tooltip="Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!"
|
|
||||||
disabled={isFunding || amount.isEqualTo(0)}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
className='w-full'
|
|
||||||
showProgressIndicator={isFunding}
|
|
||||||
disabled={amount.isEqualTo(0)}
|
|
||||||
text='Fund Account'
|
|
||||||
rightIcon={<ArrowRight />}
|
|
||||||
onClick={onDeposit}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -10,20 +9,16 @@ interface Props {
|
|||||||
|
|
||||||
export default function AmountAndValue(props: Props) {
|
export default function AmountAndValue(props: Props) {
|
||||||
return (
|
return (
|
||||||
<TitleAndSubCell
|
<div className='flex flex-col gap-[0.5] text-xs'>
|
||||||
title={
|
<FormattedNumber
|
||||||
<FormattedNumber
|
amount={props.amount.toNumber()}
|
||||||
amount={props.amount.toNumber()}
|
options={{ decimals: props.asset.decimals, abbreviated: true }}
|
||||||
options={{ decimals: props.asset.decimals, abbreviated: true }}
|
animate
|
||||||
animate
|
/>
|
||||||
/>
|
<DisplayCurrency
|
||||||
}
|
className='justify-end text-xs text-white/50'
|
||||||
sub={
|
coin={BNCoin.fromDenomAndBigNumber(props.asset.denom, props.amount)}
|
||||||
<DisplayCurrency
|
/>
|
||||||
coin={new BNCoin({ amount: props.amount.toString(), denom: props.asset.denom })}
|
</div>
|
||||||
/>
|
|
||||||
}
|
|
||||||
className='justify-end'
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,14 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AssetImage(props: Props) {
|
export default function AssetImage(props: Props) {
|
||||||
|
if (!props.asset.logo)
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={props.className}
|
||||||
|
style={{ width: `${props.size}px`, height: `${props.size}px` }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Image
|
<Image
|
||||||
src={props.asset.logo}
|
src={props.asset.logo}
|
||||||
|
@ -29,18 +29,24 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
[displayCurrency, displayCurrencies],
|
[displayCurrency, displayCurrencies],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isUSD = displayCurrencyAsset.id === 'USD'
|
||||||
|
const prefix = isUSD
|
||||||
|
? `${props.isApproximation ? '~ ' : ''}$`
|
||||||
|
: `${props.isApproximation ? '~ ' : ''}`
|
||||||
|
const suffix = isUSD
|
||||||
|
? ''
|
||||||
|
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className={props.className}
|
className={props.className}
|
||||||
amount={convertToDisplayAmount(props.coin, displayCurrency, prices).toNumber()}
|
amount={convertToDisplayAmount(props.coin, displayCurrency, prices).toNumber()}
|
||||||
options={{
|
options={{
|
||||||
minDecimals: 0,
|
minDecimals: isUSD ? 2 : 0,
|
||||||
maxDecimals: 2,
|
maxDecimals: 2,
|
||||||
abbreviated: true,
|
abbreviated: true,
|
||||||
prefix: `${props.isApproximation ? '~ ' : ''}${
|
prefix,
|
||||||
displayCurrencyAsset.prefix ? displayCurrencyAsset.prefix : ''
|
suffix,
|
||||||
}`,
|
|
||||||
suffix: displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : '',
|
|
||||||
}}
|
}}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
|
@ -2,22 +2,28 @@ import { ExternalLink } from 'components/Icons'
|
|||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: 'wallet' | 'account' | 'terms'
|
type: DocLinkType
|
||||||
}
|
}
|
||||||
|
|
||||||
function getData(type: string) {
|
function getData(type: string) {
|
||||||
if (type === 'wallet')
|
|
||||||
return [
|
|
||||||
'New with wallets?',
|
|
||||||
'Learn more',
|
|
||||||
'https://docs.marsprotocol.io/docs/learn/workstation/basics/basics-intro',
|
|
||||||
]
|
|
||||||
if (type === 'account')
|
if (type === 'account')
|
||||||
return [
|
return [
|
||||||
'Why mint your account?',
|
'Why mint your account?',
|
||||||
'Learn more',
|
'Learn more',
|
||||||
'https://docs.marsprotocol.io/docs/learn/workstation/rover/rover-intro',
|
'https://docs.marsprotocol.io/docs/learn/workstation/rover/rover-intro',
|
||||||
]
|
]
|
||||||
|
if (type === 'fund')
|
||||||
|
return [
|
||||||
|
'Why fund your account?',
|
||||||
|
'Learn more',
|
||||||
|
'https://docs.marsprotocol.io/docs/learn/workstation/rover/managing-credit-accounts',
|
||||||
|
]
|
||||||
|
if (type === 'wallet')
|
||||||
|
return [
|
||||||
|
'New with wallets?',
|
||||||
|
'Learn more',
|
||||||
|
'https://docs.marsprotocol.io/docs/learn/workstation/basics/basics-intro',
|
||||||
|
]
|
||||||
return [
|
return [
|
||||||
'By continuing you accept our',
|
'By continuing you accept our',
|
||||||
'terms of service',
|
'terms of service',
|
||||||
|
@ -38,15 +38,15 @@ export const FormattedNumber = React.memo(
|
|||||||
reduceMotion
|
reduceMotion
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<span className={classNames('number', props.className)}>
|
<p className={classNames('number', props.className)}>
|
||||||
{formatValue(props.amount.toString(), props.options)}
|
{formatValue(props.amount.toString(), props.options)}
|
||||||
</span>
|
</p>
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<animated.span className={classNames('number', props.className)}>
|
<animated.p className={classNames('number', props.className)}>
|
||||||
{springAmount.number.to((num) => formatValue(num, props.options))}
|
{springAmount.number.to((num) => formatValue(num, props.options))}
|
||||||
</animated.span>
|
</animated.p>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
(prevProps, nextProps) => prevProps.amount === nextProps.amount,
|
(prevProps, nextProps) => prevProps.amount === nextProps.amount,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import DocsLink from 'components/DocsLink'
|
import DocsLink from 'components/DocsLink'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
@ -5,14 +7,15 @@ import Text from 'components/Text'
|
|||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
title: string
|
||||||
copy: string
|
copy: string
|
||||||
|
className?: string
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
button?: ButtonProps
|
button?: ButtonProps
|
||||||
docs?: 'wallet' | 'account' | 'terms'
|
docs?: DocLinkType
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FullOverlayContent(props: Props) {
|
export default function FullOverlayContent(props: Props) {
|
||||||
return (
|
return (
|
||||||
<div className='min-h-[600px] w-100'>
|
<div className={classNames('min-h-[600px] w-100', props.className)}>
|
||||||
<Text size='4xl' className='w-full pb-2 text-center'>
|
<Text size='4xl' className='w-full pb-2 text-center'>
|
||||||
{props.title}
|
{props.title}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ReactElement, ReactNode } from 'react'
|
import { ReactElement, ReactNode } from 'react'
|
||||||
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
|
||||||
import { Tooltip } from 'components/Tooltip'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
||||||
@ -87,12 +86,6 @@ export const Gauge = ({
|
|||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FormattedNumber
|
|
||||||
className={classNames(labelClassName, 'text-2xs')}
|
|
||||||
amount={Math.round(percentage)}
|
|
||||||
options={{ maxDecimals: 0, minDecimals: 0 }}
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
|
|
||||||
import AddVaultAssetTable from 'components/Modals/AddVaultAssets/AddVaultAssetTable'
|
import AssetSelectTable from 'components/Modals/AssetsSelect/AssetSelectTable'
|
||||||
import SearchBar from 'components/SearchBar'
|
import SearchBar from 'components/SearchBar'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
||||||
@ -89,7 +89,7 @@ export default function AddVaultAssetsModalContent(props: Props) {
|
|||||||
Leverage will be set at 50% for both assets by default
|
Leverage will be set at 50% for both assets by default
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<AddVaultAssetTable
|
<AssetSelectTable
|
||||||
assets={poolAssets}
|
assets={poolAssets}
|
||||||
onChangeSelected={onChangePoolDenoms}
|
onChangeSelected={onChangePoolDenoms}
|
||||||
selectedDenoms={selectedPoolDenoms}
|
selectedDenoms={selectedPoolDenoms}
|
||||||
@ -101,7 +101,7 @@ export default function AddVaultAssetsModalContent(props: Props) {
|
|||||||
these assets below.
|
these assets below.
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<AddVaultAssetTable
|
<AssetSelectTable
|
||||||
assets={stableAssets}
|
assets={stableAssets}
|
||||||
onChangeSelected={onChangeOtherDenoms}
|
onChangeSelected={onChangeOtherDenoms}
|
||||||
selectedDenoms={selectedOtherDenoms}
|
selectedDenoms={selectedOtherDenoms}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
import Modal from 'components/Modal'
|
import Modal from 'components/Modal'
|
||||||
import AddVaultAssetsModalContent from 'components/Modals/AddVaultAssets/AddVaultBorrowAssetsModalContent'
|
import AddVaultAssetsModalContent from 'components/Modals/AddVaultAssets/AddVaultBorrowAssetsModalContent'
|
||||||
@ -41,6 +42,9 @@ export default function AddVaultBorrowAssetsModal() {
|
|||||||
) : (
|
) : (
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
)}
|
)}
|
||||||
|
<div className='flex w-full p-4'>
|
||||||
|
<Button className='w-full' onClick={onClose} color='tertiary' text='Select Assets' />
|
||||||
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,54 +0,0 @@
|
|||||||
import { ColumnDef } from '@tanstack/react-table'
|
|
||||||
import React from 'react'
|
|
||||||
import Image from 'next/image'
|
|
||||||
|
|
||||||
import Checkbox from 'components/Checkbox'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
import { formatPercent } from 'utils/formatters'
|
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
|
||||||
import AssetImage from 'components/AssetImage'
|
|
||||||
|
|
||||||
export default function useAddVaultAssetTableColumns() {
|
|
||||||
const columns = React.useMemo<ColumnDef<BorrowAsset>[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
header: 'Asset',
|
|
||||||
accessorKey: 'symbol',
|
|
||||||
id: 'symbol',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const asset = getAssetByDenom(row.original.denom)
|
|
||||||
if (!asset) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='flex items-center'>
|
|
||||||
<Checkbox checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} />
|
|
||||||
<AssetImage asset={asset} size={24} className='ml-4' />
|
|
||||||
<div className='ml-2 text-left'>
|
|
||||||
<Text size='sm' className='mb-0.5 text-white'>
|
|
||||||
{asset.symbol}
|
|
||||||
</Text>
|
|
||||||
<Text size='xs'>{asset.name}</Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'borrowRate',
|
|
||||||
accessorKey: 'borrowRate',
|
|
||||||
header: 'Borrow Rate',
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<>
|
|
||||||
<Text size='sm' className='mb-0.5 text-white'>
|
|
||||||
{formatPercent(row.original.borrowRate ?? 0)}
|
|
||||||
</Text>
|
|
||||||
<Text size='xs'>APY</Text>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
return columns
|
|
||||||
}
|
|
@ -10,31 +10,43 @@ import classNames from 'classnames'
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||||
import useAddVaultAssetTableColumns from 'components/Modals/AddVaultAssets/useAddVaultAssetTableColumns'
|
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import useAssetTableColumns from 'components/Modals/AssetsSelect/useAssetTableColumns'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
assets: BorrowAsset[]
|
assets: Asset[] | BorrowAsset[]
|
||||||
selectedDenoms: string[]
|
selectedDenoms: string[]
|
||||||
onChangeSelected: (denoms: string[]) => void
|
onChangeSelected: (denoms: string[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AddVaultAssetTable(props: Props) {
|
export default function AssetSelectTable(props: Props) {
|
||||||
const defaultSelected = useMemo(() => {
|
const defaultSelected = useMemo(() => {
|
||||||
return props.assets.reduce((acc, asset, index) => {
|
const assets = props.assets as BorrowAsset[]
|
||||||
|
return assets.reduce((acc, asset, index) => {
|
||||||
if (props.selectedDenoms?.includes(asset.denom)) {
|
if (props.selectedDenoms?.includes(asset.denom)) {
|
||||||
acc[index] = true
|
acc[index] = true
|
||||||
}
|
}
|
||||||
return acc
|
return acc
|
||||||
}, {} as { [key: number]: boolean })
|
}, {} as { [key: number]: boolean })
|
||||||
}, [props.selectedDenoms, props.assets])
|
}, [props.selectedDenoms, props.assets])
|
||||||
|
|
||||||
const [sorting, setSorting] = useState<SortingState>([{ id: 'symbol', desc: false }])
|
const [sorting, setSorting] = useState<SortingState>([{ id: 'symbol', desc: false }])
|
||||||
const [selected, setSelected] = useState<RowSelectionState>(defaultSelected)
|
const [selected, setSelected] = useState<RowSelectionState>(defaultSelected)
|
||||||
const columns = useAddVaultAssetTableColumns()
|
const balances = useStore((s) => s.balances)
|
||||||
|
const columns = useAssetTableColumns()
|
||||||
|
const tableData: AssetTableRow[] = useMemo(() => {
|
||||||
|
return props.assets.map((asset) => {
|
||||||
|
const balancesForAsset = balances.find(byDenom(asset.denom))
|
||||||
|
return {
|
||||||
|
asset,
|
||||||
|
balance: balancesForAsset?.amount ?? '0',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [balances, props.assets])
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: props.assets,
|
data: tableData,
|
||||||
columns,
|
columns,
|
||||||
state: {
|
state: {
|
||||||
sorting,
|
sorting,
|
75
src/components/Modals/AssetsSelect/useAssetTableColumns.tsx
Normal file
75
src/components/Modals/AssetsSelect/useAssetTableColumns.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AssetImage from 'components/AssetImage'
|
||||||
|
import Checkbox from 'components/Checkbox'
|
||||||
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
import { demagnify, formatPercent } from 'utils/formatters'
|
||||||
|
|
||||||
|
export default function useAssetTableColumns() {
|
||||||
|
const columns = React.useMemo<ColumnDef<AssetTableRow>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
header: 'Asset',
|
||||||
|
accessorKey: 'symbol',
|
||||||
|
id: 'symbol',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const asset = getAssetByDenom(row.original.asset.denom) as Asset
|
||||||
|
return (
|
||||||
|
<div className='flex items-center'>
|
||||||
|
<Checkbox checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} />
|
||||||
|
<AssetImage asset={asset} size={24} className='ml-4' />
|
||||||
|
<div className='ml-2 text-left'>
|
||||||
|
<Text size='sm' className='mb-0.5 text-white'>
|
||||||
|
{asset.symbol}
|
||||||
|
</Text>
|
||||||
|
<Text size='xs'>{asset.name}</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'details',
|
||||||
|
header: (data) => {
|
||||||
|
const tableData = data.table.options.data as AssetTableRow[]
|
||||||
|
const assetData = tableData.length && (tableData[0].asset as BorrowAsset)
|
||||||
|
if (assetData && assetData.borrowRate) return 'Borrow Rate'
|
||||||
|
return 'Balance'
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const asset = row.original.asset as BorrowAsset
|
||||||
|
const balance = row.original.balance
|
||||||
|
if (asset.borrowRate)
|
||||||
|
return (
|
||||||
|
<div className='flex items-center'>
|
||||||
|
<Text size='sm' className='mb-0.5 text-white'>
|
||||||
|
{formatPercent(asset.borrowRate ?? 0)}
|
||||||
|
</Text>
|
||||||
|
<Text size='xs'>APY</Text>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
if (!balance) return null
|
||||||
|
const coin = new BNCoin({ denom: row.original.asset.denom, amount: balance })
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap items-center'>
|
||||||
|
<DisplayCurrency coin={coin} className='mb-0.5 w-full text-white' />
|
||||||
|
<FormattedNumber
|
||||||
|
className='w-full text-xs'
|
||||||
|
options={{ minDecimals: 2, maxDecimals: asset.decimals }}
|
||||||
|
amount={demagnify(balance, asset)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
return columns
|
||||||
|
}
|
@ -61,19 +61,23 @@ export default function FundWithdrawModalContent(props: Props) {
|
|||||||
result = await deposit({
|
result = await deposit({
|
||||||
fee: hardcodedFee,
|
fee: hardcodedFee,
|
||||||
accountId: props.account.id,
|
accountId: props.account.id,
|
||||||
coin: {
|
coins: [
|
||||||
denom: currentAsset.denom,
|
{
|
||||||
amount: amount.toString(),
|
denom: currentAsset.denom,
|
||||||
},
|
amount: amount.toString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = await withdraw({
|
result = await withdraw({
|
||||||
fee: hardcodedFee,
|
fee: hardcodedFee,
|
||||||
accountId: props.account.id,
|
accountId: props.account.id,
|
||||||
coin: {
|
coins: [
|
||||||
denom: currentAsset.denom,
|
{
|
||||||
amount: amount.toString(),
|
denom: currentAsset.denom,
|
||||||
},
|
amount: amount.toString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
SettingsModal,
|
SettingsModal,
|
||||||
UnlockModal,
|
UnlockModal,
|
||||||
VaultModal,
|
VaultModal,
|
||||||
|
WalletAssets,
|
||||||
WithdrawFromVaultsModal,
|
WithdrawFromVaultsModal,
|
||||||
} from 'components/Modals'
|
} from 'components/Modals'
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ export default function ModalsContainer() {
|
|||||||
<UnlockModal />
|
<UnlockModal />
|
||||||
<VaultModal />
|
<VaultModal />
|
||||||
<WithdrawFromVaultsModal />
|
<WithdrawFromVaultsModal />
|
||||||
|
<WalletAssets />
|
||||||
<AlertDialogController />
|
<AlertDialogController />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -18,12 +18,12 @@ import {
|
|||||||
REDUCE_MOTION_KEY,
|
REDUCE_MOTION_KEY,
|
||||||
SLIPPAGE_KEY,
|
SLIPPAGE_KEY,
|
||||||
} from 'constants/localStore'
|
} from 'constants/localStore'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useAlertDialog from 'hooks/useAlertDialog'
|
import useAlertDialog from 'hooks/useAlertDialog'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { getAllAssets, getDisplayCurrencies } from 'utils/assets'
|
import { getDisplayCurrencies, getEnabledMarketAssets } from 'utils/assets'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
const slippages = [0.02, 0.03]
|
const slippages = [0.02, 0.03]
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export default function SettingsModal() {
|
|||||||
const modal = useStore((s) => s.settingsModal)
|
const modal = useStore((s) => s.settingsModal)
|
||||||
const { open: showResetDialog } = useAlertDialog()
|
const { open: showResetDialog } = useAlertDialog()
|
||||||
const displayCurrencies = getDisplayCurrencies()
|
const displayCurrencies = getDisplayCurrencies()
|
||||||
const assets = getAllAssets()
|
const assets = getEnabledMarketAssets()
|
||||||
const [customSlippage, setCustomSlippage] = useState<number>(0)
|
const [customSlippage, setCustomSlippage] = useState<number>(0)
|
||||||
const [inputRef, setInputRef] = useState<React.RefObject<HTMLInputElement>>()
|
const [inputRef, setInputRef] = useState<React.RefObject<HTMLInputElement>>()
|
||||||
const [isCustom, setIsCustom] = useState(false)
|
const [isCustom, setIsCustom] = useState(false)
|
||||||
@ -58,9 +58,15 @@ export default function SettingsModal() {
|
|||||||
displayCurrencies.map((asset, index) => ({
|
displayCurrencies.map((asset, index) => ({
|
||||||
label: (
|
label: (
|
||||||
<div className='flex w-full gap-2' key={index}>
|
<div className='flex w-full gap-2' key={index}>
|
||||||
<AssetImage asset={asset} size={16} />
|
{asset.denom === 'usd' ? (
|
||||||
|
<Text size='sm' className='h-4 w-4 text-center leading-4'>
|
||||||
|
{asset.symbol}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<AssetImage asset={asset} size={16} />
|
||||||
|
)}
|
||||||
<Text size='sm' className='leading-4'>
|
<Text size='sm' className='leading-4'>
|
||||||
{asset.symbol}
|
{asset.name}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
@ -8,14 +8,14 @@ import { ArrowRight, ExclamationMarkCircled } from 'components/Icons'
|
|||||||
import Slider from 'components/Slider'
|
import Slider from 'components/Slider'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TokenInput from 'components/TokenInput'
|
import TokenInput from 'components/TokenInput'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useMarketAssets from 'hooks/useMarketAssets'
|
import useMarketAssets from 'hooks/useMarketAssets'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
import { findCoinByDenom, getAssetByDenom } from 'utils/assets'
|
import { findCoinByDenom, getAssetByDenom } from 'utils/assets'
|
||||||
import { formatPercent } from 'utils/formatters'
|
import { formatPercent } from 'utils/formatters'
|
||||||
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
export interface VaultBorrowingsProps {
|
export interface VaultBorrowingsProps {
|
||||||
updatedAccount: Account
|
updatedAccount: Account
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
|
|
||||||
|
import AssetSelectTable from 'components/Modals/AssetsSelect/AssetSelectTable'
|
||||||
|
import SearchBar from 'components/SearchBar'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
defaultSelectedDenoms: string[]
|
||||||
|
onChangeDenoms: (denoms: string[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WalletAssetsModalContent(props: Props) {
|
||||||
|
const [searchString, setSearchString] = useState<string>('')
|
||||||
|
const balances = useStore((s) => s.balances)
|
||||||
|
|
||||||
|
const assets = useMemo(() => {
|
||||||
|
const assetsInWallet: Asset[] = []
|
||||||
|
balances.forEach((balance) => {
|
||||||
|
const asset = getAssetByDenom(balance.denom)
|
||||||
|
if (asset && asset.isMarket) assetsInWallet.push(asset)
|
||||||
|
})
|
||||||
|
|
||||||
|
return assetsInWallet
|
||||||
|
}, [balances])
|
||||||
|
|
||||||
|
const filteredAssets: Asset[] = useMemo(() => {
|
||||||
|
return assets.filter(
|
||||||
|
(asset) =>
|
||||||
|
asset.name.toLowerCase().includes(searchString.toLowerCase()) ||
|
||||||
|
asset.denom.toLowerCase().includes(searchString.toLowerCase()) ||
|
||||||
|
asset.symbol.toLowerCase().includes(searchString.toLowerCase()),
|
||||||
|
)
|
||||||
|
}, [assets, searchString])
|
||||||
|
|
||||||
|
const currentSelectedDenom = useStore((s) => s.walletAssetsModal?.selectedDenoms)
|
||||||
|
const [selectedDenoms, setSelectedDenoms] = useState<string[]>(
|
||||||
|
currentSelectedDenom?.filter((denom) => filteredAssets.findIndex(byDenom(denom))) || [],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onChangeDenoms = useCallback(
|
||||||
|
(denoms: string[]) => {
|
||||||
|
setSelectedDenoms(denoms)
|
||||||
|
props.onChangeDenoms(denoms)
|
||||||
|
},
|
||||||
|
[props.onChangeDenoms],
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='border-b border-white/5 bg-white/10 px-4 py-3'>
|
||||||
|
<SearchBar
|
||||||
|
value={searchString}
|
||||||
|
placeholder={`Search for e.g. "ETH" or "Ethereum"`}
|
||||||
|
onChange={setSearchString}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='max-h-[446px] overflow-y-scroll scrollbar-hide'>
|
||||||
|
<AssetSelectTable
|
||||||
|
assets={filteredAssets}
|
||||||
|
onChangeSelected={onChangeDenoms}
|
||||||
|
selectedDenoms={selectedDenoms}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
37
src/components/Modals/WalletAssets/index.tsx
Normal file
37
src/components/Modals/WalletAssets/index.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { useCallback, useState } from 'react'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import Modal from 'components/Modal'
|
||||||
|
import WalletAssetsModalContent from 'components/Modals/WalletAssets/WalletAssetsModalContent'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
|
export default function WalletAssetsModal() {
|
||||||
|
const modal = useStore((s) => s.walletAssetsModal)
|
||||||
|
const [selectedDenoms, setSelectedDenoms] = useState<string[]>([])
|
||||||
|
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
useStore.setState({
|
||||||
|
walletAssetsModal: { isOpen: false, selectedDenoms },
|
||||||
|
})
|
||||||
|
}, [selectedDenoms])
|
||||||
|
|
||||||
|
if (!modal?.isOpen) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
header={<Text>Your wallet</Text>}
|
||||||
|
onClose={onClose}
|
||||||
|
modalClassName='max-w-modal-xs'
|
||||||
|
headerClassName='bg-white/10 border-b-white/5 border-b items-center p-4'
|
||||||
|
>
|
||||||
|
<WalletAssetsModalContent
|
||||||
|
defaultSelectedDenoms={modal.selectedDenoms}
|
||||||
|
onChangeDenoms={setSelectedDenoms}
|
||||||
|
/>
|
||||||
|
<div className='flex w-full p-4'>
|
||||||
|
<Button className='w-full' onClick={onClose} color='tertiary' text='Select Assets' />
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
export { default as AddVaultBorrowAssetsModal } from 'components/Modals/AddVaultAssets/AddVaultBorrowAssetsModal'
|
export { default as AddVaultBorrowAssetsModal } from 'components/Modals/AddVaultAssets'
|
||||||
export { default as AlertDialogController } from 'components/Modals/AlertDialog'
|
export { default as AlertDialogController } from 'components/Modals/AlertDialog'
|
||||||
export { default as BorrowModal } from 'components/Modals/BorrowModal'
|
export { default as BorrowModal } from 'components/Modals/BorrowModal'
|
||||||
export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw'
|
export { default as FundAndWithdrawModal } from 'components/Modals/FundWithdraw'
|
||||||
@ -6,4 +6,5 @@ export { default as LendAndReclaimModalController } from 'components/Modals/Lend
|
|||||||
export { default as SettingsModal } from 'components/Modals/Settings'
|
export { default as SettingsModal } from 'components/Modals/Settings'
|
||||||
export { default as UnlockModal } from 'components/Modals/Unlock'
|
export { default as UnlockModal } from 'components/Modals/Unlock'
|
||||||
export { default as VaultModal } from 'components/Modals/Vault'
|
export { default as VaultModal } from 'components/Modals/Vault'
|
||||||
|
export { default as WalletAssets } from 'components/Modals/WalletAssets'
|
||||||
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
|
export { default as WithdrawFromVaultsModal } from 'components/Modals/WithdrawFromVaultsModal'
|
||||||
|
@ -31,13 +31,13 @@ export default function Switch(props: Props) {
|
|||||||
'isolate flex cursor-pointer items-center justify-between overflow-hidden',
|
'isolate flex cursor-pointer items-center justify-between overflow-hidden',
|
||||||
'relative h-5 w-10 rounded-full bg-white/20 shadow-sm',
|
'relative h-5 w-10 rounded-full bg-white/20 shadow-sm',
|
||||||
'before:content-[" "] before:absolute before:left-[1px] before:top-[1px]',
|
'before:content-[" "] before:absolute before:left-[1px] before:top-[1px]',
|
||||||
'before:z-1 before:h-4.5 before:w-4.5 before:rounded-full before:bg-white before:transition-transform',
|
'before:z-1 before:m-0.5 before:h-3.5 before:w-3.5 before:rounded-full before:bg-white before:transition-transform',
|
||||||
'peer-checked:active group peer-checked:before:translate-x-5',
|
'peer-checked:active group peer-checked:before:translate-x-5',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'absolute inset-0 opacity-0 transition-opacity gradient-primary-to-secondary',
|
'absolute inset-0 bg-martian-red opacity-0 transition-opacity',
|
||||||
props.checked && 'opacity-100',
|
props.checked && 'opacity-100',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
import { useShuttle } from '@delphi-labs/shuttle-react'
|
import { useShuttle } from '@delphi-labs/shuttle-react'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { useCallback } from 'react'
|
import { useCallback, useEffect, useMemo } from 'react'
|
||||||
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import FullOverlayContent from 'components/FullOverlayContent'
|
import FullOverlayContent from 'components/FullOverlayContent'
|
||||||
import { ChevronRight } from 'components/Icons'
|
import { ChevronRight } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
import WalletFetchBalancesAndAccounts from 'components/Wallet/WalletFetchBalancesAndAccounts'
|
||||||
import WalletSelect from 'components/Wallet/WalletSelect'
|
import WalletSelect from 'components/Wallet/WalletSelect'
|
||||||
import { BRIDGES } from 'constants/bridges'
|
import { BRIDGES } from 'constants/bridges'
|
||||||
import { CHAINS } from 'constants/chains'
|
import { CHAINS } from 'constants/chains'
|
||||||
import { ENV } from 'constants/env'
|
import { ENV, IS_TESTNET } from 'constants/env'
|
||||||
import useCurrentWallet from 'hooks/useCurrentWallet'
|
import useCurrentWallet from 'hooks/useCurrentWallet'
|
||||||
|
import useToggle from 'hooks/useToggle'
|
||||||
|
import useWalletBalances from 'hooks/useWalletBalances'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
import { getBaseAsset } from 'utils/assets'
|
||||||
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
const currentChainId = ENV.CHAIN_ID
|
const currentChainId = ENV.CHAIN_ID
|
||||||
const currentChain = CHAINS[currentChainId]
|
const currentChain = CHAINS[currentChainId]
|
||||||
@ -33,8 +40,17 @@ function Bridge({ name, url, image }: Bridge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function WalletBridges() {
|
export default function WalletBridges() {
|
||||||
|
const address = useStore((s) => s.address)
|
||||||
const currentWallet = useCurrentWallet()
|
const currentWallet = useCurrentWallet()
|
||||||
const { disconnectWallet } = useShuttle()
|
const { disconnectWallet } = useShuttle()
|
||||||
|
const { data: walletBalances, isLoading } = useWalletBalances(address)
|
||||||
|
const baseAsset = getBaseAsset()
|
||||||
|
const [hasFunds, setHasFunds] = useToggle(false)
|
||||||
|
|
||||||
|
const baseBalance = useMemo(
|
||||||
|
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||||
|
[walletBalances, baseAsset],
|
||||||
|
)
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (!currentWallet) return
|
if (!currentWallet) return
|
||||||
@ -42,6 +58,16 @@ export default function WalletBridges() {
|
|||||||
useStore.setState({ focusComponent: <WalletSelect /> })
|
useStore.setState({ focusComponent: <WalletSelect /> })
|
||||||
}, [currentWallet, disconnectWallet])
|
}, [currentWallet, disconnectWallet])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasFunds) {
|
||||||
|
useStore.setState({ focusComponent: <WalletFetchBalancesAndAccounts /> })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount) && !isLoading)
|
||||||
|
setHasFunds(true)
|
||||||
|
}, [baseBalance, isLoading, hasFunds, setHasFunds])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullOverlayContent
|
<FullOverlayContent
|
||||||
title='No supported assets'
|
title='No supported assets'
|
||||||
@ -61,6 +87,19 @@ export default function WalletBridges() {
|
|||||||
<Bridge key={bridge.name} {...bridge} />
|
<Bridge key={bridge.name} {...bridge} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
{IS_TESTNET && (
|
||||||
|
<div className='flex w-full flex-wrap gap-3'>
|
||||||
|
<Text size='lg' className='mt-4 text-white'>
|
||||||
|
Need Testnet Funds?
|
||||||
|
</Text>
|
||||||
|
<Bridge
|
||||||
|
key='osmosis-faucet'
|
||||||
|
name='Osmosis Testnet Faucet'
|
||||||
|
url='https://faucet.osmotest5.osmosis.zone/'
|
||||||
|
image='/images/tokens/osmo.svg'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</FullOverlayContent>
|
</FullOverlayContent>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,14 @@ import Overlay from 'components/Overlay'
|
|||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { CHAINS } from 'constants/chains'
|
import { CHAINS } from 'constants/chains'
|
||||||
import { IS_TESTNET } from 'constants/env'
|
import { IS_TESTNET } from 'constants/env'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useCurrentWallet from 'hooks/useCurrentWallet'
|
import useCurrentWallet from 'hooks/useCurrentWallet'
|
||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import useWalletBalances from 'hooks/useWalletBalances'
|
import useWalletBalances from 'hooks/useWalletBalances'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { ChainInfoID } from 'types/enums/wallet'
|
import { ChainInfoID } from 'types/enums/wallet'
|
||||||
import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
|
import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
|
||||||
import { formatValue, truncate } from 'utils/formatters'
|
import { truncate } from 'utils/formatters'
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
export default function WalletConnectedButton() {
|
export default function WalletConnectedButton() {
|
||||||
// ---------------
|
// ---------------
|
||||||
@ -103,7 +103,11 @@ export default function WalletConnectedButton() {
|
|||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<CircularProgress size={12} />
|
<CircularProgress size={12} />
|
||||||
) : (
|
) : (
|
||||||
`${formatValue(walletAmount.toString(), { suffix: ` ${baseAsset.symbol}` })}`
|
<FormattedNumber
|
||||||
|
amount={walletAmount.toNumber()}
|
||||||
|
options={{ suffix: ` ${baseAsset.symbol}` }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Suspense, useEffect, useMemo } from 'react'
|
import { Suspense, useEffect, useMemo } from 'react'
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
import { CircularProgress } from 'components/CircularProgress'
|
||||||
@ -11,6 +12,7 @@ import { byDenom } from 'utils/array'
|
|||||||
import { getBaseAsset } from 'utils/assets'
|
import { getBaseAsset } from 'utils/assets'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
function FetchLoading() {
|
function FetchLoading() {
|
||||||
return (
|
return (
|
||||||
@ -25,6 +27,8 @@ function FetchLoading() {
|
|||||||
|
|
||||||
function Content() {
|
function Content() {
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { pathname } = useLocation()
|
||||||
const { data: accounts } = useAccounts(address)
|
const { data: accounts } = useAccounts(address)
|
||||||
const { data: walletBalances, isLoading } = useWalletBalances(address)
|
const { data: walletBalances, isLoading } = useWalletBalances(address)
|
||||||
const baseAsset = getBaseAsset()
|
const baseAsset = getBaseAsset()
|
||||||
@ -39,9 +43,10 @@ function Content() {
|
|||||||
accounts.length !== 0 &&
|
accounts.length !== 0 &&
|
||||||
BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount)
|
BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount)
|
||||||
) {
|
) {
|
||||||
|
navigate(getRoute(getPage(pathname), address, accounts[0].id))
|
||||||
useStore.setState({ accounts: accounts, balances: walletBalances, focusComponent: null })
|
useStore.setState({ accounts: accounts, balances: walletBalances, focusComponent: null })
|
||||||
}
|
}
|
||||||
}, [accounts, walletBalances, baseBalance])
|
}, [accounts, baseBalance, navigate, pathname, address, walletBalances])
|
||||||
|
|
||||||
if (isLoading) return <FetchLoading />
|
if (isLoading) return <FetchLoading />
|
||||||
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) return <WalletBridges />
|
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) return <WalletBridges />
|
||||||
|
@ -133,9 +133,9 @@ export const ASSETS: Asset[] = [
|
|||||||
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
symbol: 'gamm/pool/6',
|
symbol: 'OSMO-USDC.n',
|
||||||
name: 'OSMO-USDC.n Pool Token',
|
name: 'OSMO-USDC.n Pool Token',
|
||||||
id: 'gamm/pool/6',
|
id: 'OSMO-USDC.n',
|
||||||
denom: 'gamm/pool/6',
|
denom: 'gamm/pool/6',
|
||||||
color: '',
|
color: '',
|
||||||
logo: '',
|
logo: '',
|
||||||
@ -147,4 +147,19 @@ export const ASSETS: Asset[] = [
|
|||||||
isStable: false,
|
isStable: false,
|
||||||
forceFetchPrice: true,
|
forceFetchPrice: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
symbol: '$',
|
||||||
|
name: 'US Dollar',
|
||||||
|
id: 'USD',
|
||||||
|
denom: 'usd',
|
||||||
|
color: '',
|
||||||
|
logo: '',
|
||||||
|
decimals: 2,
|
||||||
|
hasOraclePrice: false,
|
||||||
|
isEnabled: false,
|
||||||
|
isMarket: false,
|
||||||
|
isDisplayCurrency: true,
|
||||||
|
isStable: false,
|
||||||
|
forceFetchPrice: false,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
export const BRIDGES: Bridge[] = [
|
export const BRIDGES: Bridge[] = [
|
||||||
|
{
|
||||||
|
name: 'TFM Bridge',
|
||||||
|
url: 'https://tfm.com/bridge?chainTo=osmosis-1',
|
||||||
|
image: '/images/bridges/tfm.png',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Gravity bridge',
|
name: 'Gravity bridge',
|
||||||
url: 'https://bridge.blockscape.network',
|
url: 'https://bridge.blockscape.network',
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ASSETS } from 'constants/assets'
|
import { ASSETS } from 'constants/assets'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: Settings = {
|
export const DEFAULT_SETTINGS: Settings = {
|
||||||
reduceMotion: false,
|
reduceMotion: false,
|
||||||
lendAssets: false,
|
lendAssets: false,
|
||||||
preferredAsset: ASSETS[0].denom,
|
preferredAsset: ASSETS[0].denom,
|
||||||
displayCurrency: ASSETS[0].denom,
|
displayCurrency: ORACLE_DENOM,
|
||||||
slippage: 0.02,
|
slippage: 0.02,
|
||||||
}
|
}
|
||||||
|
1
src/constants/oracle.ts
Normal file
1
src/constants/oracle.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const ORACLE_DENOM = 'usd'
|
@ -1,6 +1,6 @@
|
|||||||
|
import { MsgExecuteContract } from '@delphi-labs/shuttle-react'
|
||||||
import { isMobile } from 'react-device-detect'
|
import { isMobile } from 'react-device-detect'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetState, SetState } from 'zustand'
|
||||||
import { MsgExecuteContract } from '@delphi-labs/shuttle-react'
|
|
||||||
|
|
||||||
import { ENV } from 'constants/env'
|
import { ENV } from 'constants/env'
|
||||||
import { Store } from 'store'
|
import { Store } from 'store'
|
||||||
@ -108,24 +108,20 @@ export default function createBroadcastSlice(
|
|||||||
|
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
deposit: async (options: { fee: StdFee; accountId: string; coin: Coin }) => {
|
deposit: async (options: { fee: StdFee; accountId: string; coins: Coin[] }) => {
|
||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
update_credit_account: {
|
update_credit_account: {
|
||||||
account_id: options.accountId,
|
account_id: options.accountId,
|
||||||
actions: [
|
actions: options.coins.map((coin) => ({
|
||||||
{
|
deposit: coin,
|
||||||
deposit: options.coin,
|
})),
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee, funds: [options.coin] })
|
const response = await get().executeMsg({ msg, fee: options.fee, funds: options.coins })
|
||||||
|
|
||||||
handleResponseMessages(
|
const depositString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
||||||
response,
|
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
|
||||||
`Deposited ${formatAmountWithSymbol(options.coin)} to Account ${options.accountId}`,
|
|
||||||
)
|
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
unlock: async (options: {
|
unlock: async (options: {
|
||||||
@ -200,23 +196,21 @@ export default function createBroadcastSlice(
|
|||||||
handleResponseMessages(response, `Deposited into vault`)
|
handleResponseMessages(response, `Deposited into vault`)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
withdraw: async (options: { fee: StdFee; accountId: string; coin: Coin }) => {
|
withdraw: async (options: { fee: StdFee; accountId: string; coins: Coin[] }) => {
|
||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
update_credit_account: {
|
update_credit_account: {
|
||||||
account_id: options.accountId,
|
account_id: options.accountId,
|
||||||
actions: [
|
actions: options.coins.map((coin) => ({
|
||||||
{
|
withdraw: coin,
|
||||||
withdraw: options.coin,
|
})),
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({ msg, fee: options.fee })
|
||||||
|
const withdrawString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
`Withdrew ${formatAmountWithSymbol(options.coin)} from Account ${options.accountId}`,
|
`Withdrew ${withdrawString} from Account ${options.accountId}`,
|
||||||
)
|
)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { GetState, SetState } from 'zustand'
|
import { GetState, SetState } from 'zustand'
|
||||||
|
|
||||||
|
import { ASSETS } from 'constants/assets'
|
||||||
|
|
||||||
export default function createCommonSlice(set: SetState<CommonSlice>, get: GetState<CommonSlice>) {
|
export default function createCommonSlice(set: SetState<CommonSlice>, get: GetState<CommonSlice>) {
|
||||||
return {
|
return {
|
||||||
accounts: null,
|
accounts: null,
|
||||||
|
@ -14,6 +14,7 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
|
|||||||
settingsModal: false,
|
settingsModal: false,
|
||||||
unlockModal: null,
|
unlockModal: null,
|
||||||
vaultModal: null,
|
vaultModal: null,
|
||||||
|
walletAssetsModal: null,
|
||||||
withdrawFromVaultsModal: null,
|
withdrawFromVaultsModal: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
src/types/interfaces/asset.d.ts
vendored
6
src/types/interfaces/asset.d.ts
vendored
@ -11,7 +11,8 @@ interface Asset {
|
|||||||
| 'USDC.n'
|
| 'USDC.n'
|
||||||
| 'WBTC.axl'
|
| 'WBTC.axl'
|
||||||
| 'WETH.axl'
|
| 'WETH.axl'
|
||||||
| 'gamm/pool/6'
|
| 'OSMO-USDC.n'
|
||||||
|
| '$'
|
||||||
id:
|
id:
|
||||||
| 'OSMO'
|
| 'OSMO'
|
||||||
| 'ATOM'
|
| 'ATOM'
|
||||||
@ -21,7 +22,8 @@ interface Asset {
|
|||||||
| 'axlWBTC'
|
| 'axlWBTC'
|
||||||
| 'axlWETH'
|
| 'axlWETH'
|
||||||
| 'nUSDC'
|
| 'nUSDC'
|
||||||
| 'gamm/pool/6'
|
| 'OSMO-USDC.n'
|
||||||
|
| 'USD'
|
||||||
prefix?: string
|
prefix?: string
|
||||||
contract_addr?: string
|
contract_addr?: string
|
||||||
logo: string
|
logo: string
|
||||||
|
4
src/types/interfaces/components/Modals/AssetSelect.d.ts
vendored
Normal file
4
src/types/interfaces/components/Modals/AssetSelect.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface AssetTableRow {
|
||||||
|
balance?: string
|
||||||
|
asset: BorrowAsset | Asset
|
||||||
|
}
|
1
src/types/interfaces/components/docLink.d.ts
vendored
Normal file
1
src/types/interfaces/components/docLink.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
type DocLinkType = 'wallet' | 'account' | 'terms' | 'fund'
|
4
src/types/interfaces/store/broadcast.d.ts
vendored
4
src/types/interfaces/store/broadcast.d.ts
vendored
@ -20,7 +20,7 @@ interface BroadcastSlice {
|
|||||||
}) => Promise<boolean>
|
}) => Promise<boolean>
|
||||||
createAccount: (options: { fee: StdFee }) => Promise<string | null>
|
createAccount: (options: { fee: StdFee }) => Promise<string | null>
|
||||||
deleteAccount: (options: { fee: StdFee; accountId: string }) => Promise<boolean>
|
deleteAccount: (options: { fee: StdFee; accountId: string }) => Promise<boolean>
|
||||||
deposit: (options: { fee: StdFee; accountId: string; coin: Coin }) => Promise<boolean>
|
deposit: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
||||||
unlock: (options: {
|
unlock: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
@ -37,7 +37,7 @@ interface BroadcastSlice {
|
|||||||
accountId: string
|
accountId: string
|
||||||
actions: Action[]
|
actions: Action[]
|
||||||
}) => Promise<boolean>
|
}) => Promise<boolean>
|
||||||
withdraw: (options: { fee: StdFee; accountId: string; coin: Coin }) => Promise<boolean>
|
withdraw: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
||||||
lend: (options: {
|
lend: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
|
9
src/types/interfaces/store/modals.d.ts
vendored
9
src/types/interfaces/store/modals.d.ts
vendored
@ -8,9 +8,10 @@ interface ModalSlice {
|
|||||||
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
||||||
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
||||||
settingsModal: boolean
|
settingsModal: boolean
|
||||||
vaultModal: VaultModal | null
|
|
||||||
withdrawFromVaultsModal: DepositedVault[] | null
|
|
||||||
unlockModal: UnlockModal | null
|
unlockModal: UnlockModal | null
|
||||||
|
vaultModal: VaultModal | null
|
||||||
|
walletAssetsModal: WalletAssetModal | null
|
||||||
|
withdrawFromVaultsModal: DepositedVault[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AlertDialogButton {
|
interface AlertDialogButton {
|
||||||
@ -52,3 +53,7 @@ interface AddVaultBorrowingsModal {
|
|||||||
interface UnlockModal {
|
interface UnlockModal {
|
||||||
vault: DepositedVault
|
vault: DepositedVault
|
||||||
}
|
}
|
||||||
|
interface WalletAssetModal {
|
||||||
|
isOpen?: boolean
|
||||||
|
selectedDenoms: string[]
|
||||||
|
}
|
||||||
|
@ -1,43 +1,49 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
|
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import {
|
import {
|
||||||
Positions,
|
Positions,
|
||||||
VaultPosition,
|
VaultPosition,
|
||||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
export const calculateAccountBalance = (
|
export const calculateAccountBalanceValue = (
|
||||||
account: Account | AccountChange,
|
account: Account | AccountChange,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
): BigNumber => {
|
): BigNumber => {
|
||||||
const totalDepositValue = calculateAccountDeposits(account, prices)
|
const totalDepositValue = calculateAccountDepositsValue(account, prices)
|
||||||
const totalDebtValue = calculateAccountDebt(account, prices)
|
const totalDebtValue = calculateAccountDebtValue(account, prices)
|
||||||
|
|
||||||
return totalDepositValue.minus(totalDebtValue)
|
return totalDepositValue.minus(totalDebtValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateAccountDeposits = (
|
export const calculateAccountDepositsValue = (
|
||||||
account: Account | AccountChange,
|
account: Account | AccountChange,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
): BigNumber => {
|
): BigNumber => {
|
||||||
if (!account.deposits) return BN_ZERO
|
if (!account.deposits) return BN_ZERO
|
||||||
return account.deposits.reduce((acc, deposit) => {
|
return account.deposits.reduce((acc, deposit) => {
|
||||||
|
const asset = getAssetByDenom(deposit.denom)
|
||||||
|
if (!asset) return acc
|
||||||
const price = prices.find((price) => price.denom === deposit.denom)?.amount ?? 0
|
const price = prices.find((price) => price.denom === deposit.denom)?.amount ?? 0
|
||||||
const depositValue = BN(deposit.amount).multipliedBy(price)
|
const amount = BN(deposit.amount).shiftedBy(-asset.decimals)
|
||||||
|
const depositValue = amount.multipliedBy(price)
|
||||||
return acc.plus(depositValue)
|
return acc.plus(depositValue)
|
||||||
}, BN_ZERO)
|
}, BN_ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateAccountDebt = (
|
export const calculateAccountDebtValue = (
|
||||||
account: Account | AccountChange,
|
account: Account | AccountChange,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
): BigNumber => {
|
): BigNumber => {
|
||||||
if (!account.debts) return BN_ZERO
|
if (!account.debts) return BN_ZERO
|
||||||
return account.debts.reduce((acc, debt) => {
|
return account.debts.reduce((acc, debt) => {
|
||||||
|
const asset = getAssetByDenom(debt.denom)
|
||||||
|
if (!asset) return acc
|
||||||
const price = prices.find((price) => price.denom === debt.denom)?.amount ?? 0
|
const price = prices.find((price) => price.denom === debt.denom)?.amount ?? 0
|
||||||
const debtAmount = BN(debt.amount)
|
const debtAmount = BN(debt.amount).shiftedBy(-asset.decimals)
|
||||||
const debtValue = debtAmount.multipliedBy(price)
|
const debtValue = debtAmount.multipliedBy(price)
|
||||||
return acc.plus(debtValue)
|
return acc.plus(debtValue)
|
||||||
}, BN_ZERO)
|
}, BN_ZERO)
|
||||||
|
@ -2,8 +2,9 @@ import BigNumber from 'bignumber.js'
|
|||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
import { getAllAssets, getEnabledMarketAssets } from 'utils/assets'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export function truncate(text = '', [h, t]: [number, number] = [6, 6]): string {
|
export function truncate(text = '', [h, t]: [number, number] = [6, 6]): string {
|
||||||
@ -177,15 +178,14 @@ export function demagnify(amount: number | string | BigNumber, asset: Asset | Ps
|
|||||||
|
|
||||||
export function convertToDisplayAmount(coin: BNCoin, displayCurrency: string, prices: BNCoin[]) {
|
export function convertToDisplayAmount(coin: BNCoin, displayCurrency: string, prices: BNCoin[]) {
|
||||||
const price = prices.find((price) => price.denom === coin.denom)
|
const price = prices.find((price) => price.denom === coin.denom)
|
||||||
const asset = getEnabledMarketAssets().find((asset) => asset.denom === coin.denom)
|
const asset = getAllAssets().find((asset) => asset.denom === coin.denom)
|
||||||
const displayPrice = prices.find((price) => price.denom === displayCurrency)
|
const displayPrice = prices.find((price) => price.denom === displayCurrency)
|
||||||
|
|
||||||
if (!price || !asset || !displayPrice) return BN_ZERO
|
if (!price || !displayPrice || !asset) return BN_ZERO
|
||||||
|
|
||||||
return coin.amount
|
const decimals = asset.denom === ORACLE_DENOM ? 0 : asset.decimals * -1
|
||||||
.shiftedBy(-1 * asset.decimals)
|
|
||||||
.multipliedBy(price.amount)
|
return coin.amount.shiftedBy(decimals).multipliedBy(price.amount).dividedBy(displayPrice.amount)
|
||||||
.dividedBy(displayPrice.amount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertLiquidityRateToAPR(rate: number) {
|
export function convertLiquidityRateToAPR(rate: number) {
|
||||||
|
Loading…
Reference in New Issue
Block a user