-
-
);
diff --git a/src/components/BalanceDisplay/index.tsx b/src/components/BalanceDisplay/index.tsx
index 0cb2089..96d94a8 100644
--- a/src/components/BalanceDisplay/index.tsx
+++ b/src/components/BalanceDisplay/index.tsx
@@ -13,7 +13,7 @@ export function BalanceDisplay() {
address: collateralTokenAddress,
functionName: 'balanceOf',
account: address,
- args: [address],
+ args: [address as `0x${string}`],
abi: [
{
constant: true,
@@ -32,7 +32,7 @@ export function BalanceDisplay() {
}
if (isPending) return
Loading...
;
-
+ // @ts-ignore-error
if (error) return
Error: {(error as BaseError).shortMessage || error.message}
;
return
Balance: {balance?.toString()}
;
diff --git a/src/components/Navbar/nav-desktop.tsx b/src/components/Navbar/nav-desktop.tsx
new file mode 100644
index 0000000..d99d3b8
--- /dev/null
+++ b/src/components/Navbar/nav-desktop.tsx
@@ -0,0 +1,25 @@
+//📂./src/components/nav-desktop.tsx
+
+import { routes } from "../../routes";
+
+export const NavDesktop = () => {
+ // lg:flex md:flex md:items-center gap-5 text-sm
+ return (
+
+ {routes.map((route) => {
+ const { href, title } = route;
+ return (
+ -
+
+ {title}
+
+
+ );
+ })}
+
+
+ );
+};
diff --git a/src/components/Navbar/nav-mobile.tsx b/src/components/Navbar/nav-mobile.tsx
new file mode 100644
index 0000000..3745963
--- /dev/null
+++ b/src/components/Navbar/nav-mobile.tsx
@@ -0,0 +1,46 @@
+import { useClickAway } from "react-use";
+import { useRef } from "react";
+import { useState } from 'react';
+import '../../App.css';
+import { Link, useLocation } from 'react-router-dom';
+import { HamburgerMenuIcon } from '@radix-ui/react-icons';
+import { SheetContent, SheetHeader, SheetTitle, Sheet } from '../ui/sheet';
+import classNames from 'classnames';
+import { routes } from "../../routes";
+
+export const NavMobile = () => {
+ const [menuOpen, setMenuOpen] = useState
(false);
+ const location = useLocation();
+ const ref = useRef(null);
+
+ useClickAway(ref, () => setMenuOpen(false));
+ // lg:hidden md:hidden
+ return (
+
+
+ setMenuOpen(true)} />
+
+
+ Menu
+
+
+ {routes.map((route) => {
+ const { href, title,icon } = route;
+ return (
+ setMenuOpen(false)}
+ >
+ {title} {icon}
+
+ );
+ })}
+
+
+
+
+ );
+};
diff --git a/src/components/Navbar/topbar.tsx b/src/components/Navbar/topbar.tsx
new file mode 100644
index 0000000..721074b
--- /dev/null
+++ b/src/components/Navbar/topbar.tsx
@@ -0,0 +1,22 @@
+import { NavMobile } from "./nav-mobile";
+// import { NavDesktop } from "./nav-desktop";
+//
+//

+//
+//
+
+
+export const Topbar = () => {
+ return (
+
+ );
+};
diff --git a/src/components/OpenPositionList/index.tsx b/src/components/OpenPositionList/index.tsx
index 84e93cb..8a09ec5 100644
--- a/src/components/OpenPositionList/index.tsx
+++ b/src/components/OpenPositionList/index.tsx
@@ -11,6 +11,7 @@ import {
formatDynamicPrecisionPrice,
formatPrice,
formatUSD,
+ liquidationPriceCalculation,
mapMarketToAssetPath,
mapMarketToPriceFeedId,
mapMarketToTradePairAddress,
@@ -106,6 +107,15 @@ const Position = ({
BigInt(Math.round(Number(size) * (currentPrice / (Number(entryPrice) / PRICE_PRECISION) - 1)))
: 0n;
+ const liquidationPrice = useMemo(() => {
+ return liquidationPriceCalculation({
+ entryPrice: Number(entryPrice) / PRICE_PRECISION,
+ isLong: isLong,
+ collateral: Number(collateral) / PRICE_PRECISION,
+ size: Number(size) / PRICE_PRECISION,
+ });
+ }, [entryPrice, isLong, collateral, size]);
+
// TODO: this rerenders all the items all the time,
// perhaps we should find out how to only locally update
useEffect(() => {
@@ -171,6 +181,10 @@ const Position = ({
Entry Price:
${formatDynamicPrecisionPrice(Number(entryPrice) / PRICE_PRECISION)}
+
Current Price:
{currentPrice ? formatPrice(currentPrice) : '$...'}
diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx
index 0050f84..d64fad3 100644
--- a/src/components/ui/carousel.tsx
+++ b/src/components/ui/carousel.tsx
@@ -181,8 +181,8 @@ const CarouselPrevious = React.forwardRef
,
VariantProps {
@@ -39,6 +39,7 @@ const Slider = React.forwardRef(
return (
{
+
+ it('should return 0 when given logical invalid input', () => {
+ const position: PositionValues = {
+ entryPrice: 20,
+ isLong: true,
+ collateral: 10,
+ size: 5
+ };
+
+ expect(liquidationPriceCalculation(position)).toBe(0);
+ });
+
+ it('should return 0 when given NaN as input', () => {
+ const position: PositionValues = {
+ entryPrice: NaN,
+ isLong: true,
+ collateral: NaN,
+ size: NaN
+ };
+
+ expect(liquidationPriceCalculation(position)).toBe(0);
+ });
+
+ it('should return the correct liquidation price when given valid inputs for a long trade', () => {
+ const position: PositionValues = {
+ entryPrice: 0.3455,
+ isLong: true,
+ collateral: 5000,
+ size: 10000
+ };
+
+ expect(liquidationPriceCalculation(position)).toBe(0.17275);
+ });
+
+ it('should return the correct liquidation price when given valid inputs for a short trade', () => {
+ const position: PositionValues = {
+ entryPrice: 69515.89,
+ isLong: false,
+ collateral: 70000,
+ size: 280000
+ };
+
+ expect(liquidationPriceCalculation(position)).toBe(86894.8625);
+ });
+
+});
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 8403b9d..38554d3 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,4 +1,4 @@
-import { Market } from '@/types';
+import { PositionValues, Market } from '@/types';
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { Address, formatEther } from 'viem';
@@ -40,7 +40,7 @@ export function formatPrice(price: number): string {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
- maximumFractionDigits: 99,
+ maximumFractionDigits: 20,
}).format(Number(formatDynamicPrecisionPrice(price)));
}
@@ -92,3 +92,10 @@ export function mapMarketToPriceFeedId(market: Market): string {
return _map[market];
}
+
+export function liquidationPriceCalculation(position: PositionValues): number {
+ const result: number = position.entryPrice * (1 + (position.isLong ? -1 : 1) * position.collateral / position.size);
+
+ if(!Number.isNaN(result) && result > 0) return result
+ return 0
+}
diff --git a/src/routes.ts b/src/routes.ts
new file mode 100644
index 0000000..2c8075a
--- /dev/null
+++ b/src/routes.ts
@@ -0,0 +1,38 @@
+export const routes = [
+ {
+ title: "Home",
+ href: "/",
+ element: "{}",
+ icon: ""
+ },
+ {
+ title: "Get Started",
+ href: "/get-started",
+ element: "{}",
+ icon: "🚀"
+ },
+ {
+ title: "Exchange",
+ href: "/exchange",
+ element: "{}",
+ icon: ""
+ },
+ {
+ title: "Open Positions",
+ href: "/open-positions",
+ element: "{}",
+ icon: ""
+ },
+ {
+ title: "Closed Positions",
+ href: "/closed-positions",
+ element: "{}",
+ icon: ""
+ },
+ {
+ title: "Pool",
+ href: "/pool",
+ element: "{}",
+ icon: ""
+ },
+];
diff --git a/src/types.ts b/src/types.ts
index 10290a9..46c0d9b 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,4 +1,4 @@
-import { config } from './lib/wagmiConfig';
+// import { config } from './lib/wagmiConfig';
export enum Market {
IOTAUSD = 'IOTAUSD',
@@ -10,8 +10,15 @@ export enum Market {
// SHIBUSD = 'SHIBUSD',
}
-declare module 'wagmi' {
- interface Register {
- config: typeof config;
- }
+// declare module 'wagmi' {
+// interface Register {
+// config: typeof config;
+// }
+// }
+
+export interface PositionValues {
+ entryPrice : number
+ isLong: boolean
+ collateral: number
+ size: number
}
diff --git a/src/views/Exchange/index.tsx b/src/views/Exchange/index.tsx
index 72b8fc8..c0e6f1e 100644
--- a/src/views/Exchange/index.tsx
+++ b/src/views/Exchange/index.tsx
@@ -11,7 +11,7 @@ import { useAccount, useReadContract, useWriteContract, useWaitForTransactionRec
import { erc20Abi, parseEther, formatEther } from 'viem';
import TradePairAbi from '@/abi/TradePair.abi';
import { connection, subscribeToPriceFeeds, unsubscribeToPriceFeeds } from '@/lib/pyth';
-import { formatPrice, mapMarketToTradePairAddress } from '@/lib/utils';
+import { formatPrice, liquidationPriceCalculation, mapMarketToTradePairAddress } from '@/lib/utils';
import { useMarketStore } from '@/store';
import { DollarMask } from '@/lib/masks';
import { Spinner } from '@/components/ui/spinner';
@@ -89,6 +89,7 @@ export const Exchange = () => {
address: collateralTokenAddress,
abi: erc20Abi,
functionName: 'balanceOf',
+ // @ts-ignore-error
args: [address],
});
@@ -96,6 +97,7 @@ export const Exchange = () => {
address: collateralTokenAddress,
abi: erc20Abi,
functionName: 'allowance',
+ // @ts-ignore-error
args: [address, tradePairAddress],
});
@@ -184,9 +186,14 @@ export const Exchange = () => {
return 0;
}
- const entryPrice = currentMarketState.currentPrice;
- return entryPrice * (1 + ((isLong ? -1 : 1) * Number(parsedCollateral)) / Number(positionSize));
- }, [currentMarketState, parsedCollateral, leverage]);
+ return liquidationPriceCalculation({
+ entryPrice: currentMarketState.currentPrice,
+ isLong,
+ collateral: Number(parsedCollateral),
+ size: Number(positionSize),
+ });
+
+ }, [currentMarketState, parsedCollateral, leverage, isLong]);
const handleOpenPosition = async () => {
if (!currentMarketState) {
@@ -209,6 +216,7 @@ export const Exchange = () => {
address: tradePairAddress,
abi: TradePairAbi,
functionName: 'openPosition',
+ // @ts-ignore-error
args: [parsedCollateral, BigInt(leverage * 1_000_000), direction, priceFeedUpdateData],
value: 1n,
});
@@ -414,6 +422,7 @@ export const Exchange = () => {