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