Skip to content

Commit

Permalink
feat: add max balance amount and minor ui refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
yvesfracari committed Oct 24, 2024
1 parent 42f42cf commit 2fe7a70
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 64 deletions.
4 changes: 2 additions & 2 deletions apps/deposit-pool/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ export default function Page() {
PoolItemInfo={PoolItemInfo}
pools={pools || []}
selectedPool={selectedPool}
isCheckDetailsCentered={false}
isCheckDetailsCentered={true}
/>
{selectedPool && (
<div className="mt-2">
<div className="flex flex-col justify-center mt-2 w-full">
<PoolForm pool={selectedPool} />
</div>
)}
Expand Down
20 changes: 11 additions & 9 deletions apps/deposit-pool/src/components/PoolForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function PoolForm({ pool }: { pool: IPool | undefined }) {
}, [poolBalances, tokenPrices, amounts]);

const updateTokenAmounts = useCallback(
(amount: number, address: Address) => {
(amount: string, address: Address) => {
if (!poolBalances || !tokenPrices || !pool) return;

const proportionalAmounts = calculateProportionalTokenAmounts({
Expand All @@ -67,9 +67,11 @@ export function PoolForm({ pool }: { pool: IPool | undefined }) {
if (address.toLowerCase() === tokenAmountAddress) continue;

const tokenAmountKey = `amounts.${tokenAmountAddress}` as const;
const calculatedAmount = Number(
formatUnits(tokenAmount.rawAmount, tokenAmount.decimals)
const calculatedAmount = formatUnits(
tokenAmount.rawAmount,
tokenAmount.decimals
);

setValue(tokenAmountKey, calculatedAmount);
}

Expand All @@ -88,9 +90,9 @@ export function PoolForm({ pool }: { pool: IPool | undefined }) {
);

return (
<div className="flex flex-col gap-2">
<Label className="block text-sm">Add liquidity</Label>
<div className="flex flex-col gap-2 bg-muted text-muted-foreground rounded-xl p-2">
<div className="flex flex-col w-full items-center gap-1">
<Label className="block text-md mt-1">Add liquidity</Label>
<div className="flex flex-col gap-2">
{poolBalances.map((poolBalance, index) => (
<TokenAmountInput
key={poolBalance.token.address}
Expand All @@ -100,17 +102,17 @@ export function PoolForm({ pool }: { pool: IPool | undefined }) {
/>
))}
</div>
<div className="flex flex-row justify-between border border-muted px-5 py-2 mb-3 rounded-xl text-md">
<div className="flex w-full flex-row justify-between border border-muted px-5 py-2 mb-3 rounded-xl text-md">
<span>Total</span>
<span className="text-right">
${totalUsd >= 0 ? formatNumber(totalUsd, 2) : "0"}
</span>
</div>
<Button
type="submit"
className="my-2 rounded-xl text-lg min-h-[58px] font-semibold"
className="my-2 rounded-xl text-lg min-h-[58px] font-semibold w-full"
loading={isSubmitting}
disabled={!referenceAmount || referenceAmount <= 0}
disabled={!referenceAmount || referenceAmount === "0"}
loadingText="Creating hook..."
>
{context?.hookToEdit ? "Update post-hook" : "Add post-hook"}
Expand Down
117 changes: 79 additions & 38 deletions apps/deposit-pool/src/components/TokenAmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import {
type IBalance,
type IPool,
Spinner,
TokenLogoWithWeight,
useIFrameContext,
useReadTokenContract,
} from "@bleu/cow-hooks-ui";
import { Button, Input, Label, formatNumber } from "@bleu/ui";
import { Button, Input, cn, formatNumber } from "@bleu/ui";
import { useCallback, useMemo } from "react";
import { useFormContext, useFormState, useWatch } from "react-hook-form";
import { useFormContext, useWatch } from "react-hook-form";
import { type Address, formatUnits } from "viem";
import { usePoolBalance } from "#/hooks/usePoolBalance";
import type { FormType } from "#/types";
import { calculateProportionalTokenAmounts, getTokenPrice } from "#/utils/math";

export function TokenAmountInput({
poolBalance,
Expand All @@ -20,9 +16,9 @@ export function TokenAmountInput({
}: {
poolBalance: IBalance;
tokenPrice?: number;
updateTokenAmounts: (amount: number, address: Address) => void;
updateTokenAmounts: (amount: string, address: Address) => void;
}) {
const { register, control } = useFormContext<FormType>();
const { register, control, setValue } = useFormContext<FormType>();

const amount = useWatch({
control,
Expand All @@ -32,53 +28,98 @@ export function TokenAmountInput({
const amountUsd = useMemo(() => {
if (!amount || !tokenPrice) return 0;

return amount * tokenPrice;
return Number(amount) * tokenPrice;
}, [amount, tokenPrice]);

const onChange = useCallback(
(amount: number) => {
(amount: string) => {
if (updateTokenAmounts) {
updateTokenAmounts(amount, poolBalance.token.address as Address);
}
},
[updateTokenAmounts, poolBalance.token.address]
);

const tokenInfo = useReadTokenContract({
tokenAddress: poolBalance.token.address as Address,
});

return (
<div className="flex flex-row justify-between items-center px-3">
<div className="grid grid-cols-3 w-full gap-2 bg-muted text-muted-foreground rounded-xl p-3">
<TokenLogoWithWeight
token={poolBalance.token}
weight={poolBalance.weight}
className="text-lg"
/>
<div className="flex flex-col gap-1 text-right">
<Input
className="bg-transparent border-transparent text-md text-right placeholder:text-foreground/50 px-0"
type="number"
placeholder="0.0"
{...register(`amounts.${poolBalance.token.address.toLowerCase()}`, {
onChange: (e) => {
onChange(Number(e.target.value));
},
})}
onKeyDown={(e) => {
if (
["Enter", "-", "e", "E", "+", "ArrowUp", "ArrowDown"].includes(
e.key
)
<Input
className="bg-transparent col-span-2 border-transparent text-xl text-right placeholder:text-foreground/50 px-0"
type="number"
placeholder="0.0"
{...register(`amounts.${poolBalance.token.address.toLowerCase()}`, {
onChange: (e) => {
onChange(e.target.value);
},
})}
onKeyDown={(e) => {
if (
["Enter", "-", "e", "E", "+", "ArrowUp", "ArrowDown"].includes(
e.key
)
e.preventDefault();
}}
onWheel={(e) => {
// @ts-ignore
e.target.blur();
}}
step={`0.${"0".repeat(poolBalance?.token?.decimals - 1)}1`}
/>
<i className="text-xs text-right font-light">
${amountUsd && amountUsd >= 0 ? formatNumber(amountUsd, 2) : "0"}
</i>
)
e.preventDefault();
}}
onWheel={(e) => {
// @ts-ignore
e.target.blur();
}}
step={`0.${"0".repeat(poolBalance?.token?.decimals - 1)}1`}
/>
<div>
{tokenInfo && (
<div className="flex gap-1">
<span
className={cn("text-xs font-normal", !tokenInfo && "sr-only")}
>
Balance{" "}
{tokenInfo &&
formatNumber(
formatUnits(
tokenInfo.userBalance || BigInt(0),
tokenInfo.tokenDecimals || 18
)
)}
</span>
{tokenInfo.userBalance &&
tokenInfo.tokenDecimals &&
formatUnits(tokenInfo.userBalance, tokenInfo.tokenDecimals) !==
amount && (
<Button
type="button"
variant="ghost"
className="rounded-sm text-xs py-0 px-1 bg-background text-foreground/50 hover:bg-primary hover:text-primary-foreground h-fit"
onClick={() => {
if (!tokenInfo.userBalance || !tokenInfo.tokenDecimals)
return;
const maxValue = formatUnits(
tokenInfo.userBalance,
tokenInfo.tokenDecimals
);
setValue(
`amounts.${poolBalance.token.address.toLowerCase()}`,
maxValue
);
onChange(maxValue);
}}
>
Max
</Button>
)}
</div>
)}
</div>
<span className="text-xs text-right font-normal col-span-2">
${amountUsd && amountUsd >= 0 ? formatNumber(amountUsd, 2) : "0"}
</span>
</div>
);
}
6 changes: 3 additions & 3 deletions apps/deposit-pool/src/contexts/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function FormContextProvider({ children }: PropsWithChildren) {

const selectedPool = useMemo(
() => pools?.find((pool) => pool.id === poolId),
[pools, poolId],
[pools, poolId]
);

const getHookInfo = useGetHookInfo(selectedPool);
Expand All @@ -34,9 +34,9 @@ export function FormContextProvider({ children }: PropsWithChildren) {
const hookInfo = await getHookInfo(data);
if (!hookInfo) return;
setHookInfo(hookInfo);
await router.push("/signing");
router.push("/signing");
},
[getHookInfo, setHookInfo, router],
[getHookInfo, setHookInfo, router]
);

return (
Expand Down
2 changes: 1 addition & 1 deletion apps/deposit-pool/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export interface SignatureStepsProps {

export type FormType = {
poolId: string;
amounts: Record<string, number>;
amounts: Record<string, string>;
referenceTokenAddress: string;
};
15 changes: 6 additions & 9 deletions apps/deposit-pool/src/utils/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export function calculateProportionalTokenAmounts({
poolBalances: IBalance[];
pool: IPool;
tokenAddress: Address;
tokenAmount: number;
tokenAmount: string;
}) {
const referenceToken = poolBalances.find(
(balance) =>
balance.token.address.toLowerCase() === tokenAddress.toLowerCase(),
balance.token.address.toLowerCase() === tokenAddress.toLowerCase()
);

if (!referenceToken) {
Expand All @@ -34,24 +34,21 @@ export function calculateProportionalTokenAmounts({
address: pool.address,
totalShares: formatUnits(
BigInt(pool.dynamicData.totalShares.toString()),
pool.decimals,
pool.decimals
) as `${number}`,
tokens: poolBalances.map((balance) => ({
address: balance.token.address.toLowerCase() as Address,
balance: formatUnits(
BigInt(balance.balance.toString()),
balance.token.decimals,
balance.token.decimals
) as `${number}`,
decimals: balance.token.decimals,
})),
},
{
address: referenceToken.token.address.toLowerCase() as Address,
decimals: referenceToken.token.decimals,
rawAmount: parseUnits(
tokenAmount.toFixed(referenceToken.token.decimals),
referenceToken.token.decimals,
),
},
rawAmount: parseUnits(tokenAmount, referenceToken.token.decimals),
}
);
}
4 changes: 2 additions & 2 deletions packages/cow-hooks-ui/src/TokenLogoWithWeight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export function TokenLogoWithWeight({
return (
<div
className={cn(
"flex items-center rounded-xl text-md py-1 px-2 gap-1 bg-background text-foreground border border-1 border-muted",
className,
"flex items-center rounded-xl text-md py-1 px-2 gap-1 bg-background text-foreground border border-1 border-muted w-fit",
className
)}
>
<div>{weight * 100}%</div>
Expand Down

0 comments on commit 2fe7a70

Please sign in to comment.