From 1a462124814443a35a0fae594b1386c567781f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B8b=C4=97rt=C3=B8?= <106074508+EchoDex@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:27:23 +0400 Subject: [PATCH] feat: add history --- .../src/components/TokenInput/TokenInput.tsx | 2 +- spark-frontend/src/entity/SpotMarketTrade.ts | 32 ++++- .../BottomTablesInterfaceSpotImpl.tsx | 133 +++++++++--------- .../BottomTablesInterfaceSpotVM.tsx | 28 ++-- .../SpotOrderBook/SpotOrderBookImpl.tsx | 3 +- .../SpotTrades/SpotTrades.tsx | 3 +- .../SpotTrades/SpotTradesVM.tsx | 6 +- .../src/services/SpotMarketService.ts | 28 ++-- spark-frontend/src/utils/AutoSerializer.ts | 0 9 files changed, 137 insertions(+), 98 deletions(-) create mode 100644 spark-frontend/src/utils/AutoSerializer.ts diff --git a/spark-frontend/src/components/TokenInput/TokenInput.tsx b/spark-frontend/src/components/TokenInput/TokenInput.tsx index 54b56b99..d9c1e5e5 100644 --- a/spark-frontend/src/components/TokenInput/TokenInput.tsx +++ b/spark-frontend/src/components/TokenInput/TokenInput.tsx @@ -103,7 +103,7 @@ const TokenInput: React.FC = (props) => { autofocus={focused} decimals={props.decimals} disabled={props.disabled} - displayDecimals={2} + displayDecimals={props.decimals} max={props.max?.toString()} placeholder="0.00" renderInput={(props, ref) => ( diff --git a/spark-frontend/src/entity/SpotMarketTrade.ts b/spark-frontend/src/entity/SpotMarketTrade.ts index 0b60c38d..a7639afb 100644 --- a/spark-frontend/src/entity/SpotMarketTrade.ts +++ b/spark-frontend/src/entity/SpotMarketTrade.ts @@ -1,4 +1,7 @@ -import { DEFAULT_DECIMALS } from "@src/constants"; +import dayjs, { Dayjs } from "dayjs"; +import { Nullable } from "tsdef"; + +import { DEFAULT_DECIMALS, TOKENS_BY_SYMBOL } from "@src/constants"; import BN from "@src/utils/BN"; import { Token } from "./Token"; @@ -7,33 +10,52 @@ interface SpotMarketTradeParams { id: string; baseToken: Token; matcher: string; + seller: string; + buyer: string; tradeAmount: BN; price: BN; timestamp: number; + userAddress: string; } +const getType = (userAddress: string, buyer: string, seller: string) => { + const address = userAddress.toLowerCase(); + return address === seller.toLowerCase() ? "SELL" : address === buyer.toLowerCase() ? "BUY" : null; +}; + export class SpotMarketTrade { readonly id: SpotMarketTradeParams["id"]; readonly baseToken: SpotMarketTradeParams["baseToken"]; readonly matcher: SpotMarketTradeParams["matcher"]; + readonly seller: SpotMarketTradeParams["seller"]; + readonly buyer: SpotMarketTradeParams["buyer"]; readonly tradeAmount: SpotMarketTradeParams["tradeAmount"]; readonly price: SpotMarketTradeParams["price"]; - readonly timestamp: SpotMarketTradeParams["timestamp"]; + readonly timestamp: Dayjs; + readonly quoteToken = TOKENS_BY_SYMBOL.USDC; + readonly type: Nullable<"SELL" | "BUY"> = null; constructor(params: SpotMarketTradeParams) { this.id = params.id; this.baseToken = params.baseToken; this.matcher = params.matcher; + this.seller = params.seller; + this.buyer = params.buyer; this.tradeAmount = params.tradeAmount; this.price = params.price; - this.timestamp = params.timestamp; + this.timestamp = dayjs.unix(params.timestamp); + this.type = getType(params.userAddress, this.buyer, this.seller); } get formatPrice() { - return BN.formatUnits(this.price, DEFAULT_DECIMALS).toFormat(2); + return BN.formatUnits(this.price, DEFAULT_DECIMALS).toSignificant(2); } get formatTradeAmount() { - return BN.formatUnits(this.price, this.baseToken.decimals).toFormat(2); + return BN.formatUnits(this.tradeAmount, this.baseToken.decimals).toSignificant(2); + } + + get marketSymbol() { + return `${this.baseToken.symbol}-${this.quoteToken.symbol}`; } } diff --git a/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotImpl.tsx b/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotImpl.tsx index d4a1c918..6e68ded5 100644 --- a/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotImpl.tsx +++ b/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotImpl.tsx @@ -40,7 +40,7 @@ const MAX_TABLE_HEIGHT = { const TABS = [ { title: "ORDERS", disabled: false }, { title: "BALANCES", disabled: false }, - // { title: "HISTORY", disabled: false }, + { title: "HISTORY", disabled: false }, ]; const TABLE_SIZES_CONFIG = [ @@ -124,26 +124,26 @@ const BottomTablesInterfaceSpotImpl: React.FC = observer(() => { ), })); - // const getHistoryData = () => - // vm.myOrdersHistory.map((order) => ({ - // date: order.timestamp.format("DD MMM YY, HH:mm"), - // pair: order.marketSymbol, - // type: ( - // - // {order.type} - // - // ), - // amount: ( - // - // {order.baseSizeUnits.toSignificant(2)} - // - // {order.baseToken.symbol} - // - // - // ), - // price: toCurrency(order.priceUnits.toSignificant(2)), - // filled: BN.ZERO.toString(), - // })); + const getHistoryData = () => + vm.myOrdersHistory.map((order) => ({ + date: order.timestamp.format("DD MMM YY, HH:mm"), + pair: order.marketSymbol, + type: ( + + {order.type} + + ), + amount: ( + + {order.formatTradeAmount} + + {order.baseToken.symbol} + + + ), + price: toCurrency(order.formatPrice), + filled: order.formatTradeAmount, + })); const getBalanceData = () => Array.from(balanceStore.balances) @@ -189,10 +189,6 @@ const BottomTablesInterfaceSpotImpl: React.FC = observer(() => { {ord.type} - - Filled: - - - @@ -207,45 +203,50 @@ const BottomTablesInterfaceSpotImpl: React.FC = observer(() => { )); - // const orderHistoryData = vm.myOrdersHistory.map((ord, i) => ( - // - // - // - // {ord.marketSymbol} - // - // - // Amount - // - // {ord.baseSizeUnits.toSignificant(2)} - // - // {ord.baseToken.symbol} - // - // - // - // - // - // Active - // - // - // Side: - // - // {ord.type} - // - // - // - // Filled: - // - - // - // - // - // - // - // Price: - // {toCurrency(ord.priceUnits.toSignificant(2))} - // - // - // - // )); + const orderHistoryData = vm.myOrdersHistory.map((ord, i) => ( + + + + {ord.marketSymbol} + + + Amount + + {ord.formatTradeAmount} + + {ord.baseToken.symbol} + + + + + + Complete + + + Side: + + {ord.type} + + + + Filled: + + {ord.formatTradeAmount} + + {ord.baseToken.symbol} + + + + + + + + Price: + {toCurrency(ord.formatPrice)} + + + + )); const balanceData = Array.from(balanceStore.balances) .filter(([, balance]) => balance && balance.gt(0)) @@ -275,7 +276,7 @@ const BottomTablesInterfaceSpotImpl: React.FC = observer(() => { ); }); - const tabToData = [orderData, balanceData]; + const tabToData = [orderData, balanceData, orderHistoryData]; return ( @@ -318,7 +319,7 @@ const BottomTablesInterfaceSpotImpl: React.FC = observer(() => { }; useEffect(() => { - const tabToData = [getOrderData, getBalanceData]; + const tabToData = [getOrderData, getBalanceData, getHistoryData]; setData(tabToData[tabIndex]()); }, [tabIndex, vm.myOrders, balanceStore.balances]); diff --git a/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotVM.tsx b/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotVM.tsx index 7e8be70e..46b3556b 100644 --- a/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotVM.tsx +++ b/spark-frontend/src/screens/TradeScreen/BottomTables/BottomTablesInterfaceSpot/BottomTablesInterfaceSpotVM.tsx @@ -3,10 +3,10 @@ import { ethers } from "ethers"; import { makeAutoObservable, reaction, when } from "mobx"; import { SPOT_MARKET_ABI } from "@src/abi"; -import { CONTRACT_ADDRESSES } from "@src/constants"; -import { SpotMarketOrder } from "@src/entity"; +import { CONTRACT_ADDRESSES, TOKENS_BY_ASSET_ID } from "@src/constants"; +import { SpotMarketOrder, SpotMarketTrade } from "@src/entity"; import useVM from "@src/hooks/useVM"; -import { fetchOrders } from "@src/services/SpotMarketService"; +import { fetchOrders, fetchTrades } from "@src/services/SpotMarketService"; import { handleEvmErrors } from "@src/utils/handleEvmErrors"; import { RootStore, useStores } from "@stores"; @@ -22,7 +22,7 @@ export const useBottomTablesInterfaceSpotVM = () => useVM(ctx); class BottomTablesInterfaceSpotVM { myOrders: SpotMarketOrder[] = []; - myOrdersHistory: SpotMarketOrder[] = []; + myOrdersHistory: SpotMarketTrade[] = []; initialized: boolean = false; isOrderCancelling = false; @@ -73,22 +73,24 @@ class BottomTablesInterfaceSpotVM { if (!tradeStore.market || !accountStore.address) return; + const { market } = tradeStore; + try { const orders = await fetchOrders({ - baseToken: tradeStore.market.baseToken.assetId, + baseToken: market.baseToken.assetId, limit: 100, trader: accountStore.address, isActive: true, }); this.setMySpotOrders(orders); - const ordersHistory = await fetchOrders({ - baseToken: tradeStore.market.baseToken.assetId, - limit: 100, - trader: accountStore.address, - isActive: false, - }); - this.setMySpotOrdersHistory(ordersHistory); + const ordersHistory = await fetchTrades(market.baseToken.assetId, 100, accountStore.address); + + const token = TOKENS_BY_ASSET_ID[market.baseToken.assetId]; + + this.setMySpotOrdersHistory( + ordersHistory.map((t) => new SpotMarketTrade({ ...t, baseToken: token, userAddress: accountStore.address! })), + ); } catch (error) { console.error(error); } @@ -96,7 +98,7 @@ class BottomTablesInterfaceSpotVM { private setMySpotOrders = (myOrders: SpotMarketOrder[]) => (this.myOrders = myOrders); - private setMySpotOrdersHistory = (myOrdersHistory: SpotMarketOrder[]) => (this.myOrdersHistory = myOrdersHistory); + private setMySpotOrdersHistory = (myOrdersHistory: SpotMarketTrade[]) => (this.myOrdersHistory = myOrdersHistory); private setInitialized = (l: boolean) => (this.initialized = l); } diff --git a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBookImpl.tsx b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBookImpl.tsx index 435ca934..c2d12b18 100644 --- a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBookImpl.tsx +++ b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBookImpl.tsx @@ -19,7 +19,7 @@ import { media } from "@src/themes/breakpoints"; import BN from "@src/utils/BN"; import hexToRgba from "@src/utils/hexToRgb"; -import { ORDER_MODE, useCreateOrderSpotVM } from "../../LeftBlock/CreateOrderSpot/CreateOrderSpotVM"; +import { ORDER_MODE, ORDER_TYPE, useCreateOrderSpotVM } from "../../LeftBlock/CreateOrderSpot/CreateOrderSpotVM"; import { useSpotOrderbookVM } from "./SpotOrderbookVM"; @@ -107,6 +107,7 @@ const SpotOrderBookImpl: React.FC = observer(() => { orderSpotVm.setOrderMode(orderMode); orderSpotVm.setInputPrice(o.price); orderSpotVm.setInputAmount(new BN(o.baseSize), true); + orderSpotVm.setOrderType(ORDER_TYPE.Limit); }} > diff --git a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTrades.tsx b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTrades.tsx index 106bd99d..7ea38962 100644 --- a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTrades.tsx +++ b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTrades.tsx @@ -1,7 +1,6 @@ import React, { useCallback, useEffect, useState } from "react"; import { useTheme } from "@emotion/react"; import styled from "@emotion/styled"; -import dayjs from "dayjs"; import { observer } from "mobx-react"; import { Column } from "@components/Flex"; @@ -60,7 +59,7 @@ const SpotTradesImpl: React.FC = observer(() => { {trade.formatTradeAmount} - {dayjs.unix(trade.timestamp).format("HH:mm:ss")} + {trade.timestamp.format("HH:mm:ss")} ))} diff --git a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTradesVM.tsx b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTradesVM.tsx index ae60b70d..0fc8387a 100644 --- a/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTradesVM.tsx +++ b/spark-frontend/src/screens/TradeScreen/OrderbookAndTradesInterface/SpotTrades/SpotTradesVM.tsx @@ -35,7 +35,7 @@ class SpotTradesVM { } updateTrades = async () => { - const { tradeStore, initialized } = this.rootStore; + const { accountStore, tradeStore, initialized } = this.rootStore; const market = tradeStore.market; @@ -47,7 +47,9 @@ class SpotTradesVM { // todo: to think about TokenStore const token = TOKENS_BY_ASSET_ID[market.baseToken.assetId]; - this.trades = data.map((t) => new SpotMarketTrade({ ...t, baseToken: token })); + this.trades = data.map( + (t) => new SpotMarketTrade({ ...t, baseToken: token, userAddress: accountStore.address! }), + ); } catch (error) { console.error("Error with loading trades"); } diff --git a/spark-frontend/src/services/SpotMarketService.ts b/spark-frontend/src/services/SpotMarketService.ts index f6a88eb1..077763af 100644 --- a/spark-frontend/src/services/SpotMarketService.ts +++ b/spark-frontend/src/services/SpotMarketService.ts @@ -104,23 +104,35 @@ export async function fetchMarketPrice(baseToken: string): Promise { export type TSpotMarketTrade = { id: string; baseToken: string; + seller: string; + buyer: string; matcher: string; tradeAmount: BN; price: BN; timestamp: number; }; -export async function fetchTrades(baseToken: string, limit: number): Promise> { - const filter = `first: ${limit}, where: {baseToken: "${baseToken}"}`; +export async function fetchTrades(baseToken: string, limit: number, trader?: string): Promise> { + const baseTokenFilter = `baseToken: "${baseToken}",`; + const smartFilter = trader + ? `or: [ + { seller: "${trader}", baseToken: "${baseToken}" }, + { buyer: "${trader}", baseToken: "${baseToken}" } + ]` + : ""; + const where = trader ? smartFilter : baseTokenFilter; + const filter = `first: ${limit}, where: { ${where} }`; const query = ` query { tradeEvents(${filter}) { - id - matcher - baseToken - tradeAmount - price - blockTimestamp + id + matcher + seller + buyer + baseToken + tradeAmount + price + blockTimestamp } } `; diff --git a/spark-frontend/src/utils/AutoSerializer.ts b/spark-frontend/src/utils/AutoSerializer.ts new file mode 100644 index 00000000..e69de29b