Mp 3104 delete account (#336)
* MP-3104: added deleteAccount and alerts for vaults and debts * MP-3104: added Borrow and Farm links to the AlertDialog * MP-3104: finished delete flow * fix: adjusted according to feedback * refactor: tidy
This commit is contained in:
parent
69dece2600
commit
1a55d8bd39
@ -56,7 +56,7 @@ export default function AccountComposition(props: Props) {
|
|||||||
className='pb-3'
|
className='pb-3'
|
||||||
/>
|
/>
|
||||||
<Item
|
<Item
|
||||||
title='Total Liabilities'
|
title='Total Debt'
|
||||||
current={debtBalance}
|
current={debtBalance}
|
||||||
change={debtBalance.plus(debtBalanceChange)}
|
change={debtBalance.plus(debtBalanceChange)}
|
||||||
className='pb-3'
|
className='pb-3'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useEffect } from 'react'
|
import { useCallback, 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 AccountFundFirst from 'components/Account/AccountFund'
|
||||||
@ -11,10 +11,10 @@ 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 useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -30,21 +30,19 @@ const accountCardHeaderClasses = classNames(
|
|||||||
export default function AccountList(props: Props) {
|
export default function AccountList(props: Props) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { accountId, address } = useParams()
|
const { address } = useParams()
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
const deleteAccount = useStore((s) => s.deleteAccount)
|
const account = useCurrentAccount()
|
||||||
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
const accountId = account?.id
|
||||||
|
|
||||||
async function deleteAccountHandler() {
|
const deleteAccountHandler = useCallback(() => {
|
||||||
if (!accountSelected) return
|
if (!account) return
|
||||||
const isSuccess = await deleteAccount({ fee: hardcodedFee, accountId: accountId })
|
useStore.setState({ accountDeleteModal: account })
|
||||||
if (isSuccess) {
|
}, [account])
|
||||||
navigate(getRoute(getPage(pathname), address))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!accountId) return
|
||||||
const element = document.getElementById(`account-${accountId}`)
|
const element = document.getElementById(`account-${accountId}`)
|
||||||
if (element) {
|
if (element) {
|
||||||
element.scrollIntoView({ behavior: 'smooth' })
|
element.scrollIntoView({ behavior: 'smooth' })
|
||||||
@ -69,6 +67,7 @@ export default function AccountList(props: Props) {
|
|||||||
contentClassName='bg-white/10 group-hover/account:bg-white/20'
|
contentClassName='bg-white/10 group-hover/account:bg-white/20'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isActive) return
|
if (isActive) return
|
||||||
|
useStore.setState({ accountDeleteModal: null })
|
||||||
navigate(getRoute(getPage(pathname), address, account.id))
|
navigate(getRoute(getPage(pathname), address, account.id))
|
||||||
}}
|
}}
|
||||||
title={
|
title={
|
||||||
|
34
src/components/AssetBalanceRow.tsx
Normal file
34
src/components/AssetBalanceRow.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import AssetImage from 'components/AssetImage'
|
||||||
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { demagnify } from 'utils/formatters'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
asset: Asset
|
||||||
|
coin: BNCoin
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AssetBalanceRow(props: Props) {
|
||||||
|
return (
|
||||||
|
<div className='flex w-full items-center gap-4'>
|
||||||
|
<AssetImage asset={props.asset} size={32} />
|
||||||
|
<div className='flex flex-1 flex-wrap'>
|
||||||
|
<Text className='w-full'>{props.asset.symbol}</Text>
|
||||||
|
<Text size='sm' className='w-full text-white/50'>
|
||||||
|
{props.asset.name}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-wrap'>
|
||||||
|
<DisplayCurrency coin={props.coin} className='w-full text-right' />
|
||||||
|
<FormattedNumber
|
||||||
|
amount={demagnify(props.coin.amount, props.asset)}
|
||||||
|
className='w-full text-right text-sm text-white/50'
|
||||||
|
options={{ suffix: ` ${props.asset.symbol}` }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import React, { LegacyRef, ReactElement, ReactNode, useMemo } from 'react'
|
import React, { LegacyRef, useMemo } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
buttonBorderClasses,
|
buttonBorderClasses,
|
||||||
@ -22,6 +22,7 @@ import useLocalStorage from 'hooks/useLocalStorage'
|
|||||||
|
|
||||||
const Button = React.forwardRef(function Button(
|
const Button = React.forwardRef(function Button(
|
||||||
{
|
{
|
||||||
|
autoFocus,
|
||||||
children,
|
children,
|
||||||
className = '',
|
className = '',
|
||||||
color = 'primary',
|
color = 'primary',
|
||||||
@ -93,6 +94,7 @@ const Button = React.forwardRef(function Button(
|
|||||||
ref={ref as LegacyRef<HTMLButtonElement>}
|
ref={ref as LegacyRef<HTMLButtonElement>}
|
||||||
onClick={isDisabled ? () => {} : onClick}
|
onClick={isDisabled ? () => {} : onClick}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
|
autoFocus={autoFocus}
|
||||||
>
|
>
|
||||||
{showProgressIndicator ? (
|
{showProgressIndicator ? (
|
||||||
<CircularProgress size={circularProgressSize[size]} />
|
<CircularProgress size={circularProgressSize[size]} />
|
||||||
|
@ -14,29 +14,25 @@ export default function Tab(props: Props) {
|
|||||||
const { address, accountId } = useParams()
|
const { address, accountId } = useParams()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mb-4 w-full'>
|
<div className='relative mb-4 w-full'>
|
||||||
<div className='flex gap-2'>
|
<NavLink
|
||||||
<div className='relative'>
|
to={getRoute('lend', address, accountId)}
|
||||||
<NavLink
|
className={classNames(
|
||||||
to={getRoute('farm', address, accountId)}
|
props.isFarm ? 'text-white/20' : underlineClasses,
|
||||||
className={classNames(
|
'relative mr-8 text-xl ',
|
||||||
!props.isFarm ? 'text-white/20' : underlineClasses,
|
)}
|
||||||
'relative mr-8 text-xl',
|
>
|
||||||
)}
|
Lend
|
||||||
>
|
</NavLink>
|
||||||
Farm
|
<NavLink
|
||||||
</NavLink>
|
to={getRoute('farm', address, accountId)}
|
||||||
</div>
|
className={classNames(
|
||||||
<NavLink
|
!props.isFarm ? 'text-white/20' : underlineClasses,
|
||||||
to={getRoute('lend', address, accountId)}
|
'relative text-xl',
|
||||||
className={classNames(
|
)}
|
||||||
props.isFarm ? 'text-white/20' : underlineClasses,
|
>
|
||||||
'relative text-xl',
|
Farm
|
||||||
)}
|
</NavLink>
|
||||||
>
|
|
||||||
Lend
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import useStore from 'store'
|
|||||||
|
|
||||||
export const menuTree: { page: Page; label: string }[] = [
|
export const menuTree: { page: Page; label: string }[] = [
|
||||||
{ page: 'trade', label: 'Trade' },
|
{ page: 'trade', label: 'Trade' },
|
||||||
{ page: 'farm', label: 'Earn' },
|
{ page: 'lend', label: 'Earn' },
|
||||||
{ page: 'borrow', label: 'Borrow' },
|
{ page: 'borrow', label: 'Borrow' },
|
||||||
{ page: 'portfolio', label: 'Portfolio' },
|
{ page: 'portfolio', label: 'Portfolio' },
|
||||||
{ page: 'council', label: 'Council' },
|
{ page: 'council', label: 'Council' },
|
||||||
|
@ -33,11 +33,16 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
||||||
|
|
||||||
const details: Detail[] = useMemo(() => {
|
const details: Detail[] = useMemo(() => {
|
||||||
|
const isDollar = displayCurrencySymbol === '$'
|
||||||
function getLendingMarketDetails() {
|
function getLendingMarketDetails() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
amount: convertAmount(asset, marketDepositAmount).toNumber(),
|
amount: convertAmount(asset, marketDepositAmount).toNumber(),
|
||||||
options: { abbreviated: true, suffix: ` ${displayCurrencySymbol}` },
|
options: {
|
||||||
|
abbreviated: true,
|
||||||
|
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
|
||||||
|
prefix: isDollar ? '$' : undefined,
|
||||||
|
},
|
||||||
title: 'Total Supplied',
|
title: 'Total Supplied',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -52,7 +57,12 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
amount: getConversionRate(asset.denom).toNumber(),
|
amount: getConversionRate(asset.denom).toNumber(),
|
||||||
options: { minDecimals: 2, maxDecimals: 2, suffix: ` ${displayCurrencySymbol}` },
|
options: {
|
||||||
|
minDecimals: 2,
|
||||||
|
maxDecimals: 2,
|
||||||
|
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
|
||||||
|
prefix: isDollar ? '$' : undefined,
|
||||||
|
},
|
||||||
title: 'Oracle Price',
|
title: 'Oracle Price',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -67,12 +77,21 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
amount: convertAmount(asset, totalBorrowed).toNumber(),
|
amount: convertAmount(asset, totalBorrowed).toNumber(),
|
||||||
options: { abbreviated: true, suffix: ` ${displayCurrencySymbol}` },
|
options: {
|
||||||
|
abbreviated: true,
|
||||||
|
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
|
||||||
|
prefix: isDollar ? '$' : undefined,
|
||||||
|
},
|
||||||
title: 'Total Borrowed',
|
title: 'Total Borrowed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
amount: getConversionRate(asset.denom).toNumber(),
|
amount: getConversionRate(asset.denom).toNumber(),
|
||||||
options: { minDecimals: 2, maxDecimals: 2, suffix: ` ${displayCurrencySymbol}` },
|
options: {
|
||||||
|
minDecimals: 2,
|
||||||
|
maxDecimals: 2,
|
||||||
|
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
|
||||||
|
prefix: isDollar ? '$' : undefined,
|
||||||
|
},
|
||||||
title: 'Oracle Price',
|
title: 'Oracle Price',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
36
src/components/Modals/Account/AccountDeleteAlertDialog.tsx
Normal file
36
src/components/Modals/Account/AccountDeleteAlertDialog.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
|
import { Enter, InfoCircle } from 'components/Icons'
|
||||||
|
import useAlertDialog from 'hooks/useAlertDialog'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
closeHandler: () => void
|
||||||
|
positiveButton: AlertDialogButton
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccoundDeleteAlertDialog(props: Props) {
|
||||||
|
const { open: showAlertDialog } = useAlertDialog()
|
||||||
|
const { title, description, closeHandler, positiveButton } = props
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
showAlertDialog({
|
||||||
|
icon: (
|
||||||
|
<div className='flex h-full w-full p-3'>
|
||||||
|
<InfoCircle />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
negativeButton: {
|
||||||
|
text: 'Close',
|
||||||
|
icon: <Enter />,
|
||||||
|
onClick: closeHandler,
|
||||||
|
},
|
||||||
|
positiveButton,
|
||||||
|
})
|
||||||
|
}, [showAlertDialog, title, description, closeHandler, positiveButton])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
144
src/components/Modals/Account/AccountDeleteModal.tsx
Normal file
144
src/components/Modals/Account/AccountDeleteModal.tsx
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import AssetBalanceRow from 'components/AssetBalanceRow'
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import { ArrowRight } from 'components/Icons'
|
||||||
|
import Modal from 'components/Modal'
|
||||||
|
import AccoundDeleteAlertDialog from 'components/Modals/Account/AccountDeleteAlertDialog'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
import { combineBNCoins } from 'utils/parsers'
|
||||||
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modal: Account
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccountDeleteController() {
|
||||||
|
const modal = useStore((s) => s.accountDeleteModal)
|
||||||
|
|
||||||
|
if (!modal) return null
|
||||||
|
|
||||||
|
return <AccountDeleteModal modal={modal} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function AccountDeleteModal(props: Props) {
|
||||||
|
const modal = props.modal
|
||||||
|
const deleteAccount = useStore((s) => s.deleteAccount)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const { address } = useParams()
|
||||||
|
const { debts, vaults, id: accountId } = modal || {}
|
||||||
|
const [isConfirming, setIsConfirming] = useState(false)
|
||||||
|
|
||||||
|
const closeDeleteAccountModal = useCallback(() => {
|
||||||
|
useStore.setState({ accountDeleteModal: null })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const deleteAccountHandler = useCallback(async () => {
|
||||||
|
setIsConfirming(true)
|
||||||
|
const options = { fee: hardcodedFee, accountId: modal.id, lends: modal.lends }
|
||||||
|
const isSuccess = await deleteAccount(options)
|
||||||
|
setIsConfirming(false)
|
||||||
|
if (isSuccess) {
|
||||||
|
navigate(getRoute(getPage(pathname), address))
|
||||||
|
closeDeleteAccountModal()
|
||||||
|
}
|
||||||
|
}, [modal, deleteAccount, navigate, pathname, address, closeDeleteAccountModal])
|
||||||
|
|
||||||
|
const depositsAndLends = useMemo(
|
||||||
|
() => combineBNCoins([...modal.deposits, ...modal.lends]),
|
||||||
|
[modal],
|
||||||
|
)
|
||||||
|
|
||||||
|
if (debts.length > 0)
|
||||||
|
return (
|
||||||
|
<AccoundDeleteAlertDialog
|
||||||
|
title='Repay your Debts to delete your account'
|
||||||
|
description='You must repay all borrowings before deleting your account.'
|
||||||
|
closeHandler={closeDeleteAccountModal}
|
||||||
|
positiveButton={{
|
||||||
|
text: 'Repay Debts',
|
||||||
|
icon: <ArrowRight />,
|
||||||
|
onClick: () => {
|
||||||
|
navigate(getRoute('borrow', address, accountId))
|
||||||
|
closeDeleteAccountModal()
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (vaults.length > 0)
|
||||||
|
return (
|
||||||
|
<AccoundDeleteAlertDialog
|
||||||
|
title='Close your positions to delete your account'
|
||||||
|
description='You must first close your farming positions before deleting your account.'
|
||||||
|
closeHandler={closeDeleteAccountModal}
|
||||||
|
positiveButton={{
|
||||||
|
text: 'Close Positions',
|
||||||
|
icon: <ArrowRight />,
|
||||||
|
onClick: () => {
|
||||||
|
navigate(getRoute('farm', address, accountId))
|
||||||
|
closeDeleteAccountModal()
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (depositsAndLends.length === 0)
|
||||||
|
return (
|
||||||
|
<AccoundDeleteAlertDialog
|
||||||
|
title={`Delete Credit Account ${accountId}`}
|
||||||
|
description='Deleting your credit account is irreversible.'
|
||||||
|
closeHandler={closeDeleteAccountModal}
|
||||||
|
positiveButton={{
|
||||||
|
text: 'Close Positions',
|
||||||
|
icon: <ArrowRight />,
|
||||||
|
isAsync: true,
|
||||||
|
onClick: deleteAccountHandler,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
onClose={closeDeleteAccountModal}
|
||||||
|
header={
|
||||||
|
<span className='flex items-center'>
|
||||||
|
<Text>{`Delete Account ${modal.id}`}</Text>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
modalClassName='max-w-modal-sm'
|
||||||
|
headerClassName='gradient-header p-4 border-b-white/5 border-b'
|
||||||
|
contentClassName='w-full'
|
||||||
|
>
|
||||||
|
<div className='w-full border-b border-white/5 p-4 gradient-header'>
|
||||||
|
<Text className='text-white/50' size='sm'>
|
||||||
|
The following assets within your credit account will be sent to your wallet.
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className='max-h-100 flex w-full flex-col gap-4 overflow-y-scroll p-4 scrollbar-hide'>
|
||||||
|
{depositsAndLends.map((position, index) => {
|
||||||
|
const coin = BNCoin.fromDenomAndBigNumber(position.denom, position.amount)
|
||||||
|
const asset = getAssetByDenom(position.denom)
|
||||||
|
|
||||||
|
if (!asset) return null
|
||||||
|
return <AssetBalanceRow key={index} asset={asset} coin={coin} />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className='w-full px-4 pb-4'>
|
||||||
|
<Button
|
||||||
|
className='w-full'
|
||||||
|
onClick={deleteAccountHandler}
|
||||||
|
text='Delete Account'
|
||||||
|
rightIcon={<ArrowRight />}
|
||||||
|
showProgressIndicator={isConfirming}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { ExclamationMarkCircled } from 'components/Icons'
|
import { ExclamationMarkCircled } from 'components/Icons'
|
||||||
import Modal from 'components/Modal'
|
import Modal from 'components/Modal'
|
||||||
@ -21,11 +24,21 @@ interface Props {
|
|||||||
function AlertDialog(props: Props) {
|
function AlertDialog(props: Props) {
|
||||||
const { title, icon, description, negativeButton, positiveButton } = props.config
|
const { title, icon, description, negativeButton, positiveButton } = props.config
|
||||||
|
|
||||||
|
const [isConfirming, setIsConfirming] = useState(false)
|
||||||
|
|
||||||
const handleButtonClick = (button?: AlertDialogButton) => {
|
const handleButtonClick = (button?: AlertDialogButton) => {
|
||||||
button?.onClick && button.onClick()
|
button?.onClick && button.onClick()
|
||||||
props.close()
|
props.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleAsyncButtonClick(button?: AlertDialogButton) {
|
||||||
|
if (!button?.onClick) return
|
||||||
|
setIsConfirming(true)
|
||||||
|
await button.onClick()
|
||||||
|
setIsConfirming(false)
|
||||||
|
props.close()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
onClose={props.close}
|
onClose={props.close}
|
||||||
@ -41,19 +54,29 @@ function AlertDialog(props: Props) {
|
|||||||
>
|
>
|
||||||
<Text size='xl'>{title}</Text>
|
<Text size='xl'>{title}</Text>
|
||||||
<Text className='mt-2 text-white/60'>{description}</Text>
|
<Text className='mt-2 text-white/60'>{description}</Text>
|
||||||
<div className='mt-10 flex flex-row-reverse justify-between'>
|
<div
|
||||||
<Button
|
className={classNames('mt-10 flex justify-between', positiveButton && 'flex-row-reverse')}
|
||||||
text={positiveButton.text ?? 'Yes'}
|
>
|
||||||
color='tertiary'
|
{positiveButton && (
|
||||||
className='px-6'
|
<Button
|
||||||
rightIcon={positiveButton.icon ?? <YesIcon />}
|
text={positiveButton.text ?? 'Yes'}
|
||||||
onClick={() => handleButtonClick(positiveButton)}
|
color='tertiary'
|
||||||
/>
|
className='px-6'
|
||||||
|
rightIcon={positiveButton.icon ?? <YesIcon />}
|
||||||
|
showProgressIndicator={isConfirming}
|
||||||
|
onClick={() =>
|
||||||
|
positiveButton.isAsync
|
||||||
|
? handleAsyncButtonClick(positiveButton)
|
||||||
|
: handleButtonClick(positiveButton)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
text={negativeButton?.text ?? 'No'}
|
text={negativeButton?.text ?? 'No'}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
className='px-6'
|
className='px-6'
|
||||||
rightIcon={negativeButton?.icon ?? <NoIcon />}
|
rightIcon={negativeButton?.icon ?? <NoIcon />}
|
||||||
|
disabled={isConfirming}
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
onClick={() => handleButtonClick(negativeButton)}
|
onClick={() => handleButtonClick(negativeButton)}
|
||||||
/>
|
/>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
AccountDeleteController,
|
||||||
AddVaultBorrowAssetsModal,
|
AddVaultBorrowAssetsModal,
|
||||||
AlertDialogController,
|
AlertDialogController,
|
||||||
BorrowModal,
|
BorrowModal,
|
||||||
@ -14,6 +15,7 @@ import {
|
|||||||
export default function ModalsContainer() {
|
export default function ModalsContainer() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<AccountDeleteController />
|
||||||
<AddVaultBorrowAssetsModal />
|
<AddVaultBorrowAssetsModal />
|
||||||
<BorrowModal />
|
<BorrowModal />
|
||||||
<FundAndWithdrawModal />
|
<FundAndWithdrawModal />
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
export { default as AccountDeleteController } from 'components/Modals/Account/AccountDeleteModal'
|
||||||
export { default as AddVaultBorrowAssetsModal } from 'components/Modals/AddVaultAssets'
|
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'
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ChangeEvent, LegacyRef } from 'react'
|
import React, { ChangeEvent, LegacyRef } from 'react'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { Search } from 'components/Icons'
|
import { Search } from 'components/Icons'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string
|
value: string
|
||||||
placeholder: string
|
placeholder: string
|
||||||
autofocus?: boolean
|
autoFocus?: boolean
|
||||||
onChange: (value: string) => void
|
onChange: (value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ const SearchBar = (props: Props, ref: LegacyRef<HTMLDivElement>) => {
|
|||||||
className='h-full w-full bg-transparent text-xs placeholder-white/50 outline-none'
|
className='h-full w-full bg-transparent text-xs placeholder-white/50 outline-none'
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
onChange={(event) => onChange(event)}
|
onChange={(event) => onChange(event)}
|
||||||
autoFocus={props.autofocus}
|
autoFocus={props.autoFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -58,7 +58,7 @@ export default function TermsOfService() {
|
|||||||
>
|
>
|
||||||
<Benefits
|
<Benefits
|
||||||
benefits={[
|
benefits={[
|
||||||
'Swap tokens with margin acress any whitelisted pair',
|
'Swap tokens with margin across any whitelisted pair',
|
||||||
'Amplify your LP rewards with leveraged yield farming',
|
'Amplify your LP rewards with leveraged yield farming',
|
||||||
'Earn interest on deposited tokens',
|
'Earn interest on deposited tokens',
|
||||||
]}
|
]}
|
||||||
|
@ -63,7 +63,7 @@ export default function AssetOverlay(props: Props) {
|
|||||||
value={searchString}
|
value={searchString}
|
||||||
onChange={onChangeSearch}
|
onChange={onChangeSearch}
|
||||||
placeholder='Search for e.g. "ETH" or "Ethereum"'
|
placeholder='Search for e.g. "ETH" or "Ethereum"'
|
||||||
autofocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
@ -15,6 +15,22 @@ import { getSingleValueFromBroadcastResult } from 'utils/broadcast'
|
|||||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||||
import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse'
|
import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse'
|
||||||
|
|
||||||
|
function generateExecutionMessage(
|
||||||
|
sender: string | undefined,
|
||||||
|
contract: string,
|
||||||
|
msg: CreditManagerExecuteMsg | AccountNftExecuteMsg,
|
||||||
|
funds: Coin[],
|
||||||
|
) {
|
||||||
|
if (!sender) return
|
||||||
|
|
||||||
|
return new MsgExecuteContract({
|
||||||
|
sender,
|
||||||
|
contract,
|
||||||
|
msg,
|
||||||
|
funds,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default function createBroadcastSlice(
|
export default function createBroadcastSlice(
|
||||||
set: SetState<Store>,
|
set: SetState<Store>,
|
||||||
get: GetState<Store>,
|
get: GetState<Store>,
|
||||||
@ -60,7 +76,10 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -74,8 +93,11 @@ export default function createBroadcastSlice(
|
|||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
create_credit_account: 'default',
|
create_credit_account: 'default',
|
||||||
}
|
}
|
||||||
set({ createAccountModal: true })
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
if (response.result) {
|
if (response.result) {
|
||||||
set({ createAccountModal: false })
|
set({ createAccountModal: false })
|
||||||
@ -93,16 +115,33 @@ export default function createBroadcastSlice(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteAccount: async (options: { fee: StdFee; accountId: string }) => {
|
deleteAccount: async (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => {
|
||||||
const msg: AccountNftExecuteMsg = {
|
const reclaimMsg = options.lends.map((coin) => {
|
||||||
|
return {
|
||||||
|
reclaim: coin.toActionCoin(true),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const refundMessage: CreditManagerExecuteMsg = {
|
||||||
|
update_credit_account: {
|
||||||
|
account_id: options.accountId,
|
||||||
|
actions: [...reclaimMsg, { refund_all_coin_balances: {} }],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const burnMessage: AccountNftExecuteMsg = {
|
||||||
burn: {
|
burn: {
|
||||||
token_id: options.accountId,
|
token_id: options.accountId,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
set({ deleteAccountModal: true })
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
|
||||||
|
|
||||||
set({ deleteAccountModal: false })
|
const response = await get().executeMsg({
|
||||||
|
messages: [
|
||||||
|
generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, refundMessage, []),
|
||||||
|
generateExecutionMessage(get().address, ENV.ADDRESS_ACCOUNT_NFT, burnMessage, []),
|
||||||
|
],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(response, `Account ${options.accountId} deleted`)
|
handleResponseMessages(response, `Account ${options.accountId} deleted`)
|
||||||
|
|
||||||
@ -118,7 +157,12 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee, funds: options.coins })
|
const response = await get().executeMsg({
|
||||||
|
messages: [
|
||||||
|
generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, options.coins),
|
||||||
|
],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
const depositString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
const depositString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
||||||
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
|
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
|
||||||
@ -145,9 +189,8 @@ export default function createBroadcastSlice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({
|
const response = await get().executeMsg({
|
||||||
msg,
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
fee: options.fee,
|
fee: options.fee,
|
||||||
funds: [],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
handleResponseMessages(response, `Requested unlock for ${options.vault.name}`)
|
handleResponseMessages(response, `Requested unlock for ${options.vault.name}`)
|
||||||
@ -176,7 +219,11 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults'
|
const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults'
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -191,7 +238,11 @@ export default function createBroadcastSlice(
|
|||||||
actions: options.actions,
|
actions: options.actions,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
|
||||||
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(response, `Deposited into vault`)
|
handleResponseMessages(response, `Deposited into vault`)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
@ -206,7 +257,11 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
const withdrawString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
const withdrawString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -214,44 +269,6 @@ export default function createBroadcastSlice(
|
|||||||
)
|
)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
executeMsg: async (options: {
|
|
||||||
fee: StdFee
|
|
||||||
msg: Record<string, unknown>
|
|
||||||
funds?: Coin[]
|
|
||||||
}): Promise<BroadcastResult> => {
|
|
||||||
const funds = options.funds ?? []
|
|
||||||
|
|
||||||
try {
|
|
||||||
const client = get().client
|
|
||||||
if (!client) return { error: 'no client detected' }
|
|
||||||
|
|
||||||
const broadcastOptions = {
|
|
||||||
messages: [
|
|
||||||
new MsgExecuteContract({
|
|
||||||
sender: client.connectedWallet.account.address,
|
|
||||||
contract: ENV.ADDRESS_CREDIT_MANAGER,
|
|
||||||
msg: options.msg,
|
|
||||||
funds,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
feeAmount: options.fee.amount[0].amount,
|
|
||||||
gasLimit: options.fee.gas,
|
|
||||||
memo: undefined,
|
|
||||||
wallet: client.connectedWallet,
|
|
||||||
mobile: isMobile,
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await client.broadcast(broadcastOptions)
|
|
||||||
|
|
||||||
if (result.hash) {
|
|
||||||
return { result }
|
|
||||||
}
|
|
||||||
return { result: undefined, error: 'Transaction failed' }
|
|
||||||
} catch (e: unknown) {
|
|
||||||
const error = typeof e === 'string' ? e : 'Transaction failed'
|
|
||||||
return { result: undefined, error }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
repay: async (options: {
|
repay: async (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
@ -271,7 +288,10 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee, funds: [] })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -291,7 +311,10 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -311,7 +334,10 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
@ -341,7 +367,11 @@ export default function createBroadcastSlice(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await get().executeMsg({ msg, fee: options.fee })
|
const response = await get().executeMsg({
|
||||||
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
|
||||||
|
fee: options.fee,
|
||||||
|
})
|
||||||
|
|
||||||
const coinOut = getTokenOutFromSwapResponse(response, options.denomOut)
|
const coinOut = getTokenOutFromSwapResponse(response, options.denomOut)
|
||||||
const successMessage = `Swapped ${formatAmountWithSymbol(
|
const successMessage = `Swapped ${formatAmountWithSymbol(
|
||||||
options.coinIn.toCoin(),
|
options.coinIn.toCoin(),
|
||||||
@ -350,5 +380,37 @@ export default function createBroadcastSlice(
|
|||||||
handleResponseMessages(response, successMessage)
|
handleResponseMessages(response, successMessage)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
|
executeMsg: async (options: {
|
||||||
|
messages: MsgExecuteContract[]
|
||||||
|
fee: StdFee
|
||||||
|
}): Promise<BroadcastResult> => {
|
||||||
|
try {
|
||||||
|
const client = get().client
|
||||||
|
if (!client) return { error: 'no client detected' }
|
||||||
|
|
||||||
|
const broadcastOptions = {
|
||||||
|
messages: options.messages,
|
||||||
|
feeAmount: options.fee.amount[0].amount,
|
||||||
|
gasLimit: options.fee.gas,
|
||||||
|
memo: undefined,
|
||||||
|
wallet: client.connectedWallet,
|
||||||
|
mobile: isMobile,
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await client.broadcast(broadcastOptions)
|
||||||
|
|
||||||
|
if (result.hash) {
|
||||||
|
return { result }
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: undefined,
|
||||||
|
error: 'Transaction failed',
|
||||||
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
const error = typeof e === 'string' ? e : 'Transaction failed'
|
||||||
|
return { result: undefined, error }
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ import { GetState, SetState } from 'zustand'
|
|||||||
export default function createModalSlice(set: SetState<ModalSlice>, get: GetState<ModalSlice>) {
|
export default function createModalSlice(set: SetState<ModalSlice>, get: GetState<ModalSlice>) {
|
||||||
return {
|
return {
|
||||||
addVaultBorrowingsModal: null,
|
addVaultBorrowingsModal: null,
|
||||||
|
accountDeleteModal: null,
|
||||||
alertDialog: null,
|
alertDialog: null,
|
||||||
borrowModal: null,
|
borrowModal: null,
|
||||||
createAccountModal: false,
|
createAccountModal: false,
|
||||||
deleteAccountModal: false,
|
|
||||||
fundAccountModal: false,
|
fundAccountModal: false,
|
||||||
fundAndWithdrawModal: null,
|
fundAndWithdrawModal: null,
|
||||||
lendAndReclaimModal: null,
|
lendAndReclaimModal: null,
|
||||||
|
1
src/types/interfaces/components/Button.d.ts
vendored
1
src/types/interfaces/components/Button.d.ts
vendored
@ -1,4 +1,5 @@
|
|||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
|
autoFocus?: boolean
|
||||||
children?: string | ReactNode
|
children?: string | ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
color?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
color?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
||||||
|
8
src/types/interfaces/store/broadcast.d.ts
vendored
8
src/types/interfaces/store/broadcast.d.ts
vendored
@ -7,11 +7,7 @@ interface BroadcastResult {
|
|||||||
|
|
||||||
interface BroadcastSlice {
|
interface BroadcastSlice {
|
||||||
toast: { message: string; isError?: boolean; title?: string } | null
|
toast: { message: string; isError?: boolean; title?: string } | null
|
||||||
executeMsg: (options: {
|
executeMsg: (options: { messages: MsgExecuteContract[]; fee: StdFee }) => Promise<BroadcastResult>
|
||||||
msg: Record<string, unknown>
|
|
||||||
fee: StdFee
|
|
||||||
funds?: Coin[]
|
|
||||||
}) => Promise<BroadcastResult>
|
|
||||||
borrow: (options: {
|
borrow: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
@ -19,7 +15,7 @@ interface BroadcastSlice {
|
|||||||
borrowToWallet: boolean
|
borrowToWallet: boolean
|
||||||
}) => 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; lends: BNCoin[] }) => Promise<boolean>
|
||||||
deposit: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
deposit: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
||||||
unlock: (options: {
|
unlock: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
|
16
src/types/interfaces/store/modals.d.ts
vendored
16
src/types/interfaces/store/modals.d.ts
vendored
@ -1,9 +1,9 @@
|
|||||||
interface ModalSlice {
|
interface ModalSlice {
|
||||||
|
accountDeleteModal: Account | null
|
||||||
addVaultBorrowingsModal: AddVaultBorrowingsModal | null
|
addVaultBorrowingsModal: AddVaultBorrowingsModal | null
|
||||||
alertDialog: AlertDialogConfig | null
|
alertDialog: AlertDialogConfig | null
|
||||||
borrowModal: BorrowModal | null
|
borrowModal: BorrowModal | null
|
||||||
createAccountModal: boolean
|
createAccountModal: boolean
|
||||||
deleteAccountModal: boolean
|
|
||||||
fundAccountModal: boolean
|
fundAccountModal: boolean
|
||||||
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
||||||
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
||||||
@ -17,6 +17,7 @@ interface ModalSlice {
|
|||||||
interface AlertDialogButton {
|
interface AlertDialogButton {
|
||||||
text?: string
|
text?: string
|
||||||
icon?: JSX.Element
|
icon?: JSX.Element
|
||||||
|
isAsync?: boolean
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +26,12 @@ interface AlertDialogConfig {
|
|||||||
title: JSX.Element | string
|
title: JSX.Element | string
|
||||||
description: JSX.Element | string
|
description: JSX.Element | string
|
||||||
negativeButton?: AlertDialogButton
|
negativeButton?: AlertDialogButton
|
||||||
positiveButton: AlertDialogButton
|
positiveButton?: AlertDialogButton
|
||||||
|
}
|
||||||
|
interface BorrowModal {
|
||||||
|
asset: Asset
|
||||||
|
marketData: BorrowMarketTableData
|
||||||
|
isRepay?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type LendAndReclaimModalAction = 'lend' | 'reclaim'
|
type LendAndReclaimModalAction = 'lend' | 'reclaim'
|
||||||
@ -34,12 +40,6 @@ interface LendAndReclaimModalConfig {
|
|||||||
action: LendAndReclaimModalAction
|
action: LendAndReclaimModalAction
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BorrowModal {
|
|
||||||
asset: Asset
|
|
||||||
marketData: BorrowMarketTableData
|
|
||||||
isRepay?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VaultModal {
|
interface VaultModal {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
isDeposited?: boolean
|
isDeposited?: boolean
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
export function isNumber(value: unknown) {
|
export function isNumber(value: unknown) {
|
||||||
if (typeof value === 'string' && value !== '') {
|
if (typeof value === 'string' && value !== '') {
|
||||||
return !isNaN(Number(value))
|
return !isNaN(Number(value))
|
||||||
@ -13,3 +15,25 @@ export function isNumber(value: unknown) {
|
|||||||
export const convertAprToApy = (apr: number, numberOfCompoundingPeriods: number): number => {
|
export const convertAprToApy = (apr: number, numberOfCompoundingPeriods: number): number => {
|
||||||
return ((1 + apr / 100 / numberOfCompoundingPeriods) ** numberOfCompoundingPeriods - 1) * 100
|
return ((1 + apr / 100 / numberOfCompoundingPeriods) ** numberOfCompoundingPeriods - 1) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const combineBNCoins = (coins: BNCoin[]): BNCoin[] => {
|
||||||
|
const combinedMap: { [key: string]: number } = {}
|
||||||
|
|
||||||
|
coins.forEach((coin) => {
|
||||||
|
if (combinedMap.hasOwnProperty(coin.denom)) {
|
||||||
|
combinedMap[coin.denom] += coin.amount.toNumber()
|
||||||
|
} else {
|
||||||
|
combinedMap[coin.denom] = coin.amount.toNumber()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const combinedArray: BNCoin[] = Object.keys(combinedMap).map(
|
||||||
|
(denom) =>
|
||||||
|
new BNCoin({
|
||||||
|
denom,
|
||||||
|
amount: BN(combinedMap[denom]).toString(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
return combinedArray
|
||||||
|
}
|
||||||
|
@ -166,7 +166,7 @@ module.exports = {
|
|||||||
maxWidth: {
|
maxWidth: {
|
||||||
content: '1024px',
|
content: '1024px',
|
||||||
modal: '895px',
|
modal: '895px',
|
||||||
'modal-sm': '517px',
|
'modal-sm': '526px',
|
||||||
'modal-xs': '442px',
|
'modal-xs': '442px',
|
||||||
},
|
},
|
||||||
minWidth: {
|
minWidth: {
|
||||||
|
Loading…
Reference in New Issue
Block a user