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

[ECO-2353] Rearrange items on the market page #325

Merged
merged 16 commits into from
Nov 14, 2024
Merged
Original file line number Diff line number Diff line change
@@ -368,8 +368,8 @@ export const Chart = (props: ChartContainerProps) => {
});

return (
<div className="relative w-full">
<div className="absolute left-0 top-0 flex h-full w-full animate-fadeIn items-center justify-center text-center font-roboto-mono text-xl font-light leading-6 text-neutral-500 opacity-0 delay-[2000]">
<div className="relative w-full h-[420px]">
<div className="absolute left-0 top-0 flex h-full w-full animate-fadeIn items-center justify-center text-center font-roboto-mono text-sm font-light leading-6 text-neutral-500 opacity-0 delay-[2000]">
<div>
{showErrorMessage ? (
<>
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ import DesktopGrid from "./components/desktop-grid";
import MobileGrid from "./components/mobile-grid";
import { type EmojicoinProps } from "./types";
import { useEventStore } from "context/event-store-context";
import TextCarousel from "components/text-carousel/TextCarousel";
import MainInfo from "./components/main-info/MainInfo";
import { useReliableSubscribe } from "@hooks/use-reliable-subscribe";
import { type BrokerEvent } from "@/broker/types";
@@ -35,7 +34,6 @@ const ClientEmojicoinPage = (props: EmojicoinProps) => {

return (
<Box pt="85px">
<TextCarousel />
<MainInfo data={props.data} />
{isTablet || isMobile ? <MobileGrid data={props.data} /> : <DesktopGrid data={props.data} />}
</Box>
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import React, { Suspense } from "react";

import { Text } from "components";

import { translationFunction } from "context/language-context";

import {
StyledContentWrapper,
StyledContentColumn,
StyledContentHeader,
StyledBlockWrapper,
StyledContentInner,
StyledBlock,
@@ -16,22 +11,16 @@ import {
import ChatBox from "../chat/ChatBox";
import TradeHistory from "../trade-history";
import { type GridProps } from "../../types";
import { LiquidityButton } from "../trade-emojicoin/LiquidityButton";
import ChartContainer from "components/charts/ChartContainer";
import SwapComponent from "../trade-emojicoin/SwapComponent";
import Loading from "components/loading";

const DesktopGrid = (props: GridProps) => {
const { t } = translationFunction();

return (
<StyledContentWrapper>
<StyledContentInner>
<StyledContentColumn>
<StyledBlock
width="57%"
className="bg-black z-10 border-t border-solid border-t-dark-gray"
>
<StyledBlock width="57%" className="bg-black z-10">
<StyledBlockWrapper>
<Suspense fallback={<Loading numEmojis={20} />}>
<ChartContainer
@@ -44,8 +33,6 @@ const DesktopGrid = (props: GridProps) => {
</StyledBlockWrapper>
</StyledBlock>
<StyledBlock width="43%">
<LiquidityButton data={props.data} />

<StyledBlockWrapper>
<SwapComponent
emojicoin={props.data.symbolData.symbol}
@@ -59,24 +46,12 @@ const DesktopGrid = (props: GridProps) => {

<StyledContentColumn>
<StyledBlock width="57%">
<StyledContentHeader>
<Text textScale="pixelHeading3" color="lightGray" textTransform="uppercase">
{t("Trade History")}
</Text>
</StyledContentHeader>

<StyledBlockWrapper>
<TradeHistory data={props.data} />
</StyledBlockWrapper>
</StyledBlock>

<StyledBlock width="43%">
<StyledContentHeader>
<Text textScale="pixelHeading3" color="lightGray" textTransform="uppercase">
{t("Chat")}
</Text>
</StyledContentHeader>

<StyledBlockWrapper>
<ChatBox data={props.data} />
</StyledBlockWrapper>
Original file line number Diff line number Diff line change
@@ -20,6 +20,19 @@ export const StyledContentColumn = styled(Flex)`

border-left: 1px solid ${({ theme }) => theme.colors.darkGray};
border-right: 1px solid ${({ theme }) => theme.colors.darkGray};
position: relative;

&:after,
&:before {
content: "";
display: block;
position: absolute;
width: 200vw;
background-color: ${({ theme }) => theme.colors.darkGray};
height: 1px;
transform: translateX(-50%);
z-index: 10;
}
`;

export const StyledContentHeader = styled.div`
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useEffect, useState } from "react";

import { translationFunction } from "context/language-context";
import { type MainInfoProps } from "../../types";
import { useEventStore } from "context/event-store-context";
import { useLabelScrambler } from "components/pages/home/components/table-card/animation-variants/event-variants";
import { motion } from "framer-motion";
import { getBondingCurveProgress } from "utils/bonding-curve";
import Button from "components/button";
import Link from "next/link";
import { ROUTES } from "router/routes";
import { useThemeContext } from "context";

const statsTextClasses = "uppercase ellipses font-forma text-[24px]";

const BondingProgress = ({ data }: MainInfoProps) => {
const { t } = translationFunction();
const { theme } = useThemeContext();

const marketEmojis = data.symbolEmojis;
const stateEvents = useEventStore((s) => s.getMarket(marketEmojis)?.stateEvents ?? []);

const [bondingProgress, setBondingProgress] = useState(
getBondingCurveProgress(data.state.state.clammVirtualReserves.quote)
);

useEffect(() => {
if (stateEvents.length === 0) return;
const event = stateEvents.at(0);
if (event) {
setBondingProgress(getBondingCurveProgress(event.state.clammVirtualReserves.quote));
}
}, [stateEvents]);

const { ref: bondingCurveRef } = useLabelScrambler(`${bondingProgress.toFixed(2)}%`, "%");

return (
<div className="flex flex-col w-fit">
<div className="flex justify-between gap-[8px] mb-[.2em]">
<div className={statsTextClasses + " text-light-gray font-pixelar text-[32px]"}>
{t("Bonding progress:")}
</div>
<div className={statsTextClasses + " text-white"}>
<div
className="text-ec-blue font-pixelar text-[32px] text-end min-w-[3.5em]"
ref={bondingCurveRef}
>
{bondingProgress.toFixed(2)}%
</div>
</div>
</div>
{bondingProgress >= 100 ? (
<Link
href={{
pathname: ROUTES.pools,
query: { pool: data.emojis.map((e) => e.emoji).join("") },
}}
>
<Button scale="lg">{t("Provide liquidity")}</Button>
</Link>
) : (
<div
style={{
width: "100%",
border: `1px solid ${theme.colors.darkGray}`,
padding: "0.15em",
borderRadius: "5px",
}}
>
<motion.div
initial={{ width: "0%" }}
animate={{ width: `${Math.max(bondingProgress, 1).toFixed(2)}%` }}
// Allow the page to load first so that users can actually see the animation.
transition={{ delay: 0.3 }}
style={{
height: "0.8em",
background: theme.colors.econiaBlue,
borderRadius: "3px",
}}
></motion.div>
</div>
)}
</div>
);
};

export default BondingProgress;
Original file line number Diff line number Diff line change
@@ -4,21 +4,19 @@ import { translationFunction } from "context/language-context";
import { toCoinDecimalString } from "lib/utils/decimals";
import AptosIconBlack from "components/svg/icons/AptosBlack";
import { type MainInfoProps } from "../../types";
import { emojisToName } from "lib/utils/emojis-to-name-or-symbol";
import { useEventStore } from "context/event-store-context";
import { useLabelScrambler } from "components/pages/home/components/table-card/animation-variants/event-variants";
import { isMarketStateModel } from "@sdk/indexer-v2/types";
import BondingProgress from "./BondingProgress";
import { useThemeContext } from "context";
import { useMatchBreakpoints } from "@hooks/index";
import { Emoji } from "utils/emoji";

const innerWrapper = `flex flex-col md:flex-row justify-around w-full max-w-[1362px] px-[30px] lg:px-[44px] py-[17px]
md:py-[37px] xl:py-[68px]`;
const headerWrapper =
"flex flex-row md:flex-col md:justify-between gap-[12px] md:gap-[4px] w-full md:w-[58%] xl:w-[65%] mb-[8px]";
const statsWrapper = "flex flex-col w-full md:w-[42%] xl:w-[35%] mt-[-8px]";
const statsTextClasses = "display-6 md:display-4 uppercase ellipses font-forma";
const statsTextClasses = "uppercase ellipses font-forma text-[24px]";

const MainInfo = ({ data }: MainInfoProps) => {
const { t } = translationFunction();
const { theme } = useThemeContext();

const marketEmojis = data.symbolEmojis;
const stateEvents = useEventStore((s) => s.getMarket(marketEmojis)?.stateEvents ?? []);
@@ -41,27 +39,48 @@ const MainInfo = ({ data }: MainInfoProps) => {
}
}, [stateEvents]);

const { ref: marketCapRef } = useLabelScrambler(marketCap);
const { ref: dailyVolumeRef } = useLabelScrambler(dailyVolume);
const { ref: allTimeVolumeRef } = useLabelScrambler(allTimeVolume);
const { ref: marketCapRef } = useLabelScrambler(toCoinDecimalString(marketCap, 2));
const { ref: dailyVolumeRef } = useLabelScrambler(toCoinDecimalString(dailyVolume, 2));
const { ref: allTimeVolumeRef } = useLabelScrambler(toCoinDecimalString(allTimeVolume, 2));

return (
<div className="flex justify-center">
<div className={innerWrapper}>
<div className={headerWrapper}>
<div
title={emojisToName(data.emojis).toUpperCase()}
className=" text-white uppercase ellipses display-4 font-forma-bold md:display-2"
>
{emojisToName(data.emojis)}
</div>
const { isMobile } = useMatchBreakpoints();

<Emoji className="text-[24px] md:display-2 my-auto text-white" emojis={data.emojis} />
</div>
return (
<div
className="flex justify-center mt-[10px]"
style={{
borderTop: `1px solid ${theme.colors.darkGray}`,
}}
>
<div
style={
isMobile
? {
display: "flex",
gap: "1em",
flexDirection: "column",
width: "100%",
padding: "40px",
}
: {
display: "grid",
gridTemplateColumns: "57fr 43fr",
width: "100%",
maxWidth: "1362px",
padding: "40px",
}
}
>
<Emoji
className="text-[24px] text-center md:display-2 my-auto text-white"
emojis={data.emojis}
/>

<div className={statsWrapper}>
<div className="flex gap-[8px]">
<div className={statsTextClasses + " text-light-gray"}>{t("Mkt. Cap:")}</div>
<div
className={`flex flex-col mt-[-8px] ${isMobile ? "m-auto" : "ml-[4em]"} w-fit gap-[2px]`}
>
<div className="flex justify-between">
<div className={statsTextClasses + " text-light-gray"}>{t("Market Cap:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
<div ref={marketCapRef}>{toCoinDecimalString(marketCap, 2)}</div>
@@ -71,7 +90,7 @@ const MainInfo = ({ data }: MainInfoProps) => {
</div>
</div>

<div className="flex gap-[8px]">
<div className="flex justify-between">
<div className={statsTextClasses + " text-light-gray"}>{t("24 hour vol:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
@@ -82,7 +101,7 @@ const MainInfo = ({ data }: MainInfoProps) => {
</div>
</div>

<div className="flex gap-[8px]">
<div className="flex justify-between">
<div className={statsTextClasses + " text-light-gray"}>{t("All-time vol:")}</div>
<div className={statsTextClasses + " text-white"}>
<div className="flex flex-row justify-center items-center">
@@ -92,6 +111,10 @@ const MainInfo = ({ data }: MainInfoProps) => {
</div>
</div>
</div>

<div className="mt-[.6em]">
<BondingProgress data={data} />
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import { toActualCoinDecimals, toDisplayCoinDecimals } from "lib/utils/decimals"
import { useScramble } from "use-scramble";
import { useSimulateSwap } from "lib/hooks/queries/use-simulate-swap";
import { useEventStore } from "context/event-store-context";
import { useMatchBreakpoints, useTooltip } from "@hooks/index";
import { useTooltip } from "@hooks/index";
import { useSearchParams } from "next/navigation";
import { translationFunction } from "context/language-context";
import { useAptos } from "context/wallet-context/AptosContextProvider";
@@ -69,7 +69,6 @@ export default function SwapComponent({
presetInputAmount !== null &&
presetInputAmount !== "" &&
!Number.isNaN(Number(presetInputAmount));
const { isDesktop } = useMatchBreakpoints();
const [inputAmount, setInputAmount] = useState(
toActualCoinDecimals({ num: presetInputAmountIsValid ? presetInputAmount! : "1" })
);
@@ -177,149 +176,149 @@ export default function SwapComponent({

const { theme } = useThemeContext();

const { targetRef, tooltip } = useTooltip(
const { targetRef, tooltip: gearTooltip } = useTooltip(
<TradeOptions
onMaxSlippageUpdate={() => setMaxSlippage(getMaxSlippageSettings().maxSlippage)}
/>,
{
placement: "bottom",
customStyles: getTooltipStyles(theme),
trigger: "click",
tooltipOffset: [100, 10],
}
);

return (
<>
<Column className="relative w-full max-w-[414px] h-full justify-center">
<Flex flexDirection="row" justifyContent="space-between">
<div
className={`${isDesktop ? "heading-1" : "heading-2"} md:heading-1 text-white uppercase pb-[17px]`}
>
{t("Trade Emojicoin")}
</div>
<FlexGap flexDirection="row" gap="5px">
{isSell ? (
<>
<EmojiPill
emoji="nauseated face"
description="Sell 50%"
onClick={() => {
setInputAmount(emojicoinBalance / 2n);
}}
/>
<EmojiPill
emoji="face vomiting"
description="Sell 100%"
onClick={() => {
setInputAmount(emojicoinBalance);
}}
/>
</>
) : (
<>
<EmojiPill
emoji={"waxing crescent moon"}
description="Buy 25%"
onClick={() => {
setInputAmount(availableAptBalance / 4n);
}}
/>
<EmojiPill
emoji={"first quarter moon"}
description="Buy 50%"
onClick={() => {
setInputAmount(availableAptBalance / 2n);
}}
/>
<EmojiPill
emoji={"full moon"}
description="Buy 100%"
onClick={() => {
setInputAmount(availableAptBalance);
}}
/>
</>
)}
</FlexGap>
</Flex>

<SimulateInputsWrapper>
<InnerWrapper>
<Column>
<div className={grayLabel}>
{isSell ? t("You sell") : t("You pay")}
{balanceLabel}
</div>
<InputNumeric
className={inputAndOutputStyles + " bg-transparent leading-[32px]"}
value={inputAmount}
onUserInput={(v) => setInputAmount(v)}
onSubmit={() => (submit ? submit() : {})}
decimals={8}
<Column className="relative w-full max-w-[414px] justify-center">
<Flex
flexDirection="row"
justifyContent="space-between"
alignItems="center"
className="mb-[.4em]"
>
<div ref={targetRef}>
<Emoji className="cursor-pointer" emojis={emoji("gear")} />
</div>
{gearTooltip}
<FlexGap flexDirection="row" gap="5px">
{isSell ? (
<>
<EmojiPill
emoji="nauseated face"
description="Sell 50%"
onClick={() => {
setInputAmount(emojicoinBalance / 2n);
}}
/>
<EmojiPill
emoji="face vomiting"
description="Sell 100%"
onClick={() => {
setInputAmount(emojicoinBalance);
}}
/>
</Column>
{isSell ? <EmojiInputLabel emoji={emojicoin} /> : <AptosInputLabel />}
</InnerWrapper>
</>
) : (
<>
<EmojiPill
emoji={"waxing crescent moon"}
description="Buy 25%"
onClick={() => {
setInputAmount(availableAptBalance / 4n);
}}
/>
<EmojiPill
emoji={"first quarter moon"}
description="Buy 50%"
onClick={() => {
setInputAmount(availableAptBalance / 2n);
}}
/>
<EmojiPill
emoji={"full moon"}
description="Buy 100%"
onClick={() => {
setInputAmount(availableAptBalance);
}}
/>
</>
)}
</FlexGap>
</Flex>

<SimulateInputsWrapper>
<InnerWrapper>
<Column>
<div className={grayLabel}>
{isSell ? t("You sell") : t("You pay")}
{balanceLabel}
</div>
<InputNumeric
className={inputAndOutputStyles + " bg-transparent leading-[32px]"}
value={inputAmount}
onUserInput={(v) => setInputAmount(v)}
onSubmit={() => (submit ? submit() : {})}
decimals={8}
/>
</Column>
{isSell ? <EmojiInputLabel emoji={emojicoin} /> : <AptosInputLabel />}
</InnerWrapper>

<FlipInputsArrow
onClick={() => {
setInputAmount(outputAmount);
// This is done as to not display an old value if the swap simulation fails.
setOutputAmount(0n);
setPrevious(0n);
setIsSell((v) => !v);
}}
/>
<FlipInputsArrow
onClick={() => {
setInputAmount(outputAmount);
// This is done as to not display an old value if the swap simulation fails.
setOutputAmount(0n);
setPrevious(0n);
setIsSell((v) => !v);
}}
/>

<InnerWrapper>
<Column>
<div className={grayLabel}>{t("You receive")}</div>
<div className="h-[22px] w-full">
<div
onClick={() => setIsSell((v) => !v)}
className={inputAndOutputStyles + " mt-[8px] ml-[1px] cursor-pointer"}
style={{ opacity: isLoading ? 0.6 : 1 }}
>
{/* Scrambled swap result output below. */}
<div ref={ref}></div>
</div>
<InnerWrapper>
<Column>
<div className={grayLabel}>{t("You receive")}</div>
<div className="h-[22px] w-full">
<div
onClick={() => setIsSell((v) => !v)}
className={inputAndOutputStyles + " mt-[8px] ml-[1px] cursor-pointer"}
style={{ opacity: isLoading ? 0.6 : 1 }}
>
{/* Scrambled swap result output below. */}
<div ref={ref}></div>
</div>
</Column>
{isSell ? <AptosInputLabel /> : <EmojiInputLabel emoji={emojicoin} />}
</InnerWrapper>
</SimulateInputsWrapper>
<div className="flex flex-row justify-between py-[10px]">
<div ref={targetRef}>
<Emoji className="cursor-pointer" emojis={emoji("gear")} />
</div>
{tooltip}
<div className="text-dark-gray">
<span className="text-xl leading-[0]">
{gasCost === null ? "~" : ""}
{toDisplayCoinDecimals({
num: gasCost !== null ? gasCost.toString() : SWAP_GAS_COST.toString(),
decimals: 4,
})}{" "}
APT
</span>{" "}
<Emoji emojis={emoji("fuel pump")} />
</div>
</div>
</Column>
{isSell ? <AptosInputLabel /> : <EmojiInputLabel emoji={emojicoin} />}
</InnerWrapper>
</SimulateInputsWrapper>
<div className="flex flex-row justify-between py-[10px]">
<div></div>
<div className="text-dark-gray">
<span className="text-xl leading-[0]">
{gasCost === null ? "~" : ""}
{toDisplayCoinDecimals({
num: gasCost !== null ? gasCost.toString() : SWAP_GAS_COST.toString(),
decimals: 4,
})}{" "}
APT
</span>{" "}
<Emoji emojis={emoji("fuel pump")} />
</div>
</div>

<Row className="justify-center mt-[14px]">
<SwapButton
inputAmount={inputAmount}
marketAddress={marketAddress}
isSell={isSell}
setSubmit={setSubmit}
// Disable the button if and only if the balance has been fetched and isn't sufficient *and*
// the user is connected.
disabled={!sufficientBalance && !isLoading && !!account}
symbol={emojicoin}
minOutputAmount={minOutputAmount}
/>
</Row>
</Column>
</>
<Row className="justify-center mt-[14px]">
<SwapButton
inputAmount={inputAmount}
marketAddress={marketAddress}
isSell={isSell}
setSubmit={setSubmit}
// Disable the button if and only if the balance has been fetched and isn't sufficient *and*
// the user is connected.
disabled={!sufficientBalance && !isLoading && !!account}
symbol={emojicoin}
minOutputAmount={minOutputAmount}
/>
</Row>
</Column>
);
}
Original file line number Diff line number Diff line change
@@ -51,9 +51,9 @@ const MainCard = (props: MainCardProps) => {
}, []);
/* eslint-enable react-hooks/exhaustive-deps */

const { ref: marketCapRef } = useLabelScrambler(marketCap);
const { ref: dailyVolumeRef } = useLabelScrambler(dailyVolume);
const { ref: allTimeVolumeRef } = useLabelScrambler(allTimeVolume);
const { ref: marketCapRef } = useLabelScrambler(toCoinDecimalString(marketCap, 2));
const { ref: dailyVolumeRef } = useLabelScrambler(toCoinDecimalString(dailyVolume, 2));
const { ref: allTimeVolumeRef } = useLabelScrambler(toCoinDecimalString(allTimeVolume, 2));

return (
<Flex justifyContent="center" width="100%" my={{ _: "20px", tablet: "70px" }} maxWidth="1872px">
Original file line number Diff line number Diff line change
@@ -103,8 +103,14 @@ const TableCard = ({
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [animations, runAnimationSequence]);

const { ref: marketCapRef } = useLabelScrambler(marketCap, " APT");
const { ref: dailyVolumeRef } = useLabelScrambler(dailyVolume, " APT");
const { ref: marketCapRef } = useLabelScrambler(
toCoinDecimalString(marketCap.toString(), 2),
" APT"
);
const { ref: dailyVolumeRef } = useLabelScrambler(
toCoinDecimalString(dailyVolume.toString(), 2),
" APT"
);

const { curr, prev, variant, displayIndex, layoutDelay } = useMemo(() => {
const { curr, prev } = calculateGridData({
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { type AnyNumberString } from "@sdk-types";
import { Trigger } from "@sdk/const";
import {
type ChatEventModel,
@@ -12,8 +11,6 @@ import {
type MarketRegistrationEventModel,
type SwapEventModel,
} from "@sdk/indexer-v2/types";
import type Big from "big.js";
import { toCoinDecimalString } from "lib/utils/decimals";
import { ECONIA_BLUE, GREEN, PINK, WHITE } from "theme/colors";
import { useScramble } from "use-scramble";

@@ -130,10 +127,10 @@ export const scrambleConfig = {
overdrive: false,
overflow: true,
speed: 0.6,
playOnMount: false,
playOnMount: true,
};

export const useLabelScrambler = (value: AnyNumberString | Big, suffix: string = "") => {
export const useLabelScrambler = (value: string, suffix: string = "") => {
// Ignore all characters in the suffix, as long as they are not numbers.
const ignore = ["."];
const numberSet = new Set("0123456789");
@@ -145,7 +142,7 @@ export const useLabelScrambler = (value: AnyNumberString | Big, suffix: string =
}

const scrambler = useScramble({
text: toCoinDecimalString(value.toString(), 2) + suffix,
text: value,
...scrambleConfig,
ignore,
});
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ export const TradeOptions = ({ onMaxSlippageUpdate }: TradeOptionsProps) => {
<div
className={
`${maxSlippageMode === "custom" ? "opacity-100" : "opacity-30"} ` +
"text-black border-black flex flex-row border-[1px] p-[.2rem] rounded border-solid"
"text-black border-black flex flex-row items-center border-[1px] rounded border-solid leading-4"
}
>
<InputNumeric
@@ -79,7 +79,7 @@ export const TradeOptions = ({ onMaxSlippageUpdate }: TradeOptionsProps) => {
decimals={2}
className="w-[4rem] bg-transparent text-right outline-none"
/>
<span className="ml-[1px] mt-[2px] mr-[2px] block">%</span>
<span className="ml-[1px] mr-[2px] block">%</span>
</div>
</div>
</DropdownMenuInner>
1 change: 1 addition & 0 deletions src/typescript/frontend/src/utils/bonding-curve.ts
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@ export const isInBondingCurve = (
* @returns the percentage of the bonding curve progress
*/
export const getBondingCurveProgress = (clammVirtualReservesQuote: number | bigint) => {
if (BigInt(clammVirtualReservesQuote) === 0n) return 100;
return Big(clammVirtualReservesQuote.toString())
.sub(QUOTE_VIRTUAL_FLOOR.toString())
.div(QUOTE_REAL_CEILING.toString())

Unchanged files with check annotations Beta

const res1text = await res1.text();
expect(res1text).toMatch(numericRegex);
expect(res1headers[NEXTJS_CACHE_HEADER]).toMatch("HIT");

Check failure on line 36 in src/typescript/frontend/tests/e2e/example.spec.ts

GitHub Actions / playwright-tests

[firefox] › example.spec.ts:10:5 › api test route

1) [firefox] › example.spec.ts:10:5 › api test route ───────────────────────────────────────────── Error: expect(received).toMatch(expected) Matcher error: received value must be a string Received has value: undefined 34 | 35 | expect(res1text).toMatch(numericRegex); > 36 | expect(res1headers[NEXTJS_CACHE_HEADER]).toMatch("HIT"); | ^ 37 | 38 | // Query a second time after a second. 39 | // at /home/runner/work/emojicoin-dot-fun/emojicoin-dot-fun/src/typescript/frontend/tests/e2e/example.spec.ts:36:44

Check failure on line 36 in src/typescript/frontend/tests/e2e/example.spec.ts

GitHub Actions / playwright-tests

[firefox] › example.spec.ts:10:5 › api test route

1) [firefox] › example.spec.ts:10:5 › api test route ───────────────────────────────────────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toMatch(expected) Matcher error: received value must be a string Received has value: undefined 34 | 35 | expect(res1text).toMatch(numericRegex); > 36 | expect(res1headers[NEXTJS_CACHE_HEADER]).toMatch("HIT"); | ^ 37 | 38 | // Query a second time after a second. 39 | // at /home/runner/work/emojicoin-dot-fun/emojicoin-dot-fun/src/typescript/frontend/tests/e2e/example.spec.ts:36:44

Check failure on line 36 in src/typescript/frontend/tests/e2e/example.spec.ts

GitHub Actions / playwright-tests

[firefox] › example.spec.ts:10:5 › api test route

1) [firefox] › example.spec.ts:10:5 › api test route ───────────────────────────────────────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toMatch(expected) Matcher error: received value must be a string Received has value: undefined 34 | 35 | expect(res1text).toMatch(numericRegex); > 36 | expect(res1headers[NEXTJS_CACHE_HEADER]).toMatch("HIT"); | ^ 37 | 38 | // Query a second time after a second. 39 | // at /home/runner/work/emojicoin-dot-fun/emojicoin-dot-fun/src/typescript/frontend/tests/e2e/example.spec.ts:36:44
// Query a second time after a second.
//