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

cap buy and sell orders by resource and lords balance #1714

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
87 changes: 66 additions & 21 deletions client/src/ui/components/trading/MarketOrderPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BattleManager } from "@/dojo/modelManager/BattleManager";
import { ProductionManager } from "@/dojo/modelManager/ProductionManager";
import { useDojo } from "@/hooks/context/DojoContext";
import { useRealm } from "@/hooks/helpers/useRealm";
import { useProductionManager } from "@/hooks/helpers/useResources";
Expand All @@ -20,7 +21,7 @@ import {
findResourceById,
} from "@bibliothecadao/eternum";
import clsx from "clsx";
import { useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { ConfirmationPopup } from "../bank/ConfirmationPopup";

export const MarketResource = ({
Expand Down Expand Up @@ -154,6 +155,8 @@ const MarketOrders = ({
offers: MarketInterface[];
isOwnStructureInBattle: boolean;
}) => {
const [updateBalance, setUpdateBalance] = useState(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good addition of the updateBalance state. This will help trigger re-renders when balances change.


const lowestPrice = useMemo(() => {
const price = offers.reduce((acc, offer) => (offer.perLords < acc ? offer.perLords : acc), Infinity);
return price === Infinity ? 0 : price;
Expand Down Expand Up @@ -185,7 +188,14 @@ const MarketOrders = ({
}`}
>
{offers.map((offer, index) => (
<OrderRow key={offer.tradeId} offer={offer} entityId={entityId} isBuy={isBuy} />
<OrderRow
key={offer.tradeId}
offer={offer}
entityId={entityId}
isBuy={isBuy}
updateBalance={updateBalance}
setUpdateBalance={setUpdateBalance}
/>
))}
{isOwnStructureInBattle && (
<div className="absolute inset-0 bg-black/50 flex items-center justify-center text-xl text-bold">
Expand Down Expand Up @@ -221,15 +231,27 @@ const OrderRowHeader = ({ resourceId, isBuy }: { resourceId?: number; isBuy: boo
);
};

const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId: ID; isBuy: boolean }) => {
const OrderRow = ({
offer,
entityId,
isBuy,
updateBalance,
setUpdateBalance,
}: {
offer: MarketInterface;
entityId: ID;
isBuy: boolean;
updateBalance: boolean;
setUpdateBalance: (value: boolean) => void;
}) => {
const { computeTravelTime } = useTravel();
const dojo = useDojo();
const {
account: { account },
setup: {
systemCalls: { cancel_order, accept_partial_order },
},
} = useDojo();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of ProductionManager to get accurate balances for Lords and resources.

const lordsManager = new ProductionManager(dojo.setup, entityId, ResourcesIds.Lords);
const lordsBalance = useMemo(() => Number(lordsManager.getResource()?.balance || 0n), [updateBalance]);

const resourceManager = new ProductionManager(dojo.setup, entityId, offer.makerGets[0].resourceId);
const resourceBalance = useMemo(() => Number(resourceManager.getResource()?.balance || 0n), [updateBalance]);

const { getRealmAddressName } = useRealm();

Expand All @@ -241,12 +263,6 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId
return battleManager.isBattleOngoing(nextBlockTimestamp!) && !battleManager.isSiege(nextBlockTimestamp!);
}, [offer, nextBlockTimestamp]);

const [inputValue, setInputValue] = useState<number>(() => {
return isBuy
? offer.makerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision
: offer.takerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision;
});

const [confirmOrderModal, setConfirmOrderModal] = useState(false);

const travelTime = useMemo(
Expand Down Expand Up @@ -282,6 +298,28 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId

const currentDefaultTick = useUIStore((state) => state.currentDefaultTick);

const resourceBalanceRatio = useMemo(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good implementation of resourceBalanceRatio and lordsBalanceRatio to cap the input value based on available balances.

() => (resourceBalance < getsDisplayNumber ? resourceBalance / getsDisplayNumber : 1),
[resourceBalance, getsDisplayNumber],
);
const lordsBalanceRatio = useMemo(
() => (lordsBalance < getTotalLords ? lordsBalance / getTotalLords : 1),
[lordsBalance, getTotalLords],
);
const [inputValue, setInputValue] = useState<number>(() => {
return isBuy
? (offer.makerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision) * resourceBalanceRatio
: (offer.takerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision) * lordsBalanceRatio;
});

useEffect(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useEffect hook is a good addition to update the input value when balance ratios change.

setInputValue(
isBuy
? (offer.makerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision) * resourceBalanceRatio
: (offer.takerGets[0].amount / EternumGlobalConfig.resources.resourcePrecision) * lordsBalanceRatio,
);
}, [resourceBalanceRatio, lordsBalanceRatio]);

const calculatedResourceAmount = useMemo(() => {
return inputValue * EternumGlobalConfig.resources.resourcePrecision;
}, [inputValue, getsDisplay, getTotalLords]);
Expand Down Expand Up @@ -325,8 +363,8 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId
setLoading(true);
setConfirmOrderModal(false);

await accept_partial_order({
signer: account,
await dojo.setup.systemCalls.accept_partial_order({
signer: dojo.account.account,
taker_id: entityId,
trade_id: offer.tradeId,
maker_gives_resources: [offer.takerGets[0].resourceId, offer.takerGets[0].amount],
Expand All @@ -336,6 +374,7 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId
} catch (error) {
console.error("Failed to accept order", error);
} finally {
setUpdateBalance(!updateBalance);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good practice to update the balance after a successful transaction.

setLoading(false);
}
};
Expand Down Expand Up @@ -382,8 +421,8 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId
<Button
onClick={async () => {
setLoading(true);
await cancel_order({
signer: account,
await dojo.setup.systemCalls.cancel_order({
signer: dojo.account.account,
trade_id: offer.tradeId,
return_resources: returnResources,
});
Expand Down Expand Up @@ -418,11 +457,17 @@ const OrderRow = ({ offer, entityId, isBuy }: { offer: MarketInterface; entityId
value={inputValue}
className="w-full col-span-3"
onChange={setInputValue}
max={getsDisplayNumber / EternumGlobalConfig.resources.resourcePrecision}
max={
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice update to the max prop of the NumberInput component to respect the balance ratios.

(getsDisplayNumber / EternumGlobalConfig.resources.resourcePrecision) *
(isBuy ? resourceBalanceRatio : lordsBalanceRatio)
}
/>
<Button
onClick={() => {
setInputValue(getsDisplayNumber / EternumGlobalConfig.resources.resourcePrecision);
setInputValue(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good update to the 'Max' button functionality to respect the new balance limits.

(getsDisplayNumber / EternumGlobalConfig.resources.resourcePrecision) *
(isBuy ? resourceBalanceRatio : lordsBalanceRatio),
);
}}
>
Max
Expand Down
Loading