Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orders edit from trading view #1579

Open
wants to merge 3 commits into
base: release-60
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sdk/src/utils/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export function getByKey<T>(obj?: { [key: string]: T }, key?: string): T | undef

return obj[key];
}

export function deleteByKey<T>(obj: { [key: string]: T }, key: string) {
const newObj = { ...obj };
delete newObj[key];
return newObj;
}
4 changes: 1 addition & 3 deletions src/components/OrderEditorContainer/OrderEditorContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ import { useMemo } from "react";
import { useEditingOrderKeyState } from "context/SyntheticsStateContext/hooks/orderEditorHooks";
import { selectEditingOrder } from "context/SyntheticsStateContext/selectors/orderEditorSelectors";
import { useSelector } from "context/SyntheticsStateContext/utils";
import { usePendingTxns } from "context/PendingTxnsContext/PendingTxnsContext";

import { OrderEditor } from "components/Synthetics/OrderEditor/OrderEditor";

export function OrderEditorContainer() {
const editingOrder = useSelector(selectEditingOrder);
const [, setEditingOrderKey] = useEditingOrderKeyState();
const { setPendingTxns } = usePendingTxns();

const handleClose = useMemo(() => () => setEditingOrderKey(undefined), [setEditingOrderKey]);

if (!editingOrder) {
return null;
}

return <OrderEditor order={editingOrder} onClose={handleClose} setPendingTxns={setPendingTxns} />;
return <OrderEditor order={editingOrder} onClose={handleClose} />;
}
135 changes: 74 additions & 61 deletions src/components/Synthetics/OrderEditor/OrderEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,20 @@
import { Trans, t } from "@lingui/macro";
import { ReactNode, useEffect, useMemo, useState } from "react";
import { useKey } from "react-use";

import { USD_DECIMALS } from "config/factors";
import useUiFeeFactorRequest from "domain/synthetics/fees/utils/useUiFeeFactor";
import {
OrderInfo,
OrderType,
PositionOrderInfo,
SwapOrderInfo,
isLimitOrderType,
isSwapOrderType,
isTriggerDecreaseOrderType,
} from "domain/synthetics/orders";
import { updateOrderTxn } from "domain/synthetics/orders/updateOrderTxn";
import {
formatAcceptablePrice,
formatLeverage,
formatLiquidationPrice,
getTriggerNameByOrderType,
substractMaxLeverageSlippage,
} from "domain/synthetics/positions";
import { convertToTokenAmount, convertToUsd, getTokenData } from "domain/synthetics/tokens";
import { useChainId } from "lib/chains";
import {
calculateDisplayDecimals,
formatAmount,
formatAmountFree,
formatBalanceAmount,
formatDeltaUsd,
formatTokenAmountWithUsd,
formatUsdPrice,
} from "lib/numbers";

import Button from "components/Button/Button";
import StatsTooltipRow from "components/StatsTooltip/StatsTooltipRow";
import TooltipWithPortal from "components/Tooltip/TooltipWithPortal";
import { ValueTransition } from "components/ValueTransition/ValueTransition";
import { BASIS_POINTS_DIVISOR } from "config/factors";
import { BASIS_POINTS_DIVISOR, USD_DECIMALS } from "config/factors";
import { usePendingTxns } from "context/PendingTxnsContext/PendingTxnsContext";
import { useSettings } from "context/SettingsContext/SettingsContextProvider";
import { useSubaccount } from "context/SubaccountContext/SubaccountContext";
import { useSyntheticsEvents } from "context/SyntheticsEvents";
import {
usePositionsConstants,
useTokensData,
useUserReferralInfo,
} from "context/SyntheticsStateContext/hooks/globalsHooks";
import { getIncreasePositionAmounts, getNextPositionValuesForIncreaseTrade } from "domain/synthetics/trade";
import useWallet from "lib/wallets/useWallet";

import BuyInputSection from "components/BuyInputSection/BuyInputSection";
import Modal from "components/Modal/Modal";
import { AcceptablePriceImpactInputRow } from "components/Synthetics/AcceptablePriceImpactInputRow/AcceptablePriceImpactInputRow";

import ExternalLink from "components/ExternalLink/ExternalLink";
import { useMarketInfo } from "context/SyntheticsStateContext/hooks/marketHooks";
import {
useOrderEditorIsSubmittingState,
useOrderEditorSizeInputValueState,
useOrderEditorTriggerPriceInputValueState,
useOrderEditorTriggerRatioInputValueState,
Expand Down Expand Up @@ -81,28 +42,69 @@ import {
selectOrderEditorTriggerRatio,
} from "context/SyntheticsStateContext/selectors/orderEditorSelectors";
import { useSelector } from "context/SyntheticsStateContext/utils";
import useUiFeeFactorRequest from "domain/synthetics/fees/utils/useUiFeeFactor";
import {
OrderInfo,
OrderType,
PositionOrderInfo,
SwapOrderInfo,
isLimitOrderType,
isSwapOrderType,
isTriggerDecreaseOrderType,
} from "domain/synthetics/orders";
import { updateOrderTxn } from "domain/synthetics/orders/updateOrderTxn";
import {
formatAcceptablePrice,
formatLeverage,
formatLiquidationPrice,
getTriggerNameByOrderType,
substractMaxLeverageSlippage,
} from "domain/synthetics/positions";
import { convertToTokenAmount, convertToUsd, getTokenData } from "domain/synthetics/tokens";
import { getIncreasePositionAmounts, getNextPositionValuesForIncreaseTrade } from "domain/synthetics/trade";
import { getIsMaxLeverageExceeded } from "domain/synthetics/trade/utils/validation";

import { numericBinarySearch } from "lib/binarySearch";
import { useChainId } from "lib/chains";
import { helperToast } from "lib/helperToast";
import { useKey } from "react-use";
import {
calculateDisplayDecimals,
formatAmount,
formatAmountFree,
formatBalanceAmount,
formatDeltaUsd,
formatTokenAmountWithUsd,
formatUsdPrice,
} from "lib/numbers";
import useWallet from "lib/wallets/useWallet";
import { bigMath } from "sdk/utils/bigmath";

import Button from "components/Button/Button";
import BuyInputSection from "components/BuyInputSection/BuyInputSection";
import ExternalLink from "components/ExternalLink/ExternalLink";
import Modal from "components/Modal/Modal";
import StatsTooltipRow from "components/StatsTooltip/StatsTooltipRow";
import { AcceptablePriceImpactInputRow } from "components/Synthetics/AcceptablePriceImpactInputRow/AcceptablePriceImpactInputRow";
import TooltipWithPortal from "components/Tooltip/TooltipWithPortal";
import { ValueTransition } from "components/ValueTransition/ValueTransition";
import { SyntheticsInfoRow } from "../SyntheticsInfoRow";

import "./OrderEditor.scss";

type Props = {
order: OrderInfo;
onClose: () => void;
setPendingTxns: (txns: any) => void;
};

export function OrderEditor(p: Props) {
const { chainId } = useChainId();
const { signer } = useWallet();
const tokensData = useTokensData();
const { setPendingTxns } = usePendingTxns();
const { setPendingOrderUpdate } = useSyntheticsEvents();

const [isInited, setIsInited] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSubmitting, setIsSubmitting] = useOrderEditorIsSubmittingState();

const [sizeInputValue, setSizeInputValue] = useOrderEditorSizeInputValueState();
const [triggerPriceInputValue, setTriggerPriceInputValue] = useOrderEditorTriggerPriceInputValueState();
Expand Down Expand Up @@ -426,17 +428,25 @@ export function OrderEditor(p: Props) {

setIsSubmitting(true);

const txnPromise = updateOrderTxn(chainId, signer, subaccount, {
orderKey: p.order.key,
sizeDeltaUsd: sizeDeltaUsd ?? positionOrder.sizeDeltaUsd,
triggerPrice: triggerPrice ?? positionOrder.triggerPrice,
acceptablePrice: acceptablePrice ?? positionOrder.acceptablePrice,
minOutputAmount: minOutputAmount ?? positionOrder.minOutputAmount,
executionFee: additionalExecutionFee?.feeTokenAmount,
indexToken: indexToken,
autoCancel: positionOrder.autoCancel,
setPendingTxns: p.setPendingTxns,
});
const txnPromise = updateOrderTxn(
chainId,
signer,
subaccount,
{
orderKey: p.order.key,
sizeDeltaUsd: sizeDeltaUsd ?? positionOrder.sizeDeltaUsd,
triggerPrice: triggerPrice ?? positionOrder.triggerPrice,
acceptablePrice: acceptablePrice ?? positionOrder.acceptablePrice,
minOutputAmount: minOutputAmount ?? positionOrder.minOutputAmount,
executionFee: additionalExecutionFee?.feeTokenAmount,
indexToken: indexToken,
autoCancel: positionOrder.autoCancel,
},
{
setPendingTxns,
setPendingOrderUpdate,
}
);

if (subaccount) {
p.onClose();
Expand Down Expand Up @@ -481,9 +491,11 @@ export function OrderEditor(p: Props) {
const price = positionOrder.triggerPrice ?? 0n;
const decimals = calculateDisplayDecimals(price, USD_DECIMALS, indexToken?.visualMultiplier);

setTriggerPriceInputValue(
formatAmount(price, USD_DECIMALS, decimals, undefined, undefined, indexToken?.visualMultiplier)
);
if (triggerPriceInputValue === "") {
setTriggerPriceInputValue(
formatAmount(price, USD_DECIMALS, decimals, undefined, undefined, indexToken?.visualMultiplier)
);
}
}

setIsInited(true);
Expand All @@ -495,6 +507,7 @@ export function OrderEditor(p: Props) {
setSizeInputValue,
setTriggerPriceInputValue,
setTriggerRatioInputValue,
triggerPriceInputValue,
]
);

Expand Down
110 changes: 4 additions & 106 deletions src/components/Synthetics/TVChart/TVChart.tsx
Original file line number Diff line number Diff line change
@@ -1,136 +1,34 @@
import { t } from "@lingui/macro";
import { useEffect, useMemo } from "react";

import { USD_DECIMALS } from "config/factors";
import { SUPPORTED_RESOLUTIONS_V2 } from "config/tradingview";
import {
useOrdersInfoData,
usePositionsInfoData,
useTokensData,
} from "context/SyntheticsStateContext/hooks/globalsHooks";
import { selectChartToken } from "context/SyntheticsStateContext/selectors/chartSelectors";
import { selectChartLines } from "context/SyntheticsStateContext/selectors/chartSelectors/selectChartLines";
import { selectSetIsCandlesLoaded } from "context/SyntheticsStateContext/selectors/globalSelectors";
import { selectSelectedMarketVisualMultiplier } from "context/SyntheticsStateContext/selectors/statsSelectors";
import { useSelector } from "context/SyntheticsStateContext/utils";
import { convertTokenAddress, getPriceDecimals, getTokenVisualMultiplier } from "sdk/configs/tokens";
import { PositionOrderInfo, isIncreaseOrderType, isSwapOrderType } from "domain/synthetics/orders";
import { getTokenData } from "domain/synthetics/tokens";
import { useChainId } from "lib/chains";
import { CHART_PERIODS } from "lib/legacy";
import { useLocalStorageSerializeKey } from "lib/localStorage";
import { formatAmount } from "lib/numbers";

import TVChartContainer, { ChartLine } from "components/TVChartContainer/TVChartContainer";
import TVChartContainer from "components/TVChartContainer/TVChartContainer";

import "./TVChart.scss";

const DEFAULT_PERIOD = "5m";

export function TVChart() {
const { chainId } = useChainId();
const { chartToken, symbol: chartTokenSymbol } = useSelector(selectChartToken);
const visualMultiplier = useSelector(selectSelectedMarketVisualMultiplier);
const setIsCandlesLoaded = useSelector(selectSetIsCandlesLoaded);

const ordersInfo = useOrdersInfoData();
const tokensData = useTokensData();
const positionsInfo = usePositionsInfoData();

const { chainId } = useChainId();
const chartTokenAddress = chartToken?.address;

let [period, setPeriod] = useLocalStorageSerializeKey([chainId, "Chart-period-v2"], DEFAULT_PERIOD);

if (!period || !(period in CHART_PERIODS)) {
period = DEFAULT_PERIOD;
}

const chartLines = useMemo(() => {
if (!chartTokenAddress) {
return [];
}

const orderLines: ChartLine[] = Object.values(ordersInfo || {})
.filter((order) => {
if (isSwapOrderType(order.orderType)) {
return false;
}

const positionOrder = order as PositionOrderInfo;

return (
positionOrder.marketInfo &&
positionOrder.triggerPrice !== undefined &&
convertTokenAddress(chainId, positionOrder.marketInfo.indexTokenAddress, "wrapped") ===
convertTokenAddress(chainId, chartTokenAddress, "wrapped")
);
})
.map((order) => {
const positionOrder = order as PositionOrderInfo;
const priceDecimal = getPriceDecimals(chainId, positionOrder.indexToken.symbol);

const longOrShortText = order.isLong ? t`Long` : t`Short`;
const orderTypeText = isIncreaseOrderType(order.orderType) ? t`Inc.` : t`Dec.`;
const token = getTokenData(tokensData, positionOrder.marketInfo.indexTokenAddress, "native");
const tokenSymbol = token?.symbol;
const prefix = token ? getTokenVisualMultiplier(token) : "";
const tokenVisualMultiplier = token?.visualMultiplier;

return {
title: `${longOrShortText} ${orderTypeText} ${prefix}${tokenSymbol}`,
price: parseFloat(
formatAmount(
positionOrder.triggerPrice,
USD_DECIMALS,
priceDecimal,
undefined,
undefined,
tokenVisualMultiplier
)
),
};
});

const positionLines = Object.values(positionsInfo || {}).reduce((acc, position) => {
const priceDecimal = getPriceDecimals(chainId, position.indexToken.symbol);
if (
position.marketInfo &&
convertTokenAddress(chainId, position.marketInfo.indexTokenAddress, "wrapped") ===
convertTokenAddress(chainId, chartTokenAddress, "wrapped")
) {
const longOrShortText = position.isLong ? t`Long` : t`Short`;
const token = getTokenData(tokensData, position.marketInfo?.indexTokenAddress, "native");
const tokenSymbol = token?.symbol;
const prefix = token ? getTokenVisualMultiplier(token) : "";
const tokenVisualMultiplier = token?.visualMultiplier;

const liquidationPrice = formatAmount(
position?.liquidationPrice,
USD_DECIMALS,
priceDecimal,
undefined,
undefined,
tokenVisualMultiplier
);

acc.push({
title: t`Open ${longOrShortText} ${prefix}${tokenSymbol}`,
price: parseFloat(
formatAmount(position.entryPrice, USD_DECIMALS, priceDecimal, undefined, undefined, tokenVisualMultiplier)
),
});
if (liquidationPrice && liquidationPrice !== "NA") {
acc.push({
title: t`Liq. ${longOrShortText} ${prefix}${tokenSymbol}`,
price: parseFloat(liquidationPrice),
});
}
}

return acc;
}, [] as ChartLine[]);

return orderLines.concat(positionLines);
}, [chainId, chartTokenAddress, ordersInfo, positionsInfo, tokensData]);
const chartLines = useSelector(selectChartLines);

useEffect(
function updatePeriod() {
Expand Down
Loading