Perps account preview (#750)
* fix: fixed the Liquidation Price inside the TradeSummary * feat: added account preview * tidy: refactor * feat: added HLS intro * fix: closing the wallet select focusComponent * fix: added perps position update to edit as well * fix: fix update perp * fix: fail catch * fix: implemented suggest changes * tidy: fix * fix: unfix * fix: created helper function * tidy: console.log
This commit is contained in:
parent
3123220fee
commit
c4a2a7d913
@ -26,8 +26,16 @@ const mapErrorMessages = (providerId: string, errorMessage: string, name: string
|
||||
}
|
||||
|
||||
export default function WalletConnecting(props: Props) {
|
||||
const { connect, mobileConnect, simulate, sign, broadcast, mobileProviders, extensionProviders } =
|
||||
useShuttle()
|
||||
const {
|
||||
connect,
|
||||
mobileConnect,
|
||||
simulate,
|
||||
sign,
|
||||
broadcast,
|
||||
mobileProviders,
|
||||
extensionProviders,
|
||||
disconnect,
|
||||
} = useShuttle()
|
||||
const providers = useMemo(
|
||||
() => [...mobileProviders, ...extensionProviders],
|
||||
[mobileProviders, extensionProviders],
|
||||
@ -85,6 +93,9 @@ export default function WalletConnecting(props: Props) {
|
||||
}}
|
||||
/>
|
||||
),
|
||||
onClose: () => {
|
||||
disconnect({ chainId: chainConfig.id })
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -92,7 +103,17 @@ export default function WalletConnecting(props: Props) {
|
||||
}
|
||||
if (!isConnecting) handleConnectAsync()
|
||||
},
|
||||
[isConnecting, client, setIsConnecting, connect, chainConfig, broadcast, sign, simulate],
|
||||
[
|
||||
isConnecting,
|
||||
client,
|
||||
setIsConnecting,
|
||||
connect,
|
||||
chainConfig,
|
||||
broadcast,
|
||||
sign,
|
||||
simulate,
|
||||
disconnect,
|
||||
],
|
||||
)
|
||||
|
||||
const handleMobileConnect = useCallback(
|
||||
@ -105,6 +126,9 @@ export default function WalletConnecting(props: Props) {
|
||||
userDomain: undefined,
|
||||
focusComponent: {
|
||||
component: <WalletSelect />,
|
||||
onClose: () => {
|
||||
disconnect({ chainId: chainConfig.id })
|
||||
},
|
||||
},
|
||||
})
|
||||
return
|
||||
@ -144,6 +168,9 @@ export default function WalletConnecting(props: Props) {
|
||||
}}
|
||||
/>
|
||||
),
|
||||
onClose: () => {
|
||||
disconnect({ chainId: chainConfig.id })
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -161,6 +188,7 @@ export default function WalletConnecting(props: Props) {
|
||||
broadcast,
|
||||
sign,
|
||||
simulate,
|
||||
disconnect,
|
||||
],
|
||||
)
|
||||
|
||||
@ -172,6 +200,9 @@ export default function WalletConnecting(props: Props) {
|
||||
userDomain: undefined,
|
||||
focusComponent: {
|
||||
component: <WalletSelect />,
|
||||
onClose: () => {
|
||||
disconnect({ chainId: chainConfig.id })
|
||||
},
|
||||
},
|
||||
})
|
||||
return
|
||||
@ -188,7 +219,15 @@ export default function WalletConnecting(props: Props) {
|
||||
return
|
||||
}
|
||||
handleConnect(provider.id)
|
||||
}, [handleConnect, isConnecting, providerId, providers, handleMobileConnect])
|
||||
}, [
|
||||
handleConnect,
|
||||
isConnecting,
|
||||
providerId,
|
||||
providers,
|
||||
handleMobileConnect,
|
||||
disconnect,
|
||||
chainConfig.id,
|
||||
])
|
||||
|
||||
return (
|
||||
<FullOverlayContent
|
||||
|
@ -58,7 +58,6 @@ export function getVaultAccountBalanceRow(
|
||||
}
|
||||
|
||||
export function getAmountChangeColor(type: PositionType, amount: BigNumber) {
|
||||
if (type === 'perp') return ''
|
||||
if (type === 'borrow') {
|
||||
if (amount.isGreaterThan(0)) return 'text-loss'
|
||||
if (amount.isLessThan(0)) return 'text-profit'
|
||||
|
@ -16,7 +16,7 @@ interface Props {
|
||||
}
|
||||
|
||||
function LabelAndValue(props: { label: string; children: ReactNode; className?: string }) {
|
||||
const { label, children, className } = props
|
||||
const { label, children } = props
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-between'>
|
||||
@ -58,6 +58,7 @@ function TooltipContent(props: Props) {
|
||||
|
||||
export default function Asset(props: Props) {
|
||||
const { row } = props
|
||||
|
||||
return (
|
||||
<Tooltip content={<TooltipContent row={row} />} type='info'>
|
||||
<Text size='xs' className='flex items-center gap-1 no-wrap group/asset hover:cursor-help'>
|
||||
|
@ -38,7 +38,6 @@ export default function AccountSummary(props: Props) {
|
||||
const { data: prices } = usePrices()
|
||||
const assets = useAllAssets()
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const chainConfig = useStore((s) => s.chainConfig)
|
||||
const accountBalance = useMemo(
|
||||
() =>
|
||||
props.account
|
||||
@ -104,7 +103,7 @@ export default function AccountSummary(props: Props) {
|
||||
renderSubTitle: () => <></>,
|
||||
},
|
||||
]
|
||||
if (chainConfig.perps)
|
||||
if (props.account.perps.length > 0)
|
||||
itemsArray.push({
|
||||
title: 'Perp Positions',
|
||||
renderContent: () =>
|
||||
@ -122,7 +121,6 @@ export default function AccountSummary(props: Props) {
|
||||
borrowAssetsData,
|
||||
lendingAssetsData,
|
||||
props.isHls,
|
||||
chainConfig.perps,
|
||||
handleToggle,
|
||||
accountSummaryTabs,
|
||||
])
|
||||
|
@ -1,16 +1,16 @@
|
||||
import classNames from 'classnames'
|
||||
import { isDesktop } from 'react-device-detect'
|
||||
import { useMemo } from 'react'
|
||||
import { isDesktop } from 'react-device-detect'
|
||||
|
||||
import Wallet from 'components/Wallet'
|
||||
import AccountMenu from 'components/account/AccountMenu'
|
||||
import EscButton from 'components/common/Button/EscButton'
|
||||
import { Coins, CoinsSwap } from 'components/common/Icons'
|
||||
import Settings from 'components/common/Settings'
|
||||
import ChainSelect from 'components/header/ChainSelect'
|
||||
import OracleResyncButton from 'components/header/OracleResyncButton'
|
||||
import { Coins, CoinsSwap } from 'components/common/Icons'
|
||||
import DesktopNavigation from 'components/header/navigation/DesktopNavigation'
|
||||
import RewardsCenter from 'components/header/RewardsCenter'
|
||||
import Settings from 'components/common/Settings'
|
||||
import Wallet from 'components/Wallet'
|
||||
import DesktopNavigation from 'components/header/navigation/DesktopNavigation'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useStore from 'store'
|
||||
import { WalletID } from 'types/enums/wallet'
|
||||
@ -83,8 +83,11 @@ export default function DesktopHeader() {
|
||||
<ChainSelect />
|
||||
</div>
|
||||
)}
|
||||
<div className='flex gap-4'>
|
||||
{!address && <ChainSelect />}
|
||||
<EscButton onClick={handleCloseFocusMode} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='flex gap-4'>
|
||||
{showStaleOracle && <OracleResyncButton />}
|
||||
|
@ -20,7 +20,7 @@ export default function HLSStakingIntro() {
|
||||
leftIcon={<PlusSquared />}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
window.open(DocURL.FARM_INTRO_URL, '_blank')
|
||||
window.open(DocURL.HLS_INTRO_URL, '_blank')
|
||||
}}
|
||||
color='secondary'
|
||||
/>
|
||||
|
@ -5,6 +5,7 @@ export const PERP_TYPE_META = { accessorKey: 'tradeDirection', header: 'Side' }
|
||||
type Props = {
|
||||
tradeDirection: TradeDirection
|
||||
className?: string
|
||||
directionChange?: boolean
|
||||
}
|
||||
|
||||
export default function TradeDirection(props: Props) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import classNames from 'classnames'
|
||||
import { useState } from 'react'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { Cross } from 'components/common/Icons'
|
||||
import LeverageSlider from 'components/common/LeverageSlider'
|
||||
@ -11,12 +12,16 @@ import { Or } from 'components/perps/Module/Or'
|
||||
import usePerpsManageModule from 'components/perps/Module/PerpsManageModule/usePerpsManageModule'
|
||||
import PerpsSummary from 'components/perps/Module/Summary'
|
||||
import AssetAmountInput from 'components/trade/TradeModule/SwapForm/AssetAmountInput'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import getPerpsPosition from 'utils/getPerpsPosition'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export function PerpsManageModule() {
|
||||
const [tradeDirection, setTradeDirection] = useState<TradeDirection | null>(null)
|
||||
const [amount, setAmount] = useState<BigNumber | null>(null)
|
||||
|
||||
const account = useCurrentAccount()
|
||||
const { simulatePerps, addedPerps } = useUpdatedAccount(account)
|
||||
const {
|
||||
closeManagePerpModule,
|
||||
previousAmount,
|
||||
@ -26,6 +31,36 @@ export function PerpsManageModule() {
|
||||
asset,
|
||||
} = usePerpsManageModule(amount)
|
||||
|
||||
const debouncedUpdateAccount = useMemo(
|
||||
() =>
|
||||
debounce((perpsPosition: PerpsPosition) => {
|
||||
if (
|
||||
addedPerps &&
|
||||
perpsPosition.amount === addedPerps.amount &&
|
||||
perpsPosition.tradeDirection === addedPerps.tradeDirection
|
||||
)
|
||||
return
|
||||
simulatePerps(perpsPosition)
|
||||
}, 100),
|
||||
[simulatePerps, addedPerps],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const perpsPosition = getPerpsPosition(
|
||||
asset,
|
||||
amount ?? previousAmount,
|
||||
tradeDirection ?? previousTradeDirection,
|
||||
)
|
||||
debouncedUpdateAccount(perpsPosition)
|
||||
}, [
|
||||
debouncedUpdateAccount,
|
||||
asset,
|
||||
amount,
|
||||
previousAmount,
|
||||
tradeDirection,
|
||||
previousTradeDirection,
|
||||
])
|
||||
|
||||
if (!asset) return null
|
||||
|
||||
return (
|
||||
@ -47,7 +82,7 @@ export function PerpsManageModule() {
|
||||
/>
|
||||
<AssetAmountInput
|
||||
label='Amount'
|
||||
max={BN(100000)} // TODO: Implement max calculation
|
||||
max={BN(1000000)} // TODO: Implement max calculation
|
||||
amount={amount ?? previousAmount}
|
||||
setAmount={setAmount}
|
||||
asset={asset}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useState } from 'react'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Card from 'components/common/Card'
|
||||
import LeverageSlider from 'components/common/LeverageSlider'
|
||||
@ -13,7 +14,10 @@ import AssetAmountInput from 'components/trade/TradeModule/SwapForm/AssetAmountI
|
||||
import OrderTypeSelector from 'components/trade/TradeModule/SwapForm/OrderTypeSelector'
|
||||
import { AvailableOrderType } from 'components/trade/TradeModule/SwapForm/OrderTypeSelector/types'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import usePerpsAsset from 'hooks/perps/usePerpsAsset'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import getPerpsPosition from 'utils/getPerpsPosition'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export function PerpsModule() {
|
||||
@ -21,23 +25,43 @@ export function PerpsModule() {
|
||||
const [tradeDirection, setTradeDirection] = useState<TradeDirection>('long')
|
||||
const { perpsAsset } = usePerpsAsset()
|
||||
const [leverage, setLeverage] = useState<number>(1)
|
||||
|
||||
const account = useCurrentAccount()
|
||||
const { simulatePerps, addedPerps } = useUpdatedAccount(account)
|
||||
const [amount, setAmount] = useState<BigNumber>(BN_ZERO)
|
||||
|
||||
const debouncedUpdateAccount = useMemo(
|
||||
() =>
|
||||
debounce((perpsPosition: PerpsPosition) => {
|
||||
if (
|
||||
addedPerps &&
|
||||
perpsPosition.amount === addedPerps.amount &&
|
||||
perpsPosition.tradeDirection === addedPerps.tradeDirection
|
||||
)
|
||||
return
|
||||
simulatePerps(perpsPosition)
|
||||
}, 100),
|
||||
[simulatePerps, addedPerps],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const perpsPosition = getPerpsPosition(perpsAsset, amount, tradeDirection)
|
||||
debouncedUpdateAccount(perpsPosition)
|
||||
}, [debouncedUpdateAccount, amount, perpsAsset, tradeDirection])
|
||||
|
||||
if (!perpsAsset) return null
|
||||
|
||||
return (
|
||||
<Card
|
||||
contentClassName='px-4 gap-5 flex flex-col h-full pb-4'
|
||||
title={<AssetSelectorPerps asset={perpsAsset} />}
|
||||
className='mb-4 h-full'
|
||||
className='h-full mb-4'
|
||||
>
|
||||
<OrderTypeSelector selected={selectedOrderType} onChange={setSelectedOrderType} />
|
||||
|
||||
<TradeDirectionSelector direction={tradeDirection} onChangeDirection={setTradeDirection} />
|
||||
<AssetAmountInput
|
||||
label='Amount'
|
||||
max={BN(1000)} // TODO: Implement max calculation
|
||||
max={BN(1000000)} // TODO: Implement max calculation
|
||||
amount={amount}
|
||||
setAmount={setAmount}
|
||||
asset={perpsAsset}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import classNames from 'classnames'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import ActionButton from 'components/common/Button/ActionButton'
|
||||
import { CircularProgress } from 'components/common/CircularProgress'
|
||||
|
@ -1,8 +1,7 @@
|
||||
import Osmosis1 from 'configs/chains/osmosis/osmosis-1'
|
||||
import { NETWORK } from 'types/enums/network'
|
||||
import { ChainInfoID } from 'types/enums/wallet'
|
||||
|
||||
import Osmosis1 from './osmosis-1'
|
||||
|
||||
const Devnet: ChainConfig = {
|
||||
...Osmosis1,
|
||||
id: ChainInfoID.OsmosisDevnet,
|
||||
|
@ -33,9 +33,12 @@ function useDisplayCurrencyPrice() {
|
||||
)
|
||||
|
||||
const convertAmount = useCallback(
|
||||
(asset: Asset, amount: string | number | BigNumber) =>
|
||||
(asset: Asset, amount: string | number | BigNumber) => {
|
||||
return (
|
||||
getConversionRate(asset.denom)?.multipliedBy(BN(amount).shiftedBy(-asset.decimals)) ??
|
||||
BN_ZERO,
|
||||
BN_ZERO
|
||||
)
|
||||
},
|
||||
[getConversionRate],
|
||||
)
|
||||
|
||||
|
@ -36,6 +36,27 @@ export function removeCoins(coinsToRemove: BNCoin[], currentCoins: BNCoin[]) {
|
||||
return currentCoins
|
||||
}
|
||||
|
||||
export function updatePerpsPositions(
|
||||
currentPositions: PerpsPosition[],
|
||||
updatedPosition?: PerpsPosition,
|
||||
): PerpsPosition[] {
|
||||
if (!updatedPosition) {
|
||||
return currentPositions ?? []
|
||||
}
|
||||
const currentDenoms = currentPositions.map((position) => position.denom)
|
||||
const index = currentDenoms.indexOf(updatedPosition.denom)
|
||||
|
||||
if (index === -1) {
|
||||
currentPositions.push(updatedPosition)
|
||||
return currentPositions
|
||||
}
|
||||
|
||||
currentPositions[index].tradeDirection = updatedPosition.tradeDirection
|
||||
currentPositions[index].amount = updatedPosition.amount
|
||||
|
||||
return currentPositions
|
||||
}
|
||||
|
||||
export function addValueToVaults(
|
||||
vaultValues: VaultValue[],
|
||||
vaults: DepositedVault[],
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
addValueToVaults,
|
||||
getDepositAndLendCoinsToSpend,
|
||||
removeCoins,
|
||||
updatePerpsPositions,
|
||||
} from 'hooks/useUpdatedAccount/functions'
|
||||
import useVaults from 'hooks/useVaults'
|
||||
import useStore from 'store'
|
||||
@ -43,6 +44,7 @@ export function useUpdatedAccount(account?: Account) {
|
||||
const [addedLends, addLends] = useState<BNCoin[]>([])
|
||||
const [removedLends, removeLends] = useState<BNCoin[]>([])
|
||||
const [addedTrades, addTrades] = useState<BNCoin[]>([])
|
||||
const [addedPerps, addPerps] = useState<PerpsPosition>()
|
||||
const [leverage, setLeverage] = useState<number>(0)
|
||||
|
||||
const removeDepositAndLendsByDenom = useCallback(
|
||||
@ -241,6 +243,14 @@ export function useUpdatedAccount(account?: Account) {
|
||||
[account, assets, prices, slippage],
|
||||
)
|
||||
|
||||
const simulatePerps = useCallback(
|
||||
(position: PerpsPosition) => {
|
||||
if (!account) return
|
||||
addPerps(position)
|
||||
},
|
||||
[account, addPerps],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!account) return
|
||||
|
||||
@ -252,6 +262,7 @@ export function useUpdatedAccount(account?: Account) {
|
||||
[...accountCopy.vaults],
|
||||
availableVaults ?? [],
|
||||
)
|
||||
accountCopy.perps = updatePerpsPositions([...accountCopy.perps], addedPerps)
|
||||
accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = removeCoins(removedDebts, [...accountCopy.debts])
|
||||
accountCopy.lends = addCoins(addedLends, [...accountCopy.lends])
|
||||
@ -274,6 +285,7 @@ export function useUpdatedAccount(account?: Account) {
|
||||
prices,
|
||||
addedTrades,
|
||||
assets,
|
||||
addedPerps,
|
||||
])
|
||||
|
||||
return {
|
||||
@ -286,10 +298,12 @@ export function useUpdatedAccount(account?: Account) {
|
||||
addLends,
|
||||
removeLends,
|
||||
addVaultValues,
|
||||
addPerps,
|
||||
addedDeposits,
|
||||
addedDebts,
|
||||
addedLends,
|
||||
addedTrades,
|
||||
addedPerps,
|
||||
leverage,
|
||||
removedDeposits,
|
||||
removedDebts,
|
||||
@ -303,5 +317,6 @@ export function useUpdatedAccount(account?: Account) {
|
||||
simulateTrade,
|
||||
simulateVaultDeposit,
|
||||
simulateWithdraw,
|
||||
simulatePerps,
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ export enum DocURL {
|
||||
COUNCIL_KEPLR = 'https://wallet.keplr.app/chains/mars-hub?tab=governance',
|
||||
DOCS_URL = 'https://docs.marsprotocol.io/',
|
||||
FARM_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/farming/farming-intro',
|
||||
HLS_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/high-leveraged-strategies/high-leveraged-strategies-intro',
|
||||
MANAGE_ACCOUNT_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/credit-accounts/credit-accounts-intro',
|
||||
ROVER_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/credit-accounts',
|
||||
PRIVACY_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/privacy-policy',
|
||||
|
@ -242,8 +242,14 @@ export function cloneAccount(account: Account): Account {
|
||||
unlocked: vault.values.unlocked,
|
||||
},
|
||||
})),
|
||||
// TODO: 📈Add correct type mapping
|
||||
perps: account.perps,
|
||||
perps: account.perps.map((perpPosition) => ({
|
||||
...perpPosition,
|
||||
amount: perpPosition.amount,
|
||||
closingFee: perpPosition.closingFee,
|
||||
pnl: perpPosition.pnl,
|
||||
entryPrice: perpPosition.entryPrice,
|
||||
tradeDirection: perpPosition.tradeDirection,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
|
23
src/utils/getPerpsPosition.ts
Normal file
23
src/utils/getPerpsPosition.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import { BN_ONE } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
export default function getPerpsPosition(
|
||||
asset: Asset,
|
||||
amount: BigNumber,
|
||||
tradeDirection: TradeDirection,
|
||||
) {
|
||||
const perpsBaseDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3'
|
||||
const perpsPosition = {
|
||||
amount,
|
||||
closingFee: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE),
|
||||
pnl: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE.negated()),
|
||||
entryPrice: BN_ONE,
|
||||
baseDenom: perpsBaseDenom,
|
||||
denom: asset.denom,
|
||||
tradeDirection,
|
||||
}
|
||||
|
||||
return perpsPosition
|
||||
}
|
Loading…
Reference in New Issue
Block a user