From 4b0a504ef6ba0c3f6738bcd4277d970252bdec3b Mon Sep 17 00:00:00 2001 From: Ishwaryaa Date: Wed, 20 Oct 2021 13:04:23 +0530 Subject: [PATCH 1/2] added min received in swap --- frontend/app/src/api/tzkt.ts | 27 +++++++++++++++++++ frontend/app/src/api/user.ts | 27 +------------------ frontend/app/src/components/SignIn/SignIn.tsx | 6 +++-- .../app/src/components/Trade/Swap/Swap.tsx | 9 +++++++ 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/frontend/app/src/api/tzkt.ts b/frontend/app/src/api/tzkt.ts index f7a1c544..f2fc2c9c 100644 --- a/frontend/app/src/api/tzkt.ts +++ b/frontend/app/src/api/tzkt.ts @@ -47,3 +47,30 @@ export const getAllOvensAPI = async (): Promise => { const data = await get(`bigmaps/${CTEZ_CONTRACT_BIGMAP}/keys`); return data; }; + +export const getUserOvenData = async (userAddress: string) => { + try { + const userOvenData: any = await get( + `bigmaps/${CTEZ_CONTRACT_BIGMAP}/keys?key.owner=${userAddress}`, + undefined, + userAddress, + ); + let tezInOvens: any = 0; + let ctezOutstanding: any = 0; + const userOvenDataLength: any = userOvenData.data.length; + for (let i = 0; i < userOvenDataLength; ) { + tezInOvens += Number(userOvenData.data[i].value.tez_balance) / 1e6; + ctezOutstanding += Number(userOvenData.data[i].value.ctez_outstanding) / 1e6; + i += 1; + } + return { + tezInOvens, + ctezOutstanding, + }; + } catch (error) { + return { + tezInOvens: 0, + ctezOutstanding: 0, + }; + } +}; diff --git a/frontend/app/src/api/user.ts b/frontend/app/src/api/user.ts index 9a5d5217..15601800 100644 --- a/frontend/app/src/api/user.ts +++ b/frontend/app/src/api/user.ts @@ -1,7 +1,7 @@ -import axios from 'axios'; import { getTezosInstance } from '../contracts/client'; import { getCTezFa12Contract } from '../contracts/fa12'; import { UserBalance } from '../interfaces'; +import { getUserOvenData } from './tzkt'; const getXtzBalance = async (userAddress: string) => { try { @@ -25,31 +25,6 @@ const getCtezBalance = async (userAddress: string) => { } }; -export const getUserOvenData = async (userAddress: string) => { - try { - const userOvenData: any = await axios.get( - `https://api.granadanet.tzkt.io/v1/bigmaps/59943/keys?key.owner=${userAddress}`, - ); - let tezInOvens: any = 0; - let ctezOutstanding: any = 0; - const userOvenDataLength: any = userOvenData.data.length; - for (let i = 0; i < userOvenDataLength; ) { - tezInOvens += Number(userOvenData.data[i].value.tez_balance) / 1e6; - ctezOutstanding += Number(userOvenData.data[i].value.ctez_outstanding) / 1e6; - i += 1; - } - return { - tezInOvens, - ctezOutstanding, - }; - } catch (error) { - return { - tezInOvens: 0, - ctezOutstanding: 0, - }; - } -}; - export const getUserBalance = async (userAddress: string): Promise => { try { const ctez = await getCtezBalance(userAddress); diff --git a/frontend/app/src/components/SignIn/SignIn.tsx b/frontend/app/src/components/SignIn/SignIn.tsx index 53cac163..0f50e26c 100644 --- a/frontend/app/src/components/SignIn/SignIn.tsx +++ b/frontend/app/src/components/SignIn/SignIn.tsx @@ -120,11 +120,13 @@ const SignIn: React.FC = () => { <> ꜩ in ovens: - {formatNumber(balance.tezInOvens, 0)} + {formatNumber(balance.tezInOvens, 0)?.toFixed(6)} cꜩ outstanding: - {formatNumber(balance.ctezOutstanding, 0)} + + {formatNumber(balance.ctezOutstanding, 0)?.toFixed(6)} + )} diff --git a/frontend/app/src/components/Trade/Swap/Swap.tsx b/frontend/app/src/components/Trade/Swap/Swap.tsx index c777380c..5045b5f0 100644 --- a/frontend/app/src/components/Trade/Swap/Swap.tsx +++ b/frontend/app/src/components/Trade/Swap/Swap.tsx @@ -52,6 +52,7 @@ const Swap: React.FC = () => { const handleProcessing = useTxLoader(); const { slippage, deadline: deadlineFromStore } = useAppSelector((state) => state.trade); + const [minReceived, setMinReceived] = useState(0); const getRightElement = useCallback((token: TToken) => { if (token === TOKEN.Tez) { @@ -142,6 +143,8 @@ const Swap: React.FC = () => { const tokWithoutSlippage = (cashSold * 997 * aPool.toNumber()) / (bPool.toNumber() * 1000 + cashSold * 997) / 1e6; setMinBuyValue(Number(tokWithoutSlippage.toFixed(6))); + const minRece = tokWithoutSlippage - (tokWithoutSlippage * slippage) / 100; + setMinReceived(minRece); } else { setMinBuyValue(0); } @@ -220,6 +223,12 @@ const Swap: React.FC = () => { 1 tez = {(1 / Number(baseStats?.currentPrice ?? 1)).toFixed(6)} ctez + + Min Received + + {Number(minReceived).toFixed(6)} ctez + + Price Impact 0.0000% From d88efad90ef4206607a43b76e047f5ab268e7a4b Mon Sep 17 00:00:00 2001 From: Ishwaryaa Date: Wed, 20 Oct 2021 17:10:16 +0530 Subject: [PATCH 2/2] added liquidate oven modal and fixed few ui tweaks --- frontend/app/src/api/tzkt.ts | 7 +- frontend/app/src/api/user.ts | 1 - .../app/src/components/OvenCard/OvenCard.tsx | 2 +- .../app/src/components/OvenCard/OvenStats.tsx | 2 +- .../src/components/OvenCard/ProgressPill.tsx | 76 ++++++-- .../app/src/components/Trade/Swap/Swap.tsx | 9 +- .../src/components/input/DepositorsInput.tsx | 2 +- .../app/src/components/modals/Liquidate.tsx | 167 ++++++++++++++++++ frontend/app/src/contracts/cfmm.ts | 4 +- frontend/app/src/pages/ovens/index.tsx | 2 +- 10 files changed, 238 insertions(+), 34 deletions(-) create mode 100644 frontend/app/src/components/modals/Liquidate.tsx diff --git a/frontend/app/src/api/tzkt.ts b/frontend/app/src/api/tzkt.ts index f2fc2c9c..7bc7fa55 100644 --- a/frontend/app/src/api/tzkt.ts +++ b/frontend/app/src/api/tzkt.ts @@ -50,14 +50,13 @@ export const getAllOvensAPI = async (): Promise => { export const getUserOvenData = async (userAddress: string) => { try { - const userOvenData: any = await get( - `bigmaps/${CTEZ_CONTRACT_BIGMAP}/keys?key.owner=${userAddress}`, - undefined, - userAddress, + const userOvenData: any = await axios.get( + `https://api.granadanet.tzkt.io/v1/bigmaps/59943/keys?key.owner=${userAddress}`, ); let tezInOvens: any = 0; let ctezOutstanding: any = 0; const userOvenDataLength: any = userOvenData.data.length; + for (let i = 0; i < userOvenDataLength; ) { tezInOvens += Number(userOvenData.data[i].value.tez_balance) / 1e6; ctezOutstanding += Number(userOvenData.data[i].value.ctez_outstanding) / 1e6; diff --git a/frontend/app/src/api/user.ts b/frontend/app/src/api/user.ts index 15601800..7948117a 100644 --- a/frontend/app/src/api/user.ts +++ b/frontend/app/src/api/user.ts @@ -30,7 +30,6 @@ export const getUserBalance = async (userAddress: string): Promise const ctez = await getCtezBalance(userAddress); const xtz = await getXtzBalance(userAddress); const { tezInOvens, ctezOutstanding } = await getUserOvenData(userAddress); - console.log(tezInOvens); return { xtz, ctez, diff --git a/frontend/app/src/components/OvenCard/OvenCard.tsx b/frontend/app/src/components/OvenCard/OvenCard.tsx index 5f84217c..24f2cbfd 100644 --- a/frontend/app/src/components/OvenCard/OvenCard.tsx +++ b/frontend/app/src/components/OvenCard/OvenCard.tsx @@ -103,7 +103,7 @@ const OvenCard: React.FC = (props) => { ))} - + Collateral Utilization diff --git a/frontend/app/src/components/OvenCard/OvenStats.tsx b/frontend/app/src/components/OvenCard/OvenStats.tsx index d48b686f..9721b17e 100644 --- a/frontend/app/src/components/OvenCard/OvenStats.tsx +++ b/frontend/app/src/components/OvenCard/OvenStats.tsx @@ -86,7 +86,7 @@ const OvenStats: React.FC<{ oven: AllOvenDatum | null }> = ({ oven }) => { - + Collateral utilization diff --git a/frontend/app/src/components/OvenCard/ProgressPill.tsx b/frontend/app/src/components/OvenCard/ProgressPill.tsx index 9ce0efcc..06eb0f9a 100644 --- a/frontend/app/src/components/OvenCard/ProgressPill.tsx +++ b/frontend/app/src/components/OvenCard/ProgressPill.tsx @@ -1,29 +1,67 @@ -import { Box, Flex, Stack, Text, useColorModeValue, VStack, Wrap } from '@chakra-ui/react'; +import { Box, Flex, Icon, Stack, Text, useColorModeValue, VStack, Wrap } from '@chakra-ui/react'; +import { useMemo, useState } from 'react'; +import { BsArrowRight } from 'react-icons/bs'; +import { AllOvenDatum } from '../../interfaces'; +import LiquidateOven from '../modals/Liquidate'; interface IProgressPill { value: number; + oven: AllOvenDatum | null; } -const ProgressPill: React.FC = ({ value }) => { +const ProgressPill: React.FC = ({ value, oven }) => { const progressPillBg = useColorModeValue('white', 'darkblue'); + const [liquidateOven, setliquidateOven] = useState(false); + + const SetOpen = (v: boolean) => { + setliquidateOven(v); + }; + + const modals = useMemo(() => { + return ( + <> + setliquidateOven(false)} /> + + ); + }, [liquidateOven, setliquidateOven]); + return ( - 80 ? '#F6F5E5AA' : '#E5F6EFAA') : '#FFE3E2AA'} - borderRadius={16} - px={4} - w="100%" - > - - 80 ? '#F3DD63' : '#38CB89') : '#CC3936'} - /> - - {value}% - +
+ 80 ? '#F6F5E5AA' : '#E5F6EFAA') : '#FFE3E2AA'} + borderRadius={16} + px={4} + pb={4} + w="100%" + > + + 80 ? '#F3DD63' : '#38CB89') : '#CC3936'} + /> + + {value}% + {modals} + + {value > 99 && ( + SetOpen(true)} + _hover={{ cursor: 'pointer' }} + > + Liquidate oven + + + )} +
); }; diff --git a/frontend/app/src/components/Trade/Swap/Swap.tsx b/frontend/app/src/components/Trade/Swap/Swap.tsx index 5045b5f0..0b6fd926 100644 --- a/frontend/app/src/components/Trade/Swap/Swap.tsx +++ b/frontend/app/src/components/Trade/Swap/Swap.tsx @@ -107,13 +107,13 @@ const Swap: React.FC = () => { ? await cashToToken({ amount: formData.amount, deadline, - minTokensBought: minBuyValue, + minTokensBought: minReceived, to: formData.to, }) : await tokenToCash( { deadline, - minCashBought: minBuyValue, + minCashBought: minReceived, to: formData.to, tokensSold: formData.amount, }, @@ -147,8 +147,9 @@ const Swap: React.FC = () => { setMinReceived(minRece); } else { setMinBuyValue(0); + setMinReceived(0); } - }, [cfmmStorage, formType, values.amount]); + }, [cfmmStorage, formType, values.amount, slippage]); const { buttonText, errorList } = useMemo(() => { logger.info(errors); @@ -226,7 +227,7 @@ const Swap: React.FC = () => { Min Received - {Number(minReceived).toFixed(6)} ctez + {Number(minReceived).toFixed(6)} {formType === FORM_TYPE.CTEZ_TEZ ? 'tez' : 'ctez'} diff --git a/frontend/app/src/components/input/DepositorsInput.tsx b/frontend/app/src/components/input/DepositorsInput.tsx index 471c1766..83429c61 100644 --- a/frontend/app/src/components/input/DepositorsInput.tsx +++ b/frontend/app/src/components/input/DepositorsInput.tsx @@ -58,7 +58,7 @@ const DepositorsInput: React.FC = (props) => { - Authorised Deposters + Authorized Depositors diff --git a/frontend/app/src/components/modals/Liquidate.tsx b/frontend/app/src/components/modals/Liquidate.tsx new file mode 100644 index 00000000..4d8189f3 --- /dev/null +++ b/frontend/app/src/components/modals/Liquidate.tsx @@ -0,0 +1,167 @@ +import { + FormControl, + FormLabel, + Input, + InputGroup, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + useColorModeValue, + useToast, +} from '@chakra-ui/react'; +import { useHistory } from 'react-router-dom'; +import { useState } from 'react'; + +import { useTranslation } from 'react-i18next'; + +import { validateAddress } from '@taquito/utils'; +import { number, object, string } from 'yup'; +import { useFormik } from 'formik'; +import { BUTTON_TXT, TButtonText, TOKEN, TToken } from '../../constants/swap'; +import { cTezError, liquidate } from '../../contracts/ctez'; +import Button from '../button/Button'; +import { AllOvenDatum } from '../../interfaces'; +import { useTxLoader } from '../../hooks/utilHooks'; +import { useWallet } from '../../wallet/hooks'; + +interface LiquidateForm { + ovenOwner: string; + amount: number; + to: string; +} +interface ILiquidateProps { + isOpen: boolean; + onClose: () => void; + oven: AllOvenDatum | null; +} + +const LiquidateOven: React.FC = ({ isOpen, onClose, oven }) => { + const toast = useToast(); + const [buttonText, setButtonText] = useState(BUTTON_TXT.ENTER_AMT); + const text1 = useColorModeValue('text1', 'darkheading'); + const text2 = useColorModeValue('text2', 'darkheading'); + const text4 = useColorModeValue('text4', 'darkheading'); + const inputbg = useColorModeValue('darkheading', 'textboxbg'); + const handleProcessing = useTxLoader(); + const [{ pkh: userAddress }] = useWallet(); + const history = useHistory(); + + const { t } = useTranslation(['common']); + const initialValues: any = { + ovenOwner: oven?.key.owner ?? '', + amount: '', + to: userAddress ?? '', + }; + + const validationSchema = object().shape({ + amount: number().min(0.000001).required(t('required')), + to: string() + .test({ + test: (value) => validateAddress(value) === 3, + message: t('invalidAddress'), + }) + .required(t('required')), + }); + + const handleFormSubmit = async (data: LiquidateForm) => { + if (oven?.key.id) { + try { + const result = await liquidate( + Number(oven?.key.id), + oven.key.owner, + Number(data.amount), + data.to, + ); + handleProcessing(result); + if (result) { + toast({ + description: t('txSubmitted'), + status: 'success', + }); + } + } catch (error) { + const errorText = cTezError[error.data[1].with.int as number] || t('txFailed'); + toast({ + description: errorText, + status: 'error', + }); + } + } + }; + + const { values, handleChange, handleSubmit } = useFormik({ + initialValues, + validationSchema, + onSubmit: handleFormSubmit, + }); + + return ( + + +
+ + + Liquidate Oven + + + + + + Oven Owner + + + + + + To + + + + + + + + Amount + + + + + + + + + + +
+
+ ); +}; + +export default LiquidateOven; diff --git a/frontend/app/src/contracts/cfmm.ts b/frontend/app/src/contracts/cfmm.ts index 41f29c79..522c536a 100644 --- a/frontend/app/src/contracts/cfmm.ts +++ b/frontend/app/src/contracts/cfmm.ts @@ -138,7 +138,7 @@ export const cashToToken = async (args: CashToTokenParams): Promise { useSetCtezBaseStatsToStore(userAddress); const isMyOven = useMemo(() => { - return location.pathname === '/myovens'; + return location.pathname === '/myovens' || location.pathname === '/myovens/'; }, [location]); const SetSortType = (value: string) => {