diff --git a/daemon/src/maker_cfd.rs b/daemon/src/maker_cfd.rs index 15f9860..54ef783 100644 --- a/daemon/src/maker_cfd.rs +++ b/daemon/src/maker_cfd.rs @@ -525,7 +525,18 @@ impl Actor { } }; - // 2. Insert CFD in DB + // 2. check if order has acceptable amounts + if quantity < current_order.min_quantity || quantity > current_order.max_quantity { + self.takers + .do_send_async(maker_inc_connections::TakerMessage { + taker_id, + command: TakerCommand::NotifyOrderRejected { id: order_id }, + }) + .await?; + return Ok(()); + } + + // 3. Insert CFD in DB let cfd = Cfd::new( current_order.clone(), quantity, @@ -541,7 +552,7 @@ impl Actor { self.cfd_feed_actor_inbox .send(load_all_cfds(&mut conn).await?)?; - // 3. Remove current order + // 4. Remove current order self.current_order_id = None; self.takers .do_send_async(maker_inc_connections::BroadcastOrder(None)) diff --git a/daemon/src/model.rs b/daemon/src/model.rs index 2d62e2a..24d0f4d 100644 --- a/daemon/src/model.rs +++ b/daemon/src/model.rs @@ -13,7 +13,7 @@ use uuid::Uuid; pub mod cfd; -#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, PartialOrd)] pub struct Usd(pub Decimal); impl Usd { diff --git a/frontend/src/TakerApp.tsx b/frontend/src/TakerApp.tsx index e5ae509..4cb0c1e 100644 --- a/frontend/src/TakerApp.tsx +++ b/frontend/src/TakerApp.tsx @@ -15,7 +15,7 @@ import { useToast, VStack, } from "@chakra-ui/react"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useAsync } from "react-async"; import { useEventSource } from "react-sse-hooks"; import { CfdTable } from "./components/cfdtables/CfdTable"; @@ -58,6 +58,8 @@ async function getMargin(payload: MarginRequestPayload): Promise } export default function App() { + const toast = useToast(); + document.title = "Hermes Taker"; let source = useEventSource({ source: "/api/feed" }); @@ -67,9 +69,11 @@ export default function App() { const order = useLatestEvent(source, "order", intoOrder); const walletInfo = useLatestEvent(source, "wallet"); - const toast = useToast(); let [quantity, setQuantity] = useState("0"); let [margin, setMargin] = useState("0"); + let [userHasEdited, setUserHasEdited] = useState(false); + + let quantityToShow = userHasEdited ? quantity : (order?.min_quantity.toString() || "0"); let { run: calculateMargin } = useAsync({ deferFn: async ([payload]: any[]) => { @@ -90,6 +94,23 @@ export default function App() { }, }); + useEffect(() => { + if (!order) { + return; + } + let quantity = quantityToShow ? Number.parseFloat(quantityToShow) : 0; + let payload: MarginRequestPayload = { + leverage: order.leverage, + price: order.price, + quantity, + }; + calculateMargin(payload); + }, // Eslint demands us to include `calculateMargin` in the list of dependencies. + // We don't want that as we will end up in an endless loop. It is safe to ignore `calculateMargin` because + // nothing in `calculateMargin` depends on outside values, i.e. is guaranteed to be stable. + // eslint-disable-next-line react-hooks/exhaustive-deps + [margin, quantityToShow, order]); + const format = (val: any) => `$` + val; const parse = (val: any) => val.replace(/^\$/, ""); @@ -135,6 +156,7 @@ export default function App() { Quantity: { + setUserHasEdited(true); setQuantity(parse(valueString)); if (!order) { return; @@ -147,7 +169,9 @@ export default function App() { }; calculateMargin(payload); }} - value={format(quantity)} + value={format(quantityToShow)} + min={order?.min_quantity} + max={order?.max_quantity} /> Margin in BTC: diff --git a/frontend/src/components/CurrencyInputField.tsx b/frontend/src/components/CurrencyInputField.tsx index 47df0a3..4b12313 100644 --- a/frontend/src/components/CurrencyInputField.tsx +++ b/frontend/src/components/CurrencyInputField.tsx @@ -11,18 +11,27 @@ import React from "react"; interface CurrencyInputFieldProps { onChange: any; value: StringOrNumber | undefined; + min?: number; + max?: number; } export default function CurrencyInputField( { onChange, value, + min, + max, }: CurrencyInputFieldProps, ) { + let minAmount = min || 0; + let maxAmount = max || Number.MAX_SAFE_INTEGER; return (