-
-
-
-
-
-
-
- Uniswap V3 LP SQTH-ETH Pool
-
-
- Earn LP fees for providing SQTH-ETH liquidity
-
-
-
-
+
+ <>
+
+ Uniswap V3 LP SQTH-ETH Pool
+
+
+ Earn LP fees for providing SQTH-ETH liquidity
+
+ >
+
+
+
+
+
-
+
-
- {lpType === 0 ? (
-
-
- Buy squeeth and LP
-
-
- Earn a payoff similar to ETH1.5
-
-
- Details
-
-
- Buying and LPing gives you a leverage position with a payoff similar to ETH1.5 . You give up
- some of your squeeth upside in exchange for trading fees. You are paying daily premiums for being long
- squeeth, but earning fees from LPing on Uniswap.
-
-
- Payoff
-
-
-
- This payoff diagram does not include premiums or trading fees and assumes implied volatility stays
- constant.{' '}
-
-
- Risks
-
-
- You are exposed to squeeth premiums, so if you hold the position for a long period of time without
- upward price movements in ETH, you can lose considerable funds to premium payments.
-
-
-
- {' '}
- Squeeth smart contracts have been audited by Trail of Bits, Akira, and Sherlock. However, smart
- contracts are experimental technology and we encourage caution only risking funds you can afford to
- lose.
-
-
- ) : (
-
-
- Mint squeeth and LP
-
- Earn yield from trading fees while being long ETH
-
- Details
-
-
- Minting and LPing is similar to a covered call. You start off with a position similar to 1x long ETH
- that gets less long ETH as the price moves up and longer ETH as the price moves down.
-
-
- Payoff
-
-
-
- This payoff diagram does not included premiums or trading fees and assumes implied volatility stays
- constant.{' '}
-
-
- Risks
-
-
- You enter this position neutral to squeeth exposure, but could end up long squeeth exposed to premiums
- or short squeeth depending on ETH price movements. If you fall below the minimum collateralization
- threshold (150%), you are at risk of liquidation.
-
-
-
- {' '}
- Squeeth smart contracts have been audited by Trail of Bits, Akira, and Sherlock. However, smart
- contracts are experimental technology and we encourage caution only risking funds you can afford to
- lose.
-
-
- )}
+
+
+
+
+
+
+
+
+ Details
+
+
+
-
- {supportedNetwork &&
{!isRestricted ? : null}
}
+
+
-
+ >
)
}
export function LPage() {
return (
- //
- //
)
}
diff --git a/packages/frontend/pages/mint.tsx b/packages/frontend/pages/mint.tsx
index c7739931f..1c2327293 100644
--- a/packages/frontend/pages/mint.tsx
+++ b/packages/frontend/pages/mint.tsx
@@ -1,27 +1,23 @@
-import { MintSqueeth } from '@components/Lp/GetSqueeth'
-import Nav from '@components/Nav'
+import React from 'react'
import { Box, Typography } from '@material-ui/core'
import { createStyles, makeStyles } from '@material-ui/core/styles'
-import Link from 'next/link'
-import React from 'react'
-import { useFirstValidVault } from 'src/state/positions/hooks'
+
+import MintSqueeth from '@components/Trade/Mint'
+import Nav from '@components/Nav'
const useStyles = makeStyles((theme) =>
createStyles({
container: {
- padding: theme.spacing(2),
+ padding: theme.spacing(4, 0),
},
title: {
- marginTop: theme.spacing(2),
- color: theme.palette.primary.main,
+ fontSize: '20px',
+ fontWeight: 700,
+ letterSpacing: '-0.01em',
},
getSqueethCard: {
- width: '400px',
- background: theme.palette.background.lightStone,
- borderRadius: theme.spacing(1),
- overflow: 'auto',
+ width: '440px',
margin: 'auto',
- marginTop: theme.spacing(4),
padding: theme.spacing(2, 0),
},
}),
@@ -29,19 +25,21 @@ const useStyles = makeStyles((theme) =>
const MintPage: React.FC = () => {
const classes = useStyles()
- const { vaultId } = useFirstValidVault()
return (
-
+ <>
-
- Mint Squeeth
-
-
- console.log('Minted')} showManageLink />
-
-
+
+
+ Mint Squeeth
+
+
+
+ console.log('Minted')} showManageLink />
+
+
+ >
)
}
diff --git a/packages/frontend/pages/opt-out.tsx b/packages/frontend/pages/opt-out.tsx
index a81fdd9c8..b1342bf37 100644
--- a/packages/frontend/pages/opt-out.tsx
+++ b/packages/frontend/pages/opt-out.tsx
@@ -1,12 +1,11 @@
+import React, { useEffect, useState } from 'react'
+import { Box, Typography } from '@material-ui/core'
+import { createStyles, makeStyles } from '@material-ui/core/styles'
import { setOptOut } from '@amplitude/analytics-browser'
+
import { PrimaryButton } from '@components/Button'
-import { MintSqueeth } from '@components/Lp/GetSqueeth'
import Nav from '@components/Nav'
-import { Box, Typography } from '@material-ui/core'
-import { createStyles, makeStyles } from '@material-ui/core/styles'
import { isOptedOut } from '@utils/amplitude'
-import Link from 'next/link'
-import React, { useEffect, useState } from 'react'
const useStyles = makeStyles((theme) =>
createStyles({
diff --git a/packages/frontend/src/components/InputNew/InputToken.tsx b/packages/frontend/src/components/InputNew/InputToken.tsx
index 5582dfa06..3ed90f38a 100644
--- a/packages/frontend/src/components/InputNew/InputToken.tsx
+++ b/packages/frontend/src/components/InputNew/InputToken.tsx
@@ -24,7 +24,6 @@ const useInputTokenProps = makeStyles((theme) =>
border: `2px solid ${theme.palette.background.lightStone}`,
borderRadius: '10px',
padding: theme.spacing(2),
- marginTop: '1em',
backgroundColor: theme.palette.background.default,
},
inputRoot: {
diff --git a/packages/frontend/src/components/Lp/GetSqueeth.tsx b/packages/frontend/src/components/Lp/GetSqueeth.tsx
index 662a6638a..adbd8bd77 100644
--- a/packages/frontend/src/components/Lp/GetSqueeth.tsx
+++ b/packages/frontend/src/components/Lp/GetSqueeth.tsx
@@ -1,278 +1,23 @@
-import { CircularProgress, InputAdornment, TextField, Typography, Tooltip } from '@material-ui/core'
+import { Typography } from '@material-ui/core'
import { createStyles, makeStyles } from '@material-ui/core/styles'
-import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined'
-import BigNumber from 'bignumber.js'
import { motion } from 'framer-motion'
-import React, { useState } from 'react'
+import React from 'react'
-import { BIG_ZERO, MIN_COLLATERAL_AMOUNT, OSQUEETH_DECIMALS, Tooltips } from '../../constants'
import { LPActions, OBTAIN_METHOD, useLPState } from '@context/lp'
-import { toTokenAmount } from '@utils/calculations'
-import { PrimaryButton } from '../Button'
-import CollatRange from '../CollatRange'
-import { PrimaryInput } from '../Input/PrimaryInput'
-import Long from '@components/TradeOld/Long'
-import TradeDetails from '@components/TradeOld/TradeDetails'
-import TradeInfoItem from '@components/TradeOld/TradeInfoItem'
-import { useVaultManager } from '@hooks/contracts/useVaultManager'
-import { useWalletBalance } from 'src/state/wallet/hooks'
-import { connectedWalletAtom, supportedNetworkAtom } from 'src/state/wallet/atoms'
-import { useAtomValue } from 'jotai'
-import { addressesAtom, existingCollatAtom, existingCollatPercentAtom } from 'src/state/positions/atoms'
-import { useTokenBalance } from '@hooks/contracts/useTokenBalance'
-import { useGetWSqueethPositionValue } from 'src/state/squeethPool/hooks'
-import {
- useGetCollatRatioAndLiqPrice,
- useGetShortAmountFromDebt,
- useOpenDepositAndMint,
-} from 'src/state/controller/hooks'
-import { useFirstValidVault } from 'src/state/positions/hooks'
-import { useVaultData } from '@hooks/useVaultData'
-import { normFactorAtom } from 'src/state/controller/atoms'
-import useAppEffect from '@hooks/useAppEffect'
-import useAppMemo from '@hooks/useAppMemo'
-import Link from 'next/link'
+import Long from '@components/Trade/Long'
+import MintSqueeth from '@components/Trade/Mint'
const useStyles = makeStyles((theme) =>
createStyles({
- container: {
- padding: theme.spacing(2),
- },
- getSqueethCard: {
- width: '400px',
- height: '496px',
- background: theme.palette.background.lightStone,
- margin: theme.spacing(1, 0),
- borderRadius: theme.spacing(1),
- overflow: 'auto',
- },
- thirdHeading: {
- marginTop: theme.spacing(1.5),
- },
- divider: {
- margin: theme.spacing(2, 0),
- width: '300px',
- marginLeft: 'auto',
- marginRight: 'auto',
- },
- amountInput: {
- marginTop: theme.spacing(1),
- backgroundColor: theme.palette.success.main,
- '&:hover': {
- backgroundColor: theme.palette.success.dark,
- },
- },
- hint: {
- display: 'flex',
- alignItems: 'center',
- },
- hintTextContainer: {
- display: 'flex',
- },
- hintTitleText: {
- marginRight: '.5em',
- },
- vaultCollatInfo: {
- display: 'flex',
- alignItems: 'center',
- pointerEvents: 'auto',
- },
- infoIcon: {
- fontSize: '1rem',
- marginLeft: theme.spacing(0.5),
- color: theme.palette.text.secondary,
- },
- link: {
- color: theme.palette.primary.main,
- marginBottom: theme.spacing(1),
- margin: 'auto',
- width: '300px',
- textDecoration: 'underline',
+ title: {
+ textAlign: 'center',
+ fontSize: '18px',
+ fontWeight: 500,
+ marginBottom: theme.spacing(2),
},
}),
)
-type MintProps = {
- onMint: () => void
- showManageLink?: boolean
-}
-
-export const MintSqueeth: React.FC
= ({ onMint, showManageLink }) => {
- const classes = useStyles()
- const { oSqueeth } = useAtomValue(addressesAtom)
- const { value: oSqueethBal } = useTokenBalance(oSqueeth, 15, OSQUEETH_DECIMALS)
- const { data: balance } = useWalletBalance()
- const connected = useAtomValue(connectedWalletAtom)
- const supportedNetwork = useAtomValue(supportedNetworkAtom)
- const { loading: vaultIDLoading } = useVaultManager()
- const getWSqueethPositionValue = useGetWSqueethPositionValue()
- const openDepositAndMint = useOpenDepositAndMint()
- const getShortAmountFromDebt = useGetShortAmountFromDebt()
- const getCollatRatioAndLiqPrice = useGetCollatRatioAndLiqPrice()
- const { validVault: vault, vaultId } = useFirstValidVault()
- const { existingCollat, existingCollatPercent } = useVaultData(vault)
-
- const [mintAmount, setMintAmount] = useState(new BigNumber(0))
- const [collatAmount, setCollatAmount] = useState('0')
- const collatAmountBN = new BigNumber(collatAmount)
- const [collatPercent, setCollatPercent] = useState(200)
- const [loading, setLoading] = useState(false)
- const [mintMinCollatError, setMintMinCollatError] = useState('')
- const [minCollRatioError, setMinCollRatioError] = useState('')
- const [liqPrice, setLiqPrice] = useState(BIG_ZERO)
-
- const mint = async () => {
- setLoading(true)
- try {
- if (vaultIDLoading) return
- await openDepositAndMint(Number(vaultId), mintAmount, collatAmountBN)
- onMint()
- } catch (e) {
- console.log(e)
- }
- setLoading(false)
- }
-
- useAppEffect(() => {
- let isMounted = true
-
- if (collatAmountBN.isNaN() || collatAmountBN.isZero()) {
- //if no collateral is being inputted and user is not trying to only adjust vault collateral
- if (isMounted) setMintAmount(new BigNumber(0))
- return
- }
- const debt = collatAmountBN.times(100).div(collatPercent)
- getShortAmountFromDebt(debt).then((s) => {
- if (isMounted) setMintAmount(s)
- })
- return () => {
- isMounted = false
- }
- }, [collatPercent, collatAmount.toString()])
-
- useAppEffect(() => {
- if (collatPercent < 150) {
- setMinCollRatioError('Minimum collateral ratio is 150%')
- } else {
- setMinCollRatioError('')
- }
-
- if (connected && collatAmountBN.isGreaterThan(balance ?? BIG_ZERO)) {
- setMintMinCollatError('Insufficient ETH balance')
- } else if (connected && collatAmountBN.plus(existingCollat).lt(MIN_COLLATERAL_AMOUNT)) {
- setMintMinCollatError('Minimum collateral is 6.9 ETH')
- }
- }, [balance?.toString(), connected, existingCollat.toString(), collatAmountBN.toString(), collatPercent])
-
- useAppEffect(() => {
- getCollatRatioAndLiqPrice(collatAmountBN, mintAmount).then(({ liquidationPrice }) => {
- setLiqPrice(liquidationPrice)
- })
- }, [collatAmountBN, mintAmount, getCollatRatioAndLiqPrice, vault?.shortAmount])
-
- return (
-
- {vaultId && showManageLink ? (
-
- Manage Vault
-
- ) : null}
-
-
setCollatAmount(v)}
- label="Collateral"
- tooltip={Tooltips.SellOpenAmount}
- actionTxt="Max"
- onActionClicked={() => setCollatAmount(toTokenAmount(balance ?? BIG_ZERO, 18).toString())}
- unit="ETH"
- convertedValue={0.0}
- hint={
- !!mintMinCollatError ? (
- mintMinCollatError
- ) : (
-
-
- Balance {' '}
- {toTokenAmount(balance ?? BIG_ZERO, 18).toFixed(4)}
-
- ETH
-
- )
- }
- error={connected && collatAmountBN.plus(existingCollat).lt(MIN_COLLATERAL_AMOUNT)}
- />
-
- setCollatPercent(Number(event.target.value))}
- id="filled-basic"
- label="Collateral Ratio"
- variant="outlined"
- error={!!minCollRatioError}
- helperText={minCollRatioError}
- InputProps={{
- endAdornment: (
-
- %
-
- ),
- }}
- inputProps={{
- min: '0',
- }}
- />
-
-
- setCollatPercent(val)} collatValue={collatPercent} />
-
-
-
-
-
- {!supportedNetwork ? (
- 'Unsupported Network'
- ) : loading ? (
-
- ) : (
- 'Mint'
- )}
-
-
-
- )
-}
-
const GetSqueeth: React.FC = () => {
const classes = useStyles()
const { lpState, dispatch } = useLPState()
@@ -283,21 +28,12 @@ const GetSqueeth: React.FC = () => {
return (
<>
-
+
{lpState.obtainMethod === OBTAIN_METHOD.BUY ? 'Buy Squeeth to LP' : 'Mint Squeeth to LP'}
-
+
{lpState.obtainMethod === OBTAIN_METHOD.BUY ? (
-
+
) : (
)}
diff --git a/packages/frontend/src/components/Lp/LPPosition.tsx b/packages/frontend/src/components/Lp/LPPosition.tsx
index e7516f784..ece3e14db 100644
--- a/packages/frontend/src/components/Lp/LPPosition.tsx
+++ b/packages/frontend/src/components/Lp/LPPosition.tsx
@@ -1,18 +1,25 @@
+import React from 'react'
+import { Typography, Box } from '@material-ui/core'
import { createStyles, makeStyles } from '@material-ui/core/styles'
import { useAtomValue } from 'jotai'
-import React from 'react'
-import { Typography } from '@material-ui/core'
import Link from 'next/link'
-import { squeethLiquidityAtom, wethLiquidityAtom } from 'src/state/positions/atoms'
-import { useLPPositionsQuery } from 'src/state/positions/hooks'
+import { squeethLiquidityAtom, wethLiquidityAtom } from '@state/positions/atoms'
+import { useLPPositionsQuery } from '@state/positions/hooks'
+import Metric from '@components/Metric'
+import { formatNumber } from '@utils/formatter'
const useStyles = makeStyles((theme) =>
createStyles({
- container: {},
link: {
- marginTop: theme.spacing(2),
color: theme.palette.primary.main,
+ fontWeight: 500,
+ fontSize: '14px',
+ },
+ subtitle: {
+ fontSize: '20px',
+ fontWeight: 700,
+ letterSpacing: '-0.01em',
},
}),
)
@@ -23,29 +30,30 @@ const LPPosition: React.FC = () => {
const wethLiquidity = useAtomValue(wethLiquidityAtom)
const { loading } = useLPPositionsQuery()
- if (loading) return Loading...
+ if (loading) {
+ return {'Fetching LP position...'}
+ }
- if (squeethLiquidity.isZero() && wethLiquidity.isZero())
- return No LP Positions
+ if (squeethLiquidity.isZero() && wethLiquidity.isZero()) {
+ return null
+ }
return (
-
-
- Position
-
-
- Liquidity:
-
- {' ' + squeethLiquidity.toFixed(4)} oSQTH,
+ <>
+
+
+ My Position
-
- {' ' + wethLiquidity.toFixed(4)} WETH
+
+ Sell full position
-
-
- See full position
-
-
+
+
+
+
+
+
+ >
)
}
diff --git a/packages/frontend/src/components/Lp/ObtainSqueeth.tsx b/packages/frontend/src/components/Lp/ObtainSqueeth.tsx
index 16e25657b..c56f68b14 100644
--- a/packages/frontend/src/components/Lp/ObtainSqueeth.tsx
+++ b/packages/frontend/src/components/Lp/ObtainSqueeth.tsx
@@ -10,19 +10,9 @@ import Stepper from './Stepper'
const useStyles = makeStyles(() =>
createStyles({
container: {
- width: '400px',
- },
- title: {
- // display: 'flex',
- // justifyContent: 'center',
- },
- obtainSqueeth: {
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
- width: '100%',
- textAlign: 'center',
- alignItems: 'center',
},
}),
)
@@ -33,12 +23,10 @@ const ObtainSqueeth: React.FC = () => {
return (
-
- {lpState.step === Steps.SELECT_METHOD ?
: null}
- {lpState.step === Steps.GET_SQUEETH ?
: null}
- {lpState.step === Steps.PROVIDE_LIQUIDITY ?
: null}
-
-
+ {lpState.step === Steps.SELECT_METHOD ?
: null}
+ {lpState.step === Steps.GET_SQUEETH ?
: null}
+ {lpState.step === Steps.PROVIDE_LIQUIDITY ?
: null}
+
)
}
diff --git a/packages/frontend/src/components/Lp/ProvideLiquidity.tsx b/packages/frontend/src/components/Lp/ProvideLiquidity.tsx
index 0fc29e34f..95a2aa356 100644
--- a/packages/frontend/src/components/Lp/ProvideLiquidity.tsx
+++ b/packages/frontend/src/components/Lp/ProvideLiquidity.tsx
@@ -7,18 +7,20 @@ import React from 'react'
import { useAtomValue } from 'jotai'
import { UniswapIFrameOpen } from '@constants/enums'
-import { networkIdAtom } from 'src/state/wallet/atoms'
+import { networkIdAtom } from '@state/wallet/atoms'
const useStyles = makeStyles((theme) =>
createStyles({
container: {
- width: '400px',
+ width: '100%',
height: '496px',
- background: theme.palette.background.lightStone,
- margin: theme.spacing(1, 0),
- borderRadius: theme.spacing(1),
overflow: 'auto',
- padding: theme.spacing(1),
+ },
+ title: {
+ textAlign: 'center',
+ fontSize: '18px',
+ fontWeight: 500,
+ marginBottom: theme.spacing(2),
},
iframeBox: {
width: '100%',
@@ -36,8 +38,7 @@ const useStyles = makeStyles((theme) =>
},
headerDiv: {
display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
+ flexDirection: 'column',
padding: theme.spacing(0, 1),
},
uniOpenBtn: {
@@ -54,9 +55,8 @@ const ProvideLiquidity: React.FC = () => {
return (
<>
-
- Provide Liquidity
-
+ Provide Liquidity
+
diff --git a/packages/frontend/src/components/Lp/SelectMethod.tsx b/packages/frontend/src/components/Lp/SelectMethod.tsx
index 4695739cb..ca508f1a9 100644
--- a/packages/frontend/src/components/Lp/SelectMethod.tsx
+++ b/packages/frontend/src/components/Lp/SelectMethod.tsx
@@ -1,4 +1,4 @@
-import { Typography } from '@material-ui/core'
+import { Typography, Box } from '@material-ui/core'
import { createStyles, makeStyles } from '@material-ui/core/styles'
import { motion } from 'framer-motion'
import Image from 'next/image'
@@ -10,16 +10,25 @@ import { LPActions, OBTAIN_METHOD, useLPState } from '@context/lp'
const useStyles = makeStyles((theme) =>
createStyles({
- container: {
- padding: theme.spacing(2),
+ title: {
+ textAlign: 'center',
+ fontSize: '18px',
+ fontWeight: 500,
+ marginBottom: theme.spacing(2),
+ },
+ obtainItemContainer: {
+ display: 'flex',
+ flexDirection: 'column',
+ gap: '12px',
},
obtainItem: {
- width: '400px',
- height: '240px',
- background: theme.palette.background.lightStone,
- margin: theme.spacing(1, 0),
+ display: 'flex',
+ alignItems: 'center',
+ gap: '12px',
+
+ background: theme.palette.background.stone,
borderRadius: theme.spacing(1),
- padding: theme.spacing(2),
+ padding: theme.spacing(4, 2),
cursor: 'pointer',
border: `1px solid ${theme.palette.background.lightStone}`,
// boxShadow: `${theme.palette.primary.main} 1px 5px 47px 5px`,
@@ -28,16 +37,15 @@ const useStyles = makeStyles((theme) =>
},
},
obtainItemTitle: {
- marginBottom: theme.spacing(3),
- // fontWeight: 500,
- // fontSize: 18,
- },
- obtainItemImg: {
- marginTop: theme.spacing(4),
+ color: 'rgba(255, 255, 255)',
+ fontSize: '20px',
+ fontWeight: 500,
},
+
obtainItemDetail: {
- marginTop: theme.spacing(3),
- color: theme.palette.text.secondary,
+ color: 'rgba(255, 255, 255, 0.5)',
+ fontSize: '15px',
+ fontWeight: 500,
},
}),
)
@@ -48,35 +56,39 @@ const SelectMethod: React.FC = () => {
return (
<>
-
- Obtain Squeeth
-
- dispatch({ type: LPActions.SELECT_METHOD, payload: OBTAIN_METHOD.MINT })}
- >
-
- Mint Squeeth to LP
-
-
- Mint Squeeth by depositing ETH as collateral
-
- dispatch({ type: LPActions.SELECT_METHOD, payload: OBTAIN_METHOD.BUY })}
- >
-
- Buy Squeeth to LP
-
-
- Buy Squeeth directly from Uniswap
-
+ Obtain Squeeth
+
+ dispatch({ type: LPActions.SELECT_METHOD, payload: OBTAIN_METHOD.MINT })}
+ >
+
+
+
+ Mint Squeeth to LP
+
+ Mint by depositing ETH as collateral
+
+
+ dispatch({ type: LPActions.SELECT_METHOD, payload: OBTAIN_METHOD.BUY })}
+ >
+
+
+
+ Buy Squeeth to LP
+
+ Buy directly from Uniswap
+
+
+
>
)
}
diff --git a/packages/frontend/src/components/Lp/SqueethInfo.tsx b/packages/frontend/src/components/Lp/SqueethInfo.tsx
index 1bd831986..7f0e8f491 100644
--- a/packages/frontend/src/components/Lp/SqueethInfo.tsx
+++ b/packages/frontend/src/components/Lp/SqueethInfo.tsx
@@ -1,146 +1,75 @@
-import { Tooltip, Typography } from '@material-ui/core'
-import { createStyles, makeStyles } from '@material-ui/core/styles'
-import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'
-import InfoIcon from '@material-ui/icons/InfoOutlined'
+import { Box, BoxProps } from '@material-ui/core'
import React from 'react'
import { useAtomValue } from 'jotai'
import { Tooltips } from '@constants/enums'
+import { BIG_ZERO } from '@constants/index'
import { toTokenAmount } from '@utils/calculations'
-import LPPosition from './LPPosition'
-import { addressAtom } from '../../state/wallet/atoms'
-import { useGetWSqueethPositionValue, useGetWSqueethPositionValueInETH } from 'src/state/squeethPool/hooks'
-import { impliedVolAtom, indexAtom, markAtom } from 'src/state/controller/atoms'
+import {
+ impliedVolAtom,
+ indexAtom,
+ markAtom,
+ osqthRefVolAtom,
+ currentImpliedFundingAtom,
+} from '@state/controller/atoms'
+import Metric, { MetricLabel } from '@components/Metric'
+import { formatCurrency, formatNumber } from '@utils/formatter'
+import { useOSQTHPrice } from '@hooks/useOSQTHPrice'
-const useStyles = makeStyles((theme) =>
- createStyles({
- squeethInfo: {
- [theme.breakpoints.down('sm')]: {
- width: '100%',
- },
- marginTop: theme.spacing(2),
- display: 'flex',
- },
- squeethInfoSubGroup: {
- display: 'flex',
- alignItems: 'center',
- },
- infoItem: {
- marginRight: theme.spacing(1),
- paddingRight: theme.spacing(1.5),
- },
- infoLabel: {
- display: 'flex',
- alignItems: 'center',
- },
- infoIcon: {
- fontSize: '14px',
- marginLeft: theme.spacing(0.5),
- },
- positionCard: {
- background: theme.palette.background.stone,
- borderRadius: theme.spacing(1),
- width: '370px',
- padding: theme.spacing(2),
- },
- }),
-)
-
-const SqueethInfo: React.FC = () => {
- const classes = useStyles()
+const SqueethInfo: React.FC = (props) => {
const mark = useAtomValue(markAtom)
const index = useAtomValue(indexAtom)
const impliedVol = useAtomValue(impliedVolAtom)
- const getWSqueethPositionValue = useGetWSqueethPositionValue()
- const getWSqueethPositionValueInETH = useGetWSqueethPositionValueInETH()
- const address = useAtomValue(addressAtom)
+ const osqthRefVol = useAtomValue(osqthRefVolAtom)
+ const currentImpliedFunding = useAtomValue(currentImpliedFundingAtom)
+ const { data: osqthPrice } = useOSQTHPrice()
+
+ const eth2Price = toTokenAmount(index, 18)
+ const ethPrice = eth2Price.sqrt()
+ const markPrice = toTokenAmount(mark, 18)
+ const impliedVolPercent = impliedVol * 100
+ const currentImpliedPremium =
+ currentImpliedFunding === 0 ? 'loading' : formatNumber(currentImpliedFunding * 100) + '%'
+
+ const osqthPriceInETH = ethPrice.isZero() ? BIG_ZERO : osqthPrice.div(ethPrice)
return (
-
-
-
- {/* hard coded width layout to align with the next line */}
-
-
-
- ETH Price
-
-
-
-
-
+
+ }
+ value={formatCurrency(ethPrice.toNumber())}
+ />
+
+ }
+ value={formatCurrency(eth2Price.toNumber())}
+ />
+
+ }
+ value={formatCurrency(markPrice.toNumber())}
+ />
+
+ }
+ value={`${formatCurrency(osqthPrice.toNumber())} (${formatNumber(osqthPriceInETH.toNumber(), 4)} ETH)`}
+ />
+
+ }
+ value={`${formatNumber(impliedVolPercent)}%`}
+ />
- ${Number(toTokenAmount(index, 18).sqrt()).toFixed(2).toLocaleString()}
-
-
-
-
- ETH² Price
-
-
-
-
-
-
${Number(toTokenAmount(index, 18).toFixed(0)).toLocaleString()}
-
-
-
-
- Mark Price
-
-
-
-
-
-
${Number(toTokenAmount(mark, 18).toFixed(0)).toLocaleString()}
-
-
-
-
-
-
- oSQTH Price
-
-
-
-
-
-
- {getWSqueethPositionValue(1) && getWSqueethPositionValueInETH(1)
- ? '$' +
- Number(getWSqueethPositionValue(1).toFixed(2).toLocaleString()) +
- '\xa0 ' +
- Number(getWSqueethPositionValueInETH(1).toFixed(4).toLocaleString()) +
- ' ETH'
- : 'loading'}
-
-
-
-
-
- Implied Volatility
-
-
-
-
-
-
{(impliedVol * 100).toFixed(2)}%
-
+
}
+ value={`${formatNumber(osqthRefVol)}%`}
+ />
- {/*
-
-
- Pool TVL
-
-
-
{tvl || 'loading'}%
-
*/}
-
-
-
- {address ? : 'Connect wallet'}
-
-
+ }
+ value={currentImpliedPremium}
+ />
+
)
}
diff --git a/packages/frontend/src/components/Lp/Stepper.tsx b/packages/frontend/src/components/Lp/Stepper.tsx
index ca893a07e..38b65d263 100644
--- a/packages/frontend/src/components/Lp/Stepper.tsx
+++ b/packages/frontend/src/components/Lp/Stepper.tsx
@@ -11,10 +11,12 @@ const useStyles = makeStyles((theme) =>
container: {
display: 'flex',
alignItems: 'center',
- marginTop: theme.spacing(0.5),
+ justifyContent: 'center',
+ marginTop: theme.spacing(3),
},
stepData: {
marginLeft: theme.spacing(1),
+ fontFamily: 'DM Mono',
},
stepButton: {
margin: theme.spacing(0, 0.5),
@@ -32,10 +34,10 @@ const useStyles = makeStyles((theme) =>
const StepperIconButton = withStyles((theme) => ({
root: {
- background: theme.palette.background.lightStone,
+ background: theme.palette.background.stone,
},
disabled: {
- background: theme.palette.background.lightStone,
+ background: theme.palette.background.stone,
opacity: '1',
},
}))(IconButton)
diff --git a/packages/frontend/src/components/Strategies/Bull/BullTrade/Deposit.tsx b/packages/frontend/src/components/Strategies/Bull/BullTrade/Deposit.tsx
index 56e91f6c8..54b082471 100644
--- a/packages/frontend/src/components/Strategies/Bull/BullTrade/Deposit.tsx
+++ b/packages/frontend/src/components/Strategies/Bull/BullTrade/Deposit.tsx
@@ -232,7 +232,7 @@ const BullDeposit: React.FC<{ onTxnConfirm: (txn: BullTransactionConfirmation) =
<>
- Strategy deposit
+ Strategy Deposit
diff --git a/packages/frontend/src/components/Strategies/Bull/BullTrade/Withdraw.tsx b/packages/frontend/src/components/Strategies/Bull/BullTrade/Withdraw.tsx
index d7e2c230f..86f8218c5 100644
--- a/packages/frontend/src/components/Strategies/Bull/BullTrade/Withdraw.tsx
+++ b/packages/frontend/src/components/Strategies/Bull/BullTrade/Withdraw.tsx
@@ -223,7 +223,7 @@ const BullWithdraw: React.FC<{ onTxnConfirm: (txn: BullTransactionConfirmation)
<>
- Strategy withdraw
+ Strategy Withdraw
diff --git a/packages/frontend/src/components/Strategies/Bull/BullTrade/styles.ts b/packages/frontend/src/components/Strategies/Bull/BullTrade/styles.ts
index 9a1830a0c..2d5233c1d 100644
--- a/packages/frontend/src/components/Strategies/Bull/BullTrade/styles.ts
+++ b/packages/frontend/src/components/Strategies/Bull/BullTrade/styles.ts
@@ -8,6 +8,7 @@ export const useZenBullStyles = makeStyles((theme) =>
tradeContainer: {
display: 'flex',
flexDirection: 'column',
+ marginTop: theme.spacing(2),
},
tabBackGround: {
position: 'sticky',
diff --git a/packages/frontend/src/components/Strategies/Crab/CrabTradeV2/styles.ts b/packages/frontend/src/components/Strategies/Crab/CrabTradeV2/styles.ts
index c3d439f82..d790c3ed8 100644
--- a/packages/frontend/src/components/Strategies/Crab/CrabTradeV2/styles.ts
+++ b/packages/frontend/src/components/Strategies/Crab/CrabTradeV2/styles.ts
@@ -8,7 +8,7 @@ export const useStyles = makeStyles((theme) =>
tradeContainer: {
display: 'flex',
flexDirection: 'column',
- marginTop: '12px',
+ marginTop: theme.spacing(3),
},
notice: {
marginTop: theme.spacing(2.5),
diff --git a/packages/frontend/src/components/Trade/Long/index.tsx b/packages/frontend/src/components/Trade/Long/index.tsx
index 3438f8963..19bf1733a 100644
--- a/packages/frontend/src/components/Trade/Long/index.tsx
+++ b/packages/frontend/src/components/Trade/Long/index.tsx
@@ -57,10 +57,17 @@ const useStyles = makeStyles((theme) =>
header: {
color: theme.palette.primary.main,
},
- subtitle: {
+ title: {
fontSize: '20px',
fontWeight: 700,
letterSpacing: '-0.01em',
+ marginBottom: '24px',
+ },
+ sectionTitle: {
+ fontSize: '20px',
+ fontWeight: 700,
+ letterSpacing: '-0.01em',
+ marginBottom: '16px',
},
body: {
padding: theme.spacing(2, 12),
@@ -286,7 +293,7 @@ const Label: React.FC<{ label: string; tooltipTitle: string }> = ({ label, toolt
const FUNDING_MOVE_THRESHOLD = 1.3
-const OpenLong: React.FC = ({ activeStep = 0 }) => {
+const OpenLong: React.FC = ({ activeStep = 0, showTitle }) => {
const [buyLoading, setBuyLoading] = useState(false)
const getBuyQuoteForETH = useGetBuyQuoteForETH()
@@ -501,12 +508,14 @@ const OpenLong: React.FC = ({ activeStep = 0 }) => {
) : (
{activeStep === 0 ? (
-
-
- Pay ETH to buy oSQTH
-
+ <>
+ {showTitle && (
+
+ Pay ETH to buy oSQTH
+
+ )}
-
+
= ({ activeStep = 0 }) => {
-
+
Projection
-
+
}
value={loadingOSQTHPrice ? 'loading...' : formatCurrency(Number(squeethExposure * 0.25))}
@@ -644,7 +653,7 @@ const OpenLong: React.FC = ({ activeStep = 0 }) => {
)}
-
+ >
) : (
@@ -876,12 +885,12 @@ const CloseLong: React.FC = () => {
>
) : (
-
-
+ <>
+
Sell oSQTH to get ETH back
-
+
= () => {
)}
-
+ >
)}
)
@@ -1015,13 +1024,14 @@ type BuyProps = {
open?: boolean
isLPage?: boolean
activeStep?: number
+ showTitle?: boolean
}
-const Long: React.FC = ({ open, isLPage = false, activeStep = 0 }) => {
+const Long: React.FC = ({ open, isLPage = false, activeStep = 0, showTitle = true }) => {
return open ? (
-
+
) : (
-
+
)
}
diff --git a/packages/frontend/src/components/Trade/Mint.tsx b/packages/frontend/src/components/Trade/Mint.tsx
new file mode 100644
index 000000000..671274cf2
--- /dev/null
+++ b/packages/frontend/src/components/Trade/Mint.tsx
@@ -0,0 +1,314 @@
+import { CircularProgress, InputAdornment, Typography, Box, Collapse } from '@material-ui/core'
+import { createStyles, makeStyles } from '@material-ui/core/styles'
+import BigNumber from 'bignumber.js'
+import React, { useState, useEffect, useMemo } from 'react'
+import { useAtomValue } from 'jotai'
+import Link from 'next/link'
+
+import {
+ BIG_ZERO,
+ MIN_COLLATERAL_AMOUNT,
+ OSQUEETH_DECIMALS,
+ Tooltips,
+ DEFAULT_COLLATERAL_RATIO,
+} from '@constants/index'
+import { toTokenAmount } from '@utils/calculations'
+import { PrimaryButtonNew } from '@components/Button'
+import { InputToken, InputNumber } from '@components/InputNew'
+import CollatRatioSlider from '@components/CollatRatioSlider'
+import { useVaultManager } from '@hooks/contracts/useVaultManager'
+import { useWalletBalance, useSelectWallet } from '@state/wallet/hooks'
+import { connectedWalletAtom, supportedNetworkAtom } from '@state/wallet/atoms'
+import { addressesAtom } from '@state/positions/atoms'
+import { useTokenBalance } from '@hooks/contracts/useTokenBalance'
+import { useGetCollatRatioAndLiqPrice, useGetShortAmountFromDebt, useOpenDepositAndMint } from '@state/controller/hooks'
+import { useFirstValidVault } from '@state/positions/hooks'
+import { useVaultData } from '@hooks/useVaultData'
+import useAppEffect from '@hooks/useAppEffect'
+import { useETHPrice } from '@hooks/useETHPrice'
+import ethLogo from 'public/images/eth-logo.svg'
+import osqthLogo from 'public/images/osqth-logo.svg'
+import Alert from '@components/Alert'
+import Checkbox from '@components/Checkbox'
+import useAppCallback from '@hooks/useAppCallback'
+import { useOSQTHPrice } from '@hooks/useOSQTHPrice'
+import Metric, { MetricLabel } from '@components/Metric'
+import { formatNumber, formatCurrency } from '@utils/formatter'
+import RestrictionInfo from '@components/RestrictionInfo'
+import { useRestrictUser } from '@context/restrict-user'
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ link: {
+ color: theme.palette.primary.main,
+ marginBottom: theme.spacing(2),
+ textDecoration: 'underline',
+ },
+ label: {
+ fontSize: '18px',
+ fontWeight: 700,
+ },
+ }),
+)
+
+interface MintProps {
+ onMint: () => void
+ showManageLink?: boolean
+}
+
+const MintSqueeth: React.FC = ({ onMint, showManageLink }) => {
+ const classes = useStyles()
+ const { oSqueeth } = useAtomValue(addressesAtom)
+ const { value: oSqueethBal } = useTokenBalance(oSqueeth, 15, OSQUEETH_DECIMALS)
+ const { data } = useWalletBalance()
+ const connected = useAtomValue(connectedWalletAtom)
+ const supportedNetwork = useAtomValue(supportedNetworkAtom)
+ const { loading: vaultIDLoading } = useVaultManager()
+ const openDepositAndMint = useOpenDepositAndMint()
+ const getShortAmountFromDebt = useGetShortAmountFromDebt()
+ const getCollatRatioAndLiqPrice = useGetCollatRatioAndLiqPrice()
+ const { validVault: vault, vaultId } = useFirstValidVault()
+ const { existingCollat, existingCollatPercent } = useVaultData(vault)
+ const ethPrice = useETHPrice()
+ const { data: osqthPrice } = useOSQTHPrice()
+ const { isRestricted } = useRestrictUser()
+ const selectWallet = useSelectWallet()
+
+ const [mintAmount, setMintAmount] = useState(new BigNumber(0))
+ const [collatAmount, setCollatAmount] = useState('0')
+ const collatAmountBN = useMemo(() => new BigNumber(collatAmount), [collatAmount])
+ const [collatPercent, setCollatPercent] = useState(200)
+ const [loading, setLoading] = useState(false)
+ const [mintMinCollatError, setMintMinCollatError] = useState('')
+ const [minCollRatioError, setMinCollRatioError] = useState('')
+ const [liqPrice, setLiqPrice] = useState(BIG_ZERO)
+ const [usingDefaultCollatRatio, setUsingDefaultCollatRatio] = useState(true)
+
+ const balance = toTokenAmount(data ?? BIG_ZERO, 18)
+
+ const mint = async () => {
+ setLoading(true)
+ try {
+ if (vaultIDLoading) return
+ await openDepositAndMint(Number(vaultId), mintAmount, collatAmountBN)
+ onMint()
+ } catch (e) {
+ console.log(e)
+ }
+ setLoading(false)
+ }
+
+ useAppEffect(() => {
+ let isMounted = true
+
+ if (collatAmountBN.isNaN() || collatAmountBN.isZero()) {
+ //if no collateral is being inputted and user is not trying to only adjust vault collateral
+ if (isMounted) setMintAmount(new BigNumber(0))
+ return
+ }
+ const debt = collatAmountBN.times(100).div(collatPercent)
+ getShortAmountFromDebt(debt).then((s) => {
+ if (isMounted) setMintAmount(s)
+ })
+ return () => {
+ isMounted = false
+ }
+ }, [collatPercent, collatAmountBN.toString()])
+
+ useAppEffect(() => {
+ if (collatPercent < 150) {
+ setMinCollRatioError('Minimum collateral ratio is 150%')
+ } else {
+ setMinCollRatioError('')
+ }
+
+ if (connected && collatAmountBN.isGreaterThan(balance)) {
+ setMintMinCollatError('Insufficient ETH balance')
+ } else if (connected && collatAmountBN.plus(existingCollat).lt(MIN_COLLATERAL_AMOUNT)) {
+ setMintMinCollatError('Minimum collateral is 6.9 ETH')
+ }
+ }, [balance.toString(), connected, existingCollat.toString(), collatAmountBN.toString(), collatPercent])
+
+ const handleDefaultCollatRatioToggle = useAppCallback(
+ (value: boolean) => {
+ if (value) {
+ setCollatPercent(DEFAULT_COLLATERAL_RATIO)
+ }
+ setUsingDefaultCollatRatio(value)
+ },
+ [setCollatPercent],
+ )
+
+ useEffect(() => {
+ if (collatPercent !== DEFAULT_COLLATERAL_RATIO) {
+ setUsingDefaultCollatRatio(false)
+ }
+ }, [collatPercent])
+
+ useAppEffect(() => {
+ getCollatRatioAndLiqPrice(collatAmountBN, mintAmount).then(({ liquidationPrice }) => {
+ setLiqPrice(liquidationPrice)
+ })
+ }, [collatAmountBN, mintAmount, getCollatRatioAndLiqPrice, vault?.shortAmount])
+
+ const error = mintMinCollatError ? mintMinCollatError : minCollRatioError ? minCollRatioError : ''
+
+ return (
+
+ {vaultId && showManageLink ? (
+
+ Manage Vault
+
+ ) : null}
+
+
+ setCollatAmount(v)}
+ symbol="ETH"
+ logo={ethLogo}
+ balance={balance}
+ usdPrice={ethPrice}
+ onBalanceClick={() => setCollatAmount(balance.toString())}
+ error={!!mintMinCollatError}
+ helperText={mintMinCollatError}
+ />
+
+
+
+
+ Collateral ratio
+
+
+
+
+
+ setCollatPercent(Number(value))}
+ InputProps={{
+ endAdornment: (
+
+ %
+
+ ),
+ }}
+ style={{ width: '80px' }}
+ />
+
+
+
+
+ setCollatPercent(value)}
+ minCollatRatio={150}
+ />
+
+
+
+
+ You will get liquidated.
+
+
+ 150 && collatPercent < 200}>
+
+ Collateral ratio is too low. You will get liquidated at 150%.
+
+
+
+ = 200 && collatPercent < 225}>
+
+ Collateral ratio is risky.
+
+
+
+
+
+
+
+
+
+
+
+ {error}
+
+
+
+
+
+ }
+ value={formatCurrency(liqPrice.toNumber())}
+ isSmall
+ />
+ }
+ value={formatNumber(existingCollatPercent) + '%'}
+ isSmall
+ />
+
+
+ {isRestricted &&
}
+
+
+ {isRestricted ? (
+
+ {'Unavailable'}
+
+ ) : !connected ? (
+
+ {'Connect Wallet'}
+
+ ) : (
+
+ {!supportedNetwork ? (
+ 'Unsupported Network'
+ ) : loading ? (
+
+ ) : (
+ 'Mint'
+ )}
+
+ )}
+
+
+ )
+}
+
+export default MintSqueeth
diff --git a/packages/frontend/src/components/Trade/Short/index.tsx b/packages/frontend/src/components/Trade/Short/index.tsx
index 54c086ceb..83d6ba51e 100644
--- a/packages/frontend/src/components/Trade/Short/index.tsx
+++ b/packages/frontend/src/components/Trade/Short/index.tsx
@@ -23,7 +23,7 @@ import { InputToken, InputNumber } from '@components/InputNew'
import Alert from '@components/Alert'
import { TradeSettings } from '@components/TradeSettings'
import Confirmed, { ConfirmType } from '@components/Trade/Confirmed'
-import { BIG_ZERO, MIN_COLLATERAL_AMOUNT } from '@constants/index'
+import { BIG_ZERO, MIN_COLLATERAL_AMOUNT, DEFAULT_COLLATERAL_RATIO } from '@constants/index'
import { connectedWalletAtom, isTransactionFirstStepAtom, supportedNetworkAtom } from '@state/wallet/atoms'
import { useSelectWallet, useTransactionStatus, useWalletBalance } from '@state/wallet/hooks'
import { addressesAtom, isLongAtom, vaultHistoryUpdatingAtom } from '@state/positions/atoms'
@@ -66,14 +66,13 @@ import { formatNumber, formatCurrency } from '@utils/formatter'
import RestrictionInfo from '@components/RestrictionInfo'
import { useRestrictUser } from '@context/restrict-user'
-const DEFAULT_COLLATERAL_RATIO = 225
-
const useStyles = makeStyles((theme) =>
createStyles({
- subtitle: {
+ title: {
fontSize: '20px',
fontWeight: 700,
letterSpacing: '-0.01em',
+ marginBottom: '24px',
},
label: {
fontSize: '18px',
@@ -509,145 +508,144 @@ const OpenShort: React.FC = ({ open }) => {