Mp 2880 modifying farm position (#272)
* added correct resolving of account positions * solve rendering bug for lp amount * bugfix: add slippage to minlpamount * fix DisplayCurrency to accept only BNCoin * bugfix: remove prices from store * add basic depostied vaults table * Farm: Added deposited table * finish deposited table, remove featured vaults: * enable deposit more for vaults * use controller for vault modal * small fixes and polishing of add deposit * fix tests, run format * removed empty deposited table --------- Co-authored-by: Linkie Link <linkielink.dev@gmail.com>
This commit is contained in:
parent
697e83b7cb
commit
999bad4059
@ -22,7 +22,7 @@ jest.mock('hooks/useMarketAssets', () =>
|
||||
})),
|
||||
)
|
||||
|
||||
jest.mock('hooks/broadcast/useDepositVault', () => jest.fn(() => ({})))
|
||||
jest.mock('hooks/broadcast/useDepositVault', () => jest.fn(() => ({ actions: [] })))
|
||||
|
||||
jest.mock('components/DisplayCurrency')
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { render } from '@testing-library/react'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { ChevronDown, ChevronRight } from 'components/Icons'
|
||||
@ -12,14 +13,12 @@ export interface Item {
|
||||
title: string
|
||||
renderContent: () => React.ReactNode
|
||||
isOpen?: boolean
|
||||
subTitle?: string | React.ReactNode
|
||||
renderSubTitle: () => React.ReactNode
|
||||
toggleOpen: (index: number) => void
|
||||
}
|
||||
|
||||
export default function AccordionContent(props: Props) {
|
||||
const { title, renderContent, isOpen, subTitle, toggleOpen } = props.item
|
||||
|
||||
const shouldShowSubTitle = subTitle && !isOpen
|
||||
const { title, renderContent, isOpen, renderSubTitle, toggleOpen } = props.item
|
||||
|
||||
return (
|
||||
<div key={title} className='group border-b-white/10 [&:not(:last-child)]:border-b'>
|
||||
@ -34,11 +33,9 @@ export default function AccordionContent(props: Props) {
|
||||
>
|
||||
<div>
|
||||
<Text>{title}</Text>
|
||||
{shouldShowSubTitle && (
|
||||
<Text size='xs' className='mt-1 text-white/60'>
|
||||
{subTitle}
|
||||
</Text>
|
||||
)}
|
||||
<Text size='xs' className='mt-1 text-white/60'>
|
||||
{renderSubTitle()}
|
||||
</Text>
|
||||
</div>
|
||||
<div className='block pr-1 group-[[open]]:hidden'>
|
||||
{isOpen ? <ChevronDown /> : <ChevronRight />}
|
||||
|
@ -54,6 +54,7 @@ export default function AccountSummary(props: Props) {
|
||||
) : null,
|
||||
isOpen: isOpen[0],
|
||||
toggleOpen: (index: number) => toggleOpen(index),
|
||||
renderSubTitle: () => <></>,
|
||||
},
|
||||
{
|
||||
title: 'Balances',
|
||||
@ -61,6 +62,7 @@ export default function AccountSummary(props: Props) {
|
||||
props.account ? <AccountBalancesTable data={props.account} /> : null,
|
||||
isOpen: isOpen[1],
|
||||
toggleOpen: (index: number) => toggleOpen(index),
|
||||
renderSubTitle: () => <></>,
|
||||
},
|
||||
]}
|
||||
allowMultipleOpen
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import Button from 'components/Button'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import { LockUnlocked, Plus } from 'components/Icons'
|
||||
import useStore from 'store'
|
||||
|
||||
@ -19,6 +19,16 @@ export default function VaultExpanded(props: Props) {
|
||||
})
|
||||
}
|
||||
|
||||
function depositMoreHandler() {
|
||||
useStore.setState({
|
||||
vaultModal: {
|
||||
vault: props.row.original,
|
||||
isDeposited: true,
|
||||
selectedBorrowDenoms: [props.row.original.denoms.secondary],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
let isDeposited: boolean = false
|
||||
if ((props.row.original as DepositedVault)?.amounts) {
|
||||
isDeposited = true
|
||||
@ -39,7 +49,11 @@ export default function VaultExpanded(props: Props) {
|
||||
<div className='align-center flex justify-end gap-3 p-4'>
|
||||
{isDeposited ? (
|
||||
<>
|
||||
<Button color='secondary' leftIcon={<Plus className='w-3' />}>
|
||||
<Button
|
||||
onClick={depositMoreHandler}
|
||||
color='secondary'
|
||||
leftIcon={<Plus className='w-3' />}
|
||||
>
|
||||
Deposit more
|
||||
</Button>
|
||||
<Button color='tertiary' leftIcon={<LockUnlocked />}>
|
||||
|
@ -76,3 +76,21 @@ function Fallback() {
|
||||
|
||||
return <VaultTable data={mockVaults} isLoading />
|
||||
}
|
||||
|
||||
export function AvailableVaults() {
|
||||
return (
|
||||
<Card className='h-fit w-full bg-white/5' title='Available vaults'>
|
||||
<Suspense fallback={<Fallback />}>
|
||||
<Content type='available' />
|
||||
</Suspense>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export function DepositedVaults() {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<Content type='deposited' />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import VaultModal from 'components/Modals/Vault/VaultModal'
|
||||
import VaultModal from 'components/Modals/Vault'
|
||||
import BorrowModal from 'components/Modals/Borrow/BorrowModal'
|
||||
import FundAndWithdrawModal from 'components/Modals/FundWithdraw/FundAndWithdrawModal'
|
||||
import AddVaultBorrowAssetsModal from 'components/Modals/AddVaultAssets/AddVaultBorrowAssetsModal'
|
||||
@ -11,7 +11,6 @@ export default function ModalsContainer() {
|
||||
<VaultModal />
|
||||
<BorrowModal />
|
||||
<FundAndWithdrawModal />
|
||||
<VaultModal />
|
||||
<AddVaultBorrowAssetsModal />
|
||||
<UnlockModal />
|
||||
<LendAndReclaimModalController />
|
||||
|
@ -40,6 +40,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const vaultModal = useStore((s) => s.vaultModal)
|
||||
const depositIntoVault = useStore((s) => s.depositIntoVault)
|
||||
const [isConfirming, setIsConfirming] = useState(false)
|
||||
|
||||
const { actions: depositActions, fee: depositFee } = useDepositVault({
|
||||
vault: props.vault,
|
||||
@ -149,8 +150,17 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
})
|
||||
}
|
||||
|
||||
function onConfirm() {
|
||||
depositIntoVault({ fee: depositFee, accountId: props.account.id, actions: depositActions })
|
||||
async function onConfirm() {
|
||||
setIsConfirming(true)
|
||||
const isSuccess = await depositIntoVault({
|
||||
fee: depositFee,
|
||||
accountId: props.account.id,
|
||||
actions: depositActions,
|
||||
})
|
||||
setIsConfirming(false)
|
||||
if (isSuccess) {
|
||||
useStore.setState({ vaultModal: null })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -207,7 +217,14 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<Button onClick={onConfirm} color='primary' text='Deposit' rightIcon={<ArrowRight />} />
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
color='primary'
|
||||
text='Deposit'
|
||||
rightIcon={<ArrowRight />}
|
||||
showProgressIndicator={isConfirming}
|
||||
disabled={!depositActions.length}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -50,12 +50,12 @@ export default function VaultDeposit(props: Props) {
|
||||
[primaryValue, secondaryValue],
|
||||
)
|
||||
|
||||
const primaryValuePercentage = useMemo(
|
||||
() => primaryValue.div(totalValue).times(100).decimalPlaces(2).toNumber() || 50,
|
||||
[primaryValue, totalValue],
|
||||
)
|
||||
const primaryValuePercentage = useMemo(() => {
|
||||
const value = primaryValue.div(totalValue).times(100).decimalPlaces(2).toNumber()
|
||||
return isNaN(value) ? 50 : value
|
||||
}, [primaryValue, totalValue])
|
||||
const secondaryValuePercentage = useMemo(
|
||||
() => new BigNumber(100).minus(primaryValuePercentage).decimalPlaces(2).toNumber() || 50,
|
||||
() => new BigNumber(100).minus(primaryValuePercentage).integerValue(2).toNumber() ?? 50,
|
||||
[primaryValuePercentage],
|
||||
)
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
import VaultLogo from 'components/Earn/vault/VaultLogo'
|
||||
import Modal from 'components/Modal'
|
||||
import Text from 'components/Text'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useStore from 'store'
|
||||
import { CircularProgress } from 'components/CircularProgress'
|
||||
import VaultModalContent from 'components/Modals/Vault/VaultModalContent'
|
||||
|
||||
export default function VaultModal() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const modal = useStore((s) => s.vaultModal)
|
||||
|
||||
const primaryAsset =
|
||||
ASSETS.find((asset) => asset.denom === modal?.vault.denoms.primary) ?? ASSETS[0]
|
||||
const secondaryAsset =
|
||||
ASSETS.find((asset) => asset.denom === modal?.vault.denoms.secondary) ?? ASSETS[0]
|
||||
|
||||
const hasValidData = primaryAsset && currentAccount && secondaryAsset
|
||||
|
||||
function onClose() {
|
||||
useStore.setState({ vaultModal: null })
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={!!(modal && hasValidData)}
|
||||
onClose={onClose}
|
||||
header={
|
||||
modal && (
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<VaultLogo vault={modal.vault} />
|
||||
<Text>{`${modal.vault.symbols.primary} - ${modal.vault.symbols.secondary}`}</Text>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
{modal?.vault && currentAccount ? (
|
||||
<VaultModalContent
|
||||
vault={modal.vault}
|
||||
primaryAsset={primaryAsset}
|
||||
secondaryAsset={secondaryAsset}
|
||||
account={currentAccount}
|
||||
/>
|
||||
) : (
|
||||
<CircularProgress />
|
||||
)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -13,10 +13,11 @@ import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
interface Props {
|
||||
vault: Vault
|
||||
vault: Vault | DepositedVault
|
||||
primaryAsset: Asset
|
||||
secondaryAsset: Asset
|
||||
account: Account
|
||||
isDeposited?: boolean
|
||||
}
|
||||
|
||||
export default function VaultModalContent(props: Props) {
|
||||
@ -55,6 +56,31 @@ export default function VaultModalContent(props: Props) {
|
||||
[setIsCustomRatio],
|
||||
)
|
||||
|
||||
function getDepositSubTitle() {
|
||||
if (isOpen[0] && props.isDeposited)
|
||||
return 'The amounts you enter below will be added to your current position.'
|
||||
|
||||
if (isOpen[0]) return null
|
||||
|
||||
return (
|
||||
<VaultDepositSubTitle
|
||||
primaryAmount={primaryAmount}
|
||||
secondaryAmount={secondaryAmount}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function getBorrowingsSubTitle() {
|
||||
if (isOpen[1] && props.isDeposited)
|
||||
return 'The amounts you enter below will be added to your current position.'
|
||||
|
||||
if (isOpen[1]) return null
|
||||
|
||||
return <VaultBorrowingsSubTitle borrowings={borrowings} />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-grow items-start gap-6 p-6'>
|
||||
<Accordion
|
||||
@ -76,14 +102,7 @@ export default function VaultModalContent(props: Props) {
|
||||
/>
|
||||
),
|
||||
title: 'Deposit',
|
||||
subTitle: (
|
||||
<VaultDepositSubTitle
|
||||
primaryAmount={primaryAmount}
|
||||
secondaryAmount={secondaryAmount}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
/>
|
||||
),
|
||||
renderSubTitle: getDepositSubTitle,
|
||||
isOpen: isOpen[0],
|
||||
toggleOpen: (index: number) => toggleOpen(index),
|
||||
},
|
||||
@ -102,7 +121,7 @@ export default function VaultModalContent(props: Props) {
|
||||
/>
|
||||
),
|
||||
title: 'Borrow',
|
||||
subTitle: <VaultBorrowingsSubTitle borrowings={borrowings} />,
|
||||
renderSubTitle: getBorrowingsSubTitle,
|
||||
isOpen: isOpen[1],
|
||||
toggleOpen: (index: number) => toggleOpen(index),
|
||||
},
|
||||
|
61
src/components/Modals/Vault/index.tsx
Normal file
61
src/components/Modals/Vault/index.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import VaultLogo from 'components/Earn/vault/VaultLogo'
|
||||
import Modal from 'components/Modal'
|
||||
import Text from 'components/Text'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useStore from 'store'
|
||||
import VaultModalContent from 'components/Modals/Vault/VaultModalContent'
|
||||
|
||||
export default function VaultModalController() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const modal = useStore((s) => s.vaultModal)
|
||||
const primaryAsset = ASSETS.find((asset) => asset.denom === modal?.vault.denoms.primary)
|
||||
const secondaryAsset = ASSETS.find((asset) => asset.denom === modal?.vault.denoms.secondary)
|
||||
|
||||
if (!modal || !currentAccount || !primaryAsset || !secondaryAsset) return null
|
||||
|
||||
return (
|
||||
<VaultModal
|
||||
currentAccount={currentAccount}
|
||||
modal={modal}
|
||||
primaryAsset={primaryAsset}
|
||||
secondaryAsset={secondaryAsset}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
interface Props {
|
||||
currentAccount: Account
|
||||
modal: VaultModal
|
||||
primaryAsset: Asset
|
||||
secondaryAsset: Asset
|
||||
}
|
||||
|
||||
function VaultModal(props: Props) {
|
||||
function onClose() {
|
||||
useStore.setState({ vaultModal: null })
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={true}
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<VaultLogo vault={props.modal.vault} />
|
||||
<Text>{`${props.modal.vault.symbols.primary} - ${props.modal.vault.symbols.secondary}`}</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col'
|
||||
>
|
||||
<VaultModalContent
|
||||
vault={props.modal.vault}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
account={props.currentAccount}
|
||||
isDeposited={props.modal.isDeposited}
|
||||
/>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -157,6 +157,7 @@ export default function NumberInput(props: Props) {
|
||||
props.className,
|
||||
)}
|
||||
style={props.style}
|
||||
placeholder='0'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -24,36 +24,31 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
|
||||
const { data: prices } = usePrices()
|
||||
const slippage = useStore((s) => s.slippage)
|
||||
|
||||
const borrowings: BNCoin[] = useMemo(
|
||||
() => props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
|
||||
[props.borrowings],
|
||||
)
|
||||
const deposits: BNCoin[] = useMemo(
|
||||
() => props.deposits.filter((deposit) => deposit.amount.gt(0)),
|
||||
[props.deposits],
|
||||
)
|
||||
|
||||
const debouncedGetMinLpToReceive = useMemo(() => debounce(getMinLpToReceive, 500), [])
|
||||
|
||||
const { primaryCoin, secondaryCoin, totalValue } = useMemo(
|
||||
() =>
|
||||
getVaultDepositCoinsAndValue(
|
||||
props.vault,
|
||||
props.deposits.filter((borrowing) => borrowing.amount.gt(0)),
|
||||
props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
|
||||
prices,
|
||||
),
|
||||
[props.deposits, props.borrowings, props.vault, prices],
|
||||
() => getVaultDepositCoinsAndValue(props.vault, deposits, borrowings, prices),
|
||||
[deposits, borrowings, props.vault, prices],
|
||||
)
|
||||
|
||||
const borrowActions: Action[] = useMemo(() => {
|
||||
return props.borrowings.map((bnCoin) => ({
|
||||
return borrowings.map((bnCoin) => ({
|
||||
borrow: bnCoin.toCoin(),
|
||||
}))
|
||||
}, [props.borrowings])
|
||||
}, [borrowings])
|
||||
|
||||
const swapActions: Action[] = useMemo(
|
||||
() =>
|
||||
getVaultSwapActions(
|
||||
props.vault,
|
||||
props.deposits.filter((borrowing) => borrowing.amount.gt(0)),
|
||||
props.borrowings.filter((borrowing) => borrowing.amount.gt(0)),
|
||||
prices,
|
||||
slippage,
|
||||
totalValue,
|
||||
),
|
||||
[totalValue, prices, props.vault, props.deposits, props.borrowings, slippage],
|
||||
() => getVaultSwapActions(props.vault, deposits, borrowings, prices, slippage, totalValue),
|
||||
[totalValue, prices, props.vault, deposits, borrowings, slippage],
|
||||
)
|
||||
|
||||
useMemo(async () => {
|
||||
@ -77,6 +72,8 @@ export default function useDepositVault(props: Props): { actions: Action[]; fee:
|
||||
])
|
||||
|
||||
const enterVaultActions: Action[] = useMemo(() => {
|
||||
if (primaryCoin.amount.isZero() || secondaryCoin.amount.isZero()) return []
|
||||
|
||||
return getEnterVaultActions(props.vault, primaryCoin, secondaryCoin, minLpToReceive)
|
||||
}, [props.vault, primaryCoin, secondaryCoin, minLpToReceive])
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import Tab from 'components/Earn/Tab'
|
||||
import Vaults from 'components/Earn/vault/Vaults'
|
||||
import { AvailableVaults, DepositedVaults } from 'components/Earn/vault/Vaults'
|
||||
|
||||
export default function FarmPage() {
|
||||
return (
|
||||
<>
|
||||
<Tab isFarm />
|
||||
{/* <FeaturedVaults /> */}
|
||||
<Vaults type='deposited' />
|
||||
<Vaults type='available' />
|
||||
<DepositedVaults />
|
||||
<AvailableVaults />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
3
src/types/interfaces/store/modals.d.ts
vendored
3
src/types/interfaces/store/modals.d.ts
vendored
@ -23,7 +23,8 @@ interface BorrowModal {
|
||||
}
|
||||
|
||||
interface VaultModal {
|
||||
vault: Vault
|
||||
vault: Vault | DepositedVault
|
||||
isDeposited?: boolean
|
||||
selectedBorrowDenoms: string[]
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user