diff --git a/package.json b/package.json index 534768a8..767b5c65 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "pnpm": ">=9.7.0" }, "dependencies": { - "@compolabs/spark-orderbook-ts-sdk": "^1.8.2", + "@compolabs/spark-orderbook-ts-sdk": "^1.8.4", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@fuels/connectors": "^0.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 349361c1..11e56451 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@compolabs/spark-orderbook-ts-sdk': - specifier: ^1.8.2 - version: 1.8.2(@types/react@18.3.4)(fuels@0.93.0)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.8.4 + version: 1.8.4(@types/react@18.3.4)(fuels@0.93.0)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@emotion/react': specifier: ^11.11.3 version: 11.13.3(@types/react@18.3.4)(react@18.3.1) @@ -982,8 +982,8 @@ packages: '@coinbase/wallet-sdk@4.0.4': resolution: {integrity: sha512-74c040CRnGhfRjr3ArnkAgud86erIqdkPHNt5HR1k9u97uTIZCJww9eGYT67Qf7gHPpGS/xW8Be1D4dvRm63FA==} - '@compolabs/spark-orderbook-ts-sdk@1.8.2': - resolution: {integrity: sha512-i3MKp0ORK8P5lscsqzQ9Wl0yC+y2yB9lGmjD2N7/2guzIq+8KUhjSijdTIZ65SFX7v5ms7ssqFmPnxJOiMQFkA==} + '@compolabs/spark-orderbook-ts-sdk@1.8.4': + resolution: {integrity: sha512-9YlOQf0G3ikyzxKadZ/ZuuC3WYLOmBFGsPtrLYjnxKBDm06xzJ0GTZp2xJhm02dko2GuweQbEJW5dm7XOOrPHA==} engines: {node: '>=18'} peerDependencies: fuels: '>=0.93.0' @@ -8247,7 +8247,7 @@ snapshots: preact: 10.23.2 sha.js: 2.4.11 - '@compolabs/spark-orderbook-ts-sdk@1.8.2(@types/react@18.3.4)(fuels@0.93.0)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@compolabs/spark-orderbook-ts-sdk@1.8.4(@types/react@18.3.4)(fuels@0.93.0)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@apollo/client': 3.11.8(@types/react@18.3.4)(graphql-ws@5.16.0(graphql@16.9.0))(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) bignumber.js: 9.1.2 diff --git a/src/screens/SpotScreen/OrderbookAndTradesInterface/OrderbookAndTradesInterface.tsx b/src/screens/SpotScreen/OrderbookAndTradesInterface/OrderbookAndTradesInterface.tsx index c637c242..c7d97a64 100644 --- a/src/screens/SpotScreen/OrderbookAndTradesInterface/OrderbookAndTradesInterface.tsx +++ b/src/screens/SpotScreen/OrderbookAndTradesInterface/OrderbookAndTradesInterface.tsx @@ -6,7 +6,6 @@ import SizedBox from "@components/SizedBox"; import Text, { TEXT_TYPES } from "@src/components/Text"; import { SpotOrderBook } from "./SpotOrderBook/SpotOrderBook"; -import { SpotOrderbookVMProvider } from "./SpotOrderBook/SpotOrderbookVM"; import { SpotTrades } from "./SpotTrades/SpotTrades"; import { SpotTradesVMProvider } from "./SpotTrades/SpotTradesVM"; @@ -14,26 +13,24 @@ const OrderbookAndTradesInterface: React.FC = () => { const [isOrderbook, setIsOrderbook] = useState(true); return ( - - - - - - - - - {isOrderbook ? : } - - - + + + + + + + + {isOrderbook ? : } + + ); }; diff --git a/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook.tsx b/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook.tsx index 81aa3f53..491a7511 100644 --- a/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook.tsx +++ b/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook.tsx @@ -24,8 +24,6 @@ import { useStores } from "@stores"; import { ORDER_MODE, useCreateOrderVM } from "../../RightBlock/CreateOrder/CreateOrderVM"; -import { useSpotOrderbookVM } from "./SpotOrderbookVM"; - interface IProps extends HTMLAttributes {} export enum SPOT_ORDER_FILTER { @@ -43,7 +41,7 @@ const SPOT_SETTINGS_ICONS = { }; export const SpotOrderBook: React.FC = observer(() => { - const vm = useSpotOrderbookVM(); + const { spotOrderBookStore } = useStores(); const orderSpotVm = useCreateOrderVM(); const media = useMedia(); const theme = useTheme(); @@ -53,18 +51,19 @@ export const SpotOrderBook: React.FC = observer(() => { const [isSettingsOpen, openSettings, closeSettings] = useFlag(); useEffect(() => { - vm.calcSize(media.mobile); + spotOrderBookStore.calcSize(media.mobile); }, [media.mobile]); const handleCalcSize = useCallback(() => { - vm.calcSize(media.mobile); + spotOrderBookStore.calcSize(media.mobile); }, [media.mobile]); useEventListener("resize", handleCalcSize); - const isOrderBookEmpty = vm.allBuyOrders.length === 0 && vm.allSellOrders.length === 0; + const isOrderBookEmpty = + spotOrderBookStore.allBuyOrders.length === 0 && spotOrderBookStore.allSellOrders.length === 0; - if (vm.isOrderBookLoading && isOrderBookEmpty) { + if (spotOrderBookStore.isOrderBookLoading && isOrderBookEmpty) { return ; } @@ -85,9 +84,9 @@ export const SpotOrderBook: React.FC = observer(() => { vm.setOrderFilter(index)} + onClick={() => spotOrderBookStore.setOrderFilter(index)} /> )); }; @@ -97,9 +96,9 @@ export const SpotOrderBook: React.FC = observer(() => { return ( - {vm.spreadPrice} + {spotOrderBookStore.spreadPrice} - {`(${vm.spreadPercent}%)`} + {`(${spotOrderBookStore.spreadPercent}%)`} ); } @@ -107,31 +106,35 @@ export const SpotOrderBook: React.FC = observer(() => { return ( SPREAD - {vm.spreadPrice} - {`(${vm.spreadPercent}%) `} + {spotOrderBookStore.spreadPrice} + {`(${spotOrderBookStore.spreadPercent}%) `} ); }; - const indexOfDecimal = SPOT_DECIMAL_OPTIONS.indexOf(vm.decimalGroup); + const indexOfDecimal = SPOT_DECIMAL_OPTIONS.indexOf(spotOrderBookStore.decimalGroup); const handleDecimalSelect = (index: string) => { const value = SPOT_DECIMAL_OPTIONS[Number(index)]; - vm.setDecimalGroup(value); + spotOrderBookStore.setDecimalGroup(value); }; const renderOrders = (orders: SpotMarketOrder[], type: "sell" | "buy") => { const orderMode = type === "sell" ? ORDER_MODE.BUY : ORDER_MODE.SELL; const volumePercent = (ord: SpotMarketOrder) => - type === "sell" ? ord.initialAmount.div(vm.totalSell) : ord.initialQuoteAmount.div(vm.totalBuy); + type === "sell" + ? ord.initialAmount.div(spotOrderBookStore.totalSell) + : ord.initialQuoteAmount.div(spotOrderBookStore.totalBuy); const color = type === "sell" ? theme.colors.redLight : theme.colors.greenLight; return orders.map((o, index) => ( orderSpotVm.selectOrderbookOrder(o, orderMode)}> {o.currentAmountUnits.toFormat(4)} - {o.priceUnits.toFormat(vm.decimalGroup)} - {numeral(o.currentQuoteAmountUnits).format(`0.${"0".repeat(vm.decimalGroup)}a`)} + {o.priceUnits.toFormat(spotOrderBookStore.decimalGroup)} + + {numeral(o.currentQuoteAmountUnits).format(`0.${"0".repeat(spotOrderBookStore.decimalGroup)}a`)} + )); }; @@ -156,33 +159,56 @@ export const SpotOrderBook: React.FC = observer(() => { {`Total ${market?.quoteToken.symbol}`} - {vm.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && ( + {spotOrderBookStore.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && ( )} - {vm.orderFilter === SPOT_ORDER_FILTER.SELL && ( + {spotOrderBookStore.orderFilter === SPOT_ORDER_FILTER.SELL && ( )} - {vm.orderFilter !== SPOT_ORDER_FILTER.BUY && renderOrders(vm.sellOrders, "sell")} + {spotOrderBookStore.orderFilter !== SPOT_ORDER_FILTER.BUY && + renderOrders(spotOrderBookStore.sellOrders, "sell")} - {vm.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && renderSpread()} + {spotOrderBookStore.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && renderSpread()} - {vm.orderFilter !== SPOT_ORDER_FILTER.SELL && renderOrders(vm.buyOrders, "buy")} + {spotOrderBookStore.orderFilter !== SPOT_ORDER_FILTER.SELL && + renderOrders(spotOrderBookStore.buyOrders, "buy")} - {vm.orderFilter === SPOT_ORDER_FILTER.BUY && ( + {spotOrderBookStore.orderFilter === SPOT_ORDER_FILTER.BUY && ( )} - {vm.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && ( - + {spotOrderBookStore.orderFilter === SPOT_ORDER_FILTER.SELL_AND_BUY && ( + )} @@ -191,10 +217,10 @@ export const SpotOrderBook: React.FC = observer(() => { filterIcons={Object.entries(SPOT_SETTINGS_ICONS).map(([key, value]) => value)} isOpen={isSettingsOpen} selectedDecimal={String(indexOfDecimal)} - selectedFilter={vm.orderFilter} + selectedFilter={spotOrderBookStore.orderFilter} onClose={closeSettings} onDecimalSelect={handleDecimalSelect} - onFilterSelect={vm.setOrderFilter} + onFilterSelect={spotOrderBookStore.setOrderFilter} /> diff --git a/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrder.tsx b/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrder.tsx index b2b9fac4..2bcf8ef2 100644 --- a/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrder.tsx +++ b/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrder.tsx @@ -126,6 +126,7 @@ const CreateOrder: React.FC = observer(() => { }; const renderInstruction = () => { + if (settingsStore.orderType === ORDER_TYPE.Market) return <>; const handleChangeTimeInForce = (e: any) => { settingsStore.setTimeInForce(e); }; diff --git a/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrderVM.tsx b/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrderVM.tsx index 7d435140..35baa702 100644 --- a/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrderVM.tsx +++ b/src/screens/SpotScreen/RightBlock/CreateOrder/CreateOrderVM.tsx @@ -89,17 +89,18 @@ class CreateOrderVM { () => oracleStore.prices, () => { const { orderType } = settingsStore; - const token = tradeStore.market?.baseToken; - const price = token?.priceFeed ? oracleStore.getTokenIndexPrice(token?.priceFeed) : BN.ZERO; - + const { spotOrderBookStore } = this.rootStore; + const order = this.isSell + ? spotOrderBookStore.buyOrders[0] + : spotOrderBookStore.sellOrders[spotOrderBookStore.sellOrders.length - 1]; if (orderType === ORDER_TYPE.Market) { - this.setInputPriceThrottle(price); + this.setInputPriceThrottle(order.price); } else if ( orderType === ORDER_TYPE.Limit && this.inputPrice.isZero() && this.activeInput !== ACTIVE_INPUT.Price ) { - this.setInputPriceThrottle(price); + this.setInputPriceThrottle(order.price); } }, ); @@ -363,8 +364,6 @@ class CreateOrderVM { ...deposit, }; - console.log(order); - const data = await bcNetwork.createSpotOrderWithDeposit(order, marketContracts); return data.transactionId; }; @@ -383,27 +382,42 @@ class CreateOrderVM { asset: market.baseToken.assetId ?? "", status: ["Active"], }; + const isBuy = type === OrderType.Buy; - const oppositeOrderType = type === OrderType.Buy ? OrderType.Sell : OrderType.Buy; + const oppositeOrderType = isBuy ? OrderType.Sell : OrderType.Buy; const orders = await bcNetwork.fetchSpotOrders({ ...params, orderType: oppositeOrderType }); + let total = this.inputTotal; + let spend = BN.ZERO; + const orderList = orders + .map((el) => { + if (total.toNumber() < 0) { + return null; + } + spend = spend.plus(el.currentAmount); + total = total.minus(el.currentQuoteAmount); + return el; + }) + .filter((el) => el !== null); const price = settingsStore.orderType === ORDER_TYPE.Market - ? orders[orders.length - 1].price.toString() + ? orderList[orderList.length - 1].price.toString() : this.inputPrice.toString(); + deposit = { + ...deposit, + amountToSpend: this.inputAmount.toString(), + }; + const order: FulfillOrderManyWithDepositParams = { amount: this.inputAmount.toString(), orderType: type, limitType: settingsStore.timeInForce, price, - orders: orders.map((el) => el.id), + orders: orderList.map((el) => el.id), slippage: "10000", ...deposit, }; - - console.log(order); - const data = await bcNetwork.fulfillOrderManyWithDeposit(order, marketContracts); return data.transactionId; }; diff --git a/src/screens/SpotScreen/SpotScreenMobile.tsx b/src/screens/SpotScreen/SpotScreenMobile.tsx index 02c6ad12..0e2d595b 100644 --- a/src/screens/SpotScreen/SpotScreenMobile.tsx +++ b/src/screens/SpotScreen/SpotScreenMobile.tsx @@ -12,7 +12,6 @@ import { media } from "@src/themes/breakpoints"; import { useStores } from "@stores"; import { SpotOrderBook } from "./OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook"; -import { SpotOrderbookVMProvider } from "./OrderbookAndTradesInterface/SpotOrderBook/SpotOrderbookVM"; import CreateOrder from "./RightBlock/CreateOrder"; import MarketSelection from "./RightBlock/MarketSelection"; import MarketStatistics from "./MarketStatistics"; @@ -38,9 +37,7 @@ const SpotScreenMobile: React.FC = observer(() => { return ( - - - + diff --git a/src/screens/SwapScreen/SwapScreen.tsx b/src/screens/SwapScreen/SwapScreen.tsx index ad24a75d..2b1744f4 100644 --- a/src/screens/SwapScreen/SwapScreen.tsx +++ b/src/screens/SwapScreen/SwapScreen.tsx @@ -30,7 +30,7 @@ export const SwapScreen: React.FC = observer(() => { const { isConnected } = useWallet(); const theme = useTheme(); const media = useMedia(); - const { swapStore, balanceStore, quickAssetsStore, tradeStore } = useStores(); + const { swapStore, balanceStore, tradeStore, spotOrderBookStore } = useStores(); const [isConnectDialogVisible, openConnectDialog, closeConnectDialog] = useFlag(); const bcNetwork = FuelNetwork.getInstance(); const [slippage, setSlippage] = useState(INITIAL_SLIPPAGE); @@ -76,14 +76,6 @@ export const SwapScreen: React.FC = observer(() => { return d.length > 0 ? d.filter((el) => assets.some((item) => item.assetId === el.assetId)) : []; }; - const getMarketPair = (baseAsset: Token, queryAsset: Token) => { - return markets.find( - (el) => - (el.baseToken.assetId === baseAsset.assetId && el.quoteToken.assetId === queryAsset.assetId) || - (el.baseToken.assetId === queryAsset.assetId && el.quoteToken.assetId === baseAsset.assetId), - ); - }; - const onPayAmountChange = (e: React.ChangeEvent) => { setOnPress(false); const newPayAmount = replaceComma(e.target.value); @@ -93,9 +85,11 @@ export const SwapScreen: React.FC = observer(() => { } swapStore.setPayAmount(newPayAmount); - - const receiveAmount = - Number(newPayAmount) * (parseNumberWithCommas(sellTokenPrice) / parseNumberWithCommas(buyTokenPrice)); + const isBuy = swapStore.isBuy; + const price = !isBuy() + ? spotOrderBookStore.buyOrders[0].price + : spotOrderBookStore.sellOrders[spotOrderBookStore.sellOrders.length - 1].price; + const receiveAmount = BN.parseUnits(new BN(newPayAmount).dividedBy(price), DEFAULT_DECIMALS); swapStore.setReceiveAmount(receiveAmount.toFixed(swapStore.buyToken.precision)); }; @@ -109,8 +103,11 @@ export const SwapScreen: React.FC = observer(() => { swapStore.setReceiveAmount(newReceiveAmount); - const payAmount = - Number(newReceiveAmount) * (parseNumberWithCommas(buyTokenPrice) / parseNumberWithCommas(sellTokenPrice)); + const isBuy = swapStore.isBuy; + const price = !isBuy() + ? spotOrderBookStore.buyOrders[0].price + : spotOrderBookStore.sellOrders[spotOrderBookStore.sellOrders.length - 1].price; + const payAmount = BN.parseUnits(new BN(newReceiveAmount).dividedBy(price), DEFAULT_DECIMALS); swapStore.setPayAmount(payAmount.toFixed(swapStore.sellToken.precision)); }; @@ -139,6 +136,7 @@ export const SwapScreen: React.FC = observer(() => { swapStore.setReceiveAmount("0"); } } catch (err) { + setIsloading(false); console.error("er", err); } }; @@ -155,7 +153,7 @@ export const SwapScreen: React.FC = observer(() => { swapStore.setBuyToken(type === "sell" ? paris[0] : pair); swapStore.setPayAmount("0"); swapStore.setReceiveAmount("0"); - const marketId = getMarketPair(pair, paris[0]); + const marketId = swapStore.getMarketPair(pair, paris[0]); if (!marketId) return; tradeStore.selectActiveMarket(marketId.symbol); balanceStore.update(); @@ -183,7 +181,7 @@ export const SwapScreen: React.FC = observer(() => { { handleChangeMarketId(tokens, item, "sell"); @@ -217,7 +215,7 @@ export const SwapScreen: React.FC = observer(() => { { handleChangeMarketId(buyTokenOptions, item, "buy"); diff --git a/src/stores/RootStore.ts b/src/stores/RootStore.ts index 2c69e9da..ecc1bd29 100644 --- a/src/stores/RootStore.ts +++ b/src/stores/RootStore.ts @@ -13,6 +13,7 @@ import { BalanceStore } from "./BalanceStore"; import { ModalStore } from "./ModalStore"; import OracleStore from "./OracleStore"; import SwapStore from "./SwapStore"; +import SpotOrderBookStore from "./SpotOrderBookStore"; export interface ISerializedRootStore { accountStore?: ISerializedAccountStore; @@ -33,6 +34,7 @@ export default class RootStore { swapStore: SwapStore; mixPanelStore: MixPanelStore; quickAssetsStore: QuickAssetsStore; + spotOrderBookStore: SpotOrderBookStore; private constructor(initState?: ISerializedRootStore) { this.notificationStore = new NotificationStore(this); @@ -46,6 +48,7 @@ export default class RootStore { this.swapStore = new SwapStore(this); this.mixPanelStore = new MixPanelStore(this); this.quickAssetsStore = new QuickAssetsStore(this); + this.spotOrderBookStore = new SpotOrderBookStore(this); makeAutoObservable(this); diff --git a/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderbookVM.tsx b/src/stores/SpotOrderBookStore.ts similarity index 91% rename from src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderbookVM.tsx rename to src/stores/SpotOrderBookStore.ts index 3178ff6c..60e6950e 100644 --- a/src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderbookVM.tsx +++ b/src/stores/SpotOrderBookStore.ts @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React from "react"; import { GetActiveOrdersParams, OrderType } from "@compolabs/spark-orderbook-ts-sdk"; import { makeAutoObservable, reaction } from "mobx"; import { Nullable } from "tsdef"; @@ -6,30 +6,19 @@ import { Nullable } from "tsdef"; import { FuelNetwork } from "@src/blockchain"; import { DEFAULT_DECIMALS } from "@src/constants"; import { SpotMarketOrder } from "@src/entity"; -import useVM from "@src/hooks/useVM"; import { Subscription } from "@src/typings/utils"; import BN from "@src/utils/BN"; import { formatSpotMarketOrders } from "@src/utils/formatSpotMarketOrders"; import { groupOrders } from "@src/utils/groupOrders"; -import { RootStore, useStores } from "@stores"; +import { RootStore } from "@stores"; -import { SPOT_ORDER_FILTER } from "./SpotOrderBook"; - -const ctx = React.createContext(null); +import { SPOT_ORDER_FILTER } from "@src/screens/SpotScreen/OrderbookAndTradesInterface/SpotOrderBook/SpotOrderBook"; interface IProps { children: React.ReactNode; } -export const SpotOrderbookVMProvider: React.FC = ({ children }) => { - const rootStore = useStores(); - const store = useMemo(() => new SpotOrderbookVM(rootStore), [rootStore]); - return {children}; -}; - -export const useSpotOrderbookVM = () => useVM(ctx); - -class SpotOrderbookVM { +class SpotOrderBookStore { private readonly rootStore: RootStore; allBuyOrders: SpotMarketOrder[] = []; @@ -208,3 +197,5 @@ class SpotOrderbookVM { return spread.div(maxBuyPrice).times(100).toFormat(2); } } + +export default SpotOrderBookStore; diff --git a/src/stores/SwapStore.ts b/src/stores/SwapStore.ts index 907e6fbb..75627c40 100644 --- a/src/stores/SwapStore.ts +++ b/src/stores/SwapStore.ts @@ -1,4 +1,4 @@ -import { FulfillOrderManyParams, GetOrdersParams, LimitType, OrderType } from "@compolabs/spark-orderbook-ts-sdk"; +import { AssetType, GetOrdersParams, LimitType, OrderType } from "@compolabs/spark-orderbook-ts-sdk"; import { autorun, makeAutoObservable, reaction } from "mobx"; import { FuelNetwork } from "@src/blockchain"; @@ -90,6 +90,15 @@ class SwapStore { : "0"; } + getMarketPair = (baseAsset: Token, quoteToken: Token) => { + const { tradeStore } = this.rootStore; + return tradeStore.spotMarkets.find( + (el) => + (el.baseToken.assetId === baseAsset.assetId && el.quoteToken.assetId === quoteToken.assetId) || + (el.baseToken.assetId === quoteToken.assetId && el.quoteToken.assetId === baseAsset.assetId), + ); + }; + updateTokens() { const newTokens = this.fetchNewTokens(); this.tokens = newTokens; @@ -124,7 +133,7 @@ class SwapStore { fetchExchangeFeeDebounce = _.debounce(this.fetchExchangeFee, 250); swapTokens = async ({ slippage }: { slippage: number }): Promise => { - const { notificationStore, tradeStore, oracleStore } = this.rootStore; + const { notificationStore, tradeStore } = this.rootStore; const baseToken = tradeStore.market?.baseToken; const isBuy = baseToken?.assetId === this.buyToken.assetId; const bcNetwork = FuelNetwork.getInstance(); @@ -134,21 +143,44 @@ class SwapStore { status: ["Active"], }; - const sellOrders = await bcNetwork!.fetchSpotOrders({ + const orders = await bcNetwork!.fetchSpotOrders({ ...params, orderType: !isBuy ? OrderType.Buy : OrderType.Sell, }); // TODO: check if there is enough price sum to fulfill the order - const formattedAmount = BN.parseUnits(this.payAmount, this.sellToken.decimals).toString(); const formattedVolume = BN.parseUnits(this.receiveAmount, this.buyToken.decimals).toString(); + const decimalToken = isBuy ? this.buyToken.decimals : this.sellToken.decimals; + const depositAmountWithFee = BN.parseUnits(this.exchangeFee, decimalToken).plus( + BN.parseUnits(this.rootStore.tradeStore.matcherFee, decimalToken), + ); - const order: FulfillOrderManyParams = { - amount: isBuy ? formattedVolume : formattedAmount, + const pair = this.getMarketPair(this.buyToken, this.sellToken); + if (!pair) return true; + let total = new BN(isBuy ? formattedAmount : formattedVolume); + let spend = BN.ZERO; + const orderList = orders + .map((el) => { + if (total.toNumber() < 0) { + return null; + } + spend = spend.plus(el.currentAmount); + total = total.minus(el.currentQuoteAmount); + return el; + }) + .filter((el) => el !== null); + + const order = { orderType: isBuy ? OrderType.Buy : OrderType.Sell, + amount: isBuy ? formattedVolume : formattedAmount, + price: orderList[orderList.length - 1].price.toString(), + amountToSpend: isBuy ? formattedVolume : formattedAmount, + amountFee: depositAmountWithFee.toString(), + depositAssetId: isBuy ? pair?.quoteToken.assetId : pair?.baseToken.assetId, + feeAssetId: pair?.quoteToken.assetId, + assetType: isBuy ? AssetType.Quote : AssetType.Base, limitType: LimitType.FOK, - price: sellOrders[sellOrders.length - 1].price.toString(), - orders: sellOrders.map((el) => el.id), + orders: orderList.map((el) => el.id), slippage: slippage.toString(), }; @@ -163,7 +195,8 @@ class SwapStore { ).toSignificant(2); try { - const tx = await bcNetwork.swapTokens(order); + const marketContracts = CONFIG.APP.markets.map((el) => el.contractId); + const tx = await bcNetwork.fulfillOrderManyWithDeposit(order, marketContracts); notificationStore.success({ text: getActionMessage(ACTION_MESSAGE_TYPE.CREATING_SWAP)( amountFormatted, @@ -171,7 +204,7 @@ class SwapStore { volumeFormatted, this.buyToken.symbol, ), - hash: tx.transactionId, + hash: "tx.transactionId,", }); return true; } catch (error: any) { @@ -230,11 +263,11 @@ class SwapStore { return [ { assetId: market.baseAssetId, - balance: new BN(marketBalance?.locked?.base ?? 0), + balance: new BN(marketBalance?.liquid?.base ?? 0), }, { assetId: market.quoteAssetId, - balance: new BN(marketBalance?.locked?.quote ?? 0), + balance: new BN(marketBalance?.liquid?.quote ?? 0), }, ]; }) diff --git a/src/stores/index.ts b/src/stores/index.ts index 4248ee9b..e2347df2 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -10,6 +10,7 @@ import QuickAssetsStore from "./QuickAssetsStore"; import RootStore from "./RootStore"; import SettingsStore from "./SettingsStore"; import TradeStore from "./TradeStore"; +import SpotOrderBookStore from "./SpotOrderBookStore"; export { AccountStore, @@ -20,6 +21,7 @@ export { QuickAssetsStore, RootStore, SettingsStore, + SpotOrderBookStore, storesContext, // SpotOrdersStore, TradeStore,