Skip to content

Commit

Permalink
feat: collateral adjustment form
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelxuwu authored Feb 21, 2023
1 parent 9a8e1db commit 98f4318
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 11 deletions.
8 changes: 8 additions & 0 deletions app/craco.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ module.exports = {
new BundleAnalyzerPlugin({ analyzerMode: process.env.REACT_APP_INTERACTIVE_ANALYZE ? 'server' : 'json' })
)
}
if (process.env.NODE_ENV !== 'production') {
webpackConfig.devtool = 'eval-cheap-module-source-map'
webpackConfig.ignoreWarnings = [
{
message: /Failed to parse source map/,
},
]
}
webpackConfig.plugins.push(
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
Expand Down
29 changes: 22 additions & 7 deletions app/src/components/position/PositionCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React, { useState } from 'react'
import PositionStatusText from '@/app/components/common/PositionStatusText'
import { UNIT, ZERO_BN } from '@/app/constants/bn'
import ShortYieldValue from '@/app/containers/common/ShortYieldValue'
import TradeCollateralFormModal from '@/app/containers/trade/TradeCollateralFormModal'
import TradeFormModal from '@/app/containers/trade/TradeFormModal'
import useWallet from '@/app/hooks/account/useWallet'

Expand All @@ -31,7 +32,8 @@ const PositionCard = ({ position, option }: Props): JSX.Element | null => {
const equity = position.isLong ? currentPrice.mul(size).div(UNIT) : position?.collateral?.value ?? ZERO_BN

const [isBuy, setIsBuy] = useState(false)
const [isOpen, setIsOpen] = useState(false)
const [isTradeFormOpen, setIsTradeFormOpen] = useState(false)
const [isCollateralFormOpen, setIsCollateralFormOpen] = useState(false)

const { account, isOverride } = useWallet()
const isOwner = account === position.owner && !isOverride
Expand Down Expand Up @@ -85,30 +87,43 @@ const PositionCard = ({ position, option }: Props): JSX.Element | null => {
label="Open Position"
onClick={() => {
setIsBuy(position.isLong)
setIsOpen(true)
setIsTradeFormOpen(true)
}}
/>
<Button
variant="error"
isOutline
size="lg"
isOutline
label="Close Position"
onClick={() => {
setIsBuy(!position.isLong)
setIsOpen(true)
setIsTradeFormOpen(true)
}}
/>
<Button
variant="default"
size="lg"
label="Adjust Collateral"
onClick={() => setIsCollateralFormOpen(true)}
/>
</Grid>
) : null}
</CardBody>
<TradeFormModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
onTrade={() => setIsOpen(false)}
isOpen={isTradeFormOpen}
onClose={() => setIsTradeFormOpen(false)}
onTrade={() => setIsTradeFormOpen(false)}
isBuy={isBuy}
position={position}
option={option}
/>
<TradeCollateralFormModal
isOpen={isCollateralFormOpen}
onClose={() => setIsCollateralFormOpen(false)}
onTrade={() => setIsCollateralFormOpen(false)}
position={position}
option={option}
/>
</Card>
)
}
Expand Down
161 changes: 161 additions & 0 deletions app/src/containers/trade/TradeCollateralFormModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { BigNumber } from '@ethersproject/bignumber'
import Button from '@lyra/ui/components/Button'
import CardSection from '@lyra/ui/components/Card/CardSection'
import CardSeparator from '@lyra/ui/components/Card/CardSeparator'
import Center from '@lyra/ui/components/Center'
import Modal from '@lyra/ui/components/Modal'
import Spinner from '@lyra/ui/components/Spinner'
import Text from '@lyra/ui/components/Text'
import formatBalance from '@lyra/ui/utils/formatBalance'
import { Position } from '@lyrafinance/lyra-js'
import { Market, Option } from '@lyrafinance/lyra-js'
import React, { useCallback, useState } from 'react'

import AmountUpdateText from '@/app/components/common/AmountUpdateText'
import RowItem from '@/app/components/common/RowItem'
import { ZERO_BN } from '@/app/constants/bn'
import { MIN_TRADE_CARD_HEIGHT } from '@/app/constants/layout'
import withSuspense from '@/app/hooks/data/withSuspense'
import useTradeBalances from '@/app/hooks/market/useTradeBalances'
import useTradeSync from '@/app/hooks/market/useTradeSync'
import fromBigNumber from '@/app/utils/fromBigNumber'
import getSoftMaxCollateral from '@/app/utils/getSoftMaxCollateral'
import getSoftMinCollateral from '@/app/utils/getSoftMinCollateral'

import TradeFormButton from '../TradeForm/TradeFormButton'
import TradeFormCollateralSection from '../TradeForm/TradeFormCollateralSection'

// TODO: @dappbeast make slippage configurable
const SLIPPAGE = 0.5 / 100 // 0.5%

type Props = {
isOpen: boolean
onClose: () => void
onTrade?: (market: Market, positionId: number) => void
option: Option
position: Position
}

const TradeCollateralFormModal = withSuspense(({ isOpen, onClose, onTrade, option, position }: Props) => {
const market = option.market()
// TODO: @dappbeast parallelize requests
const balances = useTradeBalances(market)
const quoteBalance = balances.quoteAsset
const baseBalance = balances.baseAsset
const isBaseCollateral = position.collateral?.isBase
const defaultCollateralAmount = position.collateral?.amount ?? ZERO_BN
const [collateralAmount, setCollateralAmount] = useState<BigNumber>(defaultCollateralAmount)

// Reset to default collateral
const resetCollateralAmount = useCallback(() => {
setCollateralAmount(defaultCollateralAmount) // Triggers default fallback
}, [defaultCollateralAmount])

const handleTrade = useCallback(
(market: Market, positionId: number) => {
resetCollateralAmount()
if (onTrade) {
onTrade(market, positionId)
}
},
[onTrade, resetCollateralAmount]
)

const trade = useTradeSync({
option,
position,
balances,
isBuy: true,
size: ZERO_BN,
setToCollateral: collateralAmount,
isBaseCollateral,
slippage: SLIPPAGE,
})

if (!trade.collateral) {
return null
}

const max = getSoftMaxCollateral(trade, trade.collateral)
const min = getSoftMinCollateral(trade.collateral)
const isRange = !min.gte(max)

return (
<Modal isMobileFullscreen title="Adjust Collateral" isOpen={isOpen} onClose={onClose}>
{isRange ? (
<>
<TradeFormCollateralSection
trade={trade}
collateral={trade.collateral}
collateralAmount={collateralAmount}
onChangeCollateralAmount={setCollateralAmount}
/>
<CardSeparator />
<CardSection>
<RowItem
mb={5}
label="Balance"
value={
<AmountUpdateText
variant="secondary"
prevAmount={
isBaseCollateral
? fromBigNumber(baseBalance.balance, baseBalance.decimals)
: fromBigNumber(quoteBalance.balance, quoteBalance.decimals)
}
newAmount={
isBaseCollateral
? fromBigNumber(
baseBalance.balance.sub(trade.baseToken.transfer).add(trade.baseToken.receive),
baseBalance.decimals
)
: fromBigNumber(
quoteBalance.balance.sub(trade.quoteToken.transfer).add(trade.quoteToken.receive),
quoteBalance.decimals
)
}
isUSDFormat={!isBaseCollateral}
symbol={isBaseCollateral ? trade.baseToken.symbol : trade.quoteToken.symbol}
/>
}
valueColor="text"
textVariant="secondary"
/>
<TradeFormButton mt={3} width="100%" trade={trade} onTrade={handleTrade} />
</CardSection>
</>
) : (
<>
<CardSection>
<RowItem
label="Collateral"
value={formatBalance(
collateralAmount,
isBaseCollateral ? trade.baseToken.symbol : trade.quoteToken.symbol,
{
showDollars: !isBaseCollateral,
}
)}
></RowItem>
</CardSection>
<CardSeparator />
<CardSection>
<Text variant="secondary" color="secondaryText">
This position is too small and has fixed collateral requirements that can't be adjusted.
</Text>
<Button mt={6} size="lg" label="Close" onClick={() => onClose()} />
</CardSection>
</>
)}
</Modal>
)
})
;() => (
<CardSection height={MIN_TRADE_CARD_HEIGHT}>
<Center width="100%" flexGrow={1}>
<Spinner />
</Center>
</CardSection>
)

export default TradeCollateralFormModal
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Props = {
collateral: TradeCollateral
collateralAmount: BigNumber
onChangeCollateralAmount: (size: BigNumber) => void
onToggleCoveredCall: (isCoveredCall: boolean) => void
onToggleCoveredCall?: (isCoveredCall: boolean) => void
} & MarginProps

const NUM_STEPS = 200
Expand Down Expand Up @@ -85,7 +85,9 @@ const TradeFormCollateralSection = ({
const onOpen = useCallback(() => setIsOpen(true), [])
const onSelectCollateral = useCallback(
(isCoveredCall: boolean) => {
onToggleCoveredCall(isCoveredCall)
if (onToggleCoveredCall) {
onToggleCoveredCall(isCoveredCall)
}
onClose()
},
[onClose, onToggleCoveredCall]
Expand Down
8 changes: 6 additions & 2 deletions ui/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,11 @@ const theme = {
color: 'text',
'&:not(.disabled):hover': {
bg: 'hover',
borderColor: 'hover',
borderColor: 'buttonHover',
},
'&:not(.disabled):active': {
bg: 'active',
borderColor: 'active',
borderColor: 'buttonActive',
},
},
defaultTransparent: {
Expand Down Expand Up @@ -749,6 +749,10 @@ const theme = {
color: 'text',
borderColor: 'secondaryText',
},
'&:not(.disabled):active': {
color: 'text',
borderColor: 'secondaryText',
},
},
lightTransparent: {
variant: 'buttons.defaultTransparent',
Expand Down

0 comments on commit 98f4318

Please sign in to comment.