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

fix: elena comments pt1 #65

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
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
21 changes: 9 additions & 12 deletions apps/withdraw-uni-v2/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import { PoolForm } from "#/components/PoolForm";
import { useFetchNewPoolCallback } from "#/hooks/useFetchNewPoolCallback";
import { useSelectedPool } from "#/hooks/useSelectedPool";
import { useUserPools } from "#/hooks/useUserPools";
import { combineTokenLists } from "#/utils/combineTokenLists";
import { isChainIdSupported } from "#/utils/uniswapSupportedChains";

export default function Page() {
const [isEditHookLoading, setIsEditHookLoading] = useState(true);
const { context } = useIFrameContext();
const { data: pools, isLoading: isLoadingPools } = useUserPools();
const { data: pools, isLoading: isLoadingPools, mutate } = useUserPools();
const { setValue, control } = useFormContext<WithdrawSchemaType>();

const poolId = useWatch({ control, name: "poolId" });
Expand All @@ -41,11 +42,7 @@ export default function Page() {
}
}, [context?.account, context?.hookToEdit, setValue]);

const {
data: selectedPool,
isLoading: isLoadingSelectedPool,
mutate: mutateSelectedPool,
} = useSelectedPool(poolId);
const selectedPool = useSelectedPool(poolId);

useEffect(() => {
if (poolId) {
Expand All @@ -67,11 +64,7 @@ export default function Page() {
return <span className="mt-10 text-center">Unsupported chain</span>;
}

if (
isLoadingPools ||
(isEditHookLoading && context.hookToEdit) ||
isLoadingSelectedPool
) {
if (isLoadingPools || (isEditHookLoading && context.hookToEdit)) {
return (
<div className="text-center mt-10 p-2">
<Spinner size="xl" />
Expand All @@ -84,7 +77,11 @@ export default function Page() {
<PoolsDropdownMenu
onSelect={(pool: IPool) => {
setValue("poolId", pool.id);
mutateSelectedPool(pool);
const chainId = context.chainId;
const poolWithChainId = { ...pool, chainId };
const poolsWithChainId = pools?.map((p) => ({ ...p, chainId })) || [];

mutate(combineTokenLists([poolWithChainId], poolsWithChainId));
}}
pools={pools || []}
PoolItemInfo={PoolItemInfo}
Expand Down
2 changes: 1 addition & 1 deletion apps/withdraw-uni-v2/src/context/withdrawHookForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function WithdrawFormContextProvider({

const poolId = useWatch({ control, name: "poolId" });

const { data: selectedPool } = useSelectedPool(poolId);
const selectedPool = useSelectedPool(poolId);

const router = useRouter();

Expand Down
58 changes: 31 additions & 27 deletions apps/withdraw-uni-v2/src/hooks/useFetchNewPoolCallback.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IPool } from "@bleu/cow-hooks-ui";
import { useIFrameContext } from "@bleu/cow-hooks-ui";
import type { Address, PublicClient } from "viem";
import { type Address, type PublicClient, formatUnits } from "viem";
import { getTokensInfo } from "#/utils/getTokensInfo";
import { readPairData } from "#/utils/readPairsData";
import { storeExtraTokens } from "#/utils/storage";
Expand All @@ -11,12 +11,14 @@ async function fetchNewPool({
poolAddress,
client,
balancesDiff,
saveOnStore,
}: {
chainId: number;
account: string;
poolAddress: Address;
client: PublicClient;
balancesDiff: Record<string, string>;
saveOnStore: boolean;
}): Promise<IPool> {
// Get lists of tokens
const lpToken = await readPairData(
Expand All @@ -32,13 +34,11 @@ async function fetchNewPool({
const userBalance0 = lpToken.userBalance
.mul(lpToken.reserve0)
.div(lpToken.totalSupply)
.mul(99)
.div(100); // 1% slippage
.toBigInt();
const userBalance1 = lpToken.userBalance
.mul(lpToken.reserve1)
.div(lpToken.totalSupply)
.mul(99)
.div(100); // 1% slippage;
.toBigInt();

const token0 = tokens.find((token) => token.address === lpToken.tokens[0]);
const token1 = tokens.find((token) => token.address === lpToken.tokens[1]);
Expand All @@ -48,30 +48,33 @@ async function fetchNewPool({
"Unexpected error in fetchNewPool: some of tokens are undefined",
);

try {
storeExtraTokens(
[
{
chainId,
address: poolAddress,
name: `Uniswap V2 ${token0.symbol}/${token1.symbol}`,
symbol: lpToken.symbol,
decimals: 18, // UniV2 are always 18 decimals
extensions: { tokens: lpToken.tokens.join(",") },
},
],
chainId,
account,
);
} catch (e) {
console.error("Error caching new LP token:", e);
if (saveOnStore) {
try {
storeExtraTokens(
[
{
chainId,
address: poolAddress,
name: `Uniswap V2 ${token0.symbol}/${token1.symbol}`,
symbol: lpToken.symbol,
decimals: 18, // UniV2 are always 18 decimals
extensions: { tokens: lpToken.tokens.join(",") },
},
],
chainId,
account,
);
} catch (e) {
console.error("Error caching new LP token:", e);
}
}

const userBalanceUsd0 =
(token0.priceUsd * userBalance0.toNumber()) / 10 ** token0.decimals;
const userBalance0Number = Number(formatUnits(userBalance0, token0.decimals));
const userBalance1Number = Number(formatUnits(userBalance1, token1.decimals));

const userBalanceUsd0 = token0.priceUsd * userBalance0Number;

const userBalanceUsd1 =
(token1.priceUsd * userBalance1.toNumber()) / 10 ** token1.decimals;
const userBalanceUsd1 = token1.priceUsd * userBalance1Number;

return {
id: lpToken.address as Address,
Expand Down Expand Up @@ -109,7 +112,7 @@ async function fetchNewPool({
};
}

export function useFetchNewPoolCallback() {
export function useFetchNewPoolCallback(saveOnStore = true) {
const { context, publicClient } = useIFrameContext();
//@ts-ignore
const { account, chainId, balancesDiff } = context ?? {
Expand All @@ -130,6 +133,7 @@ export function useFetchNewPoolCallback() {
poolAddress,
client: publicClient,
balancesDiff: userBalancesDiff as Record<string, string>,
saveOnStore,
});
};
}
149 changes: 67 additions & 82 deletions apps/withdraw-uni-v2/src/hooks/usePools.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IPool } from "@bleu/cow-hooks-ui";
import type { SupportedChainId } from "@cowprotocol/cow-sdk";
import useSWR from "swr";
import type { Address, PublicClient } from "viem";
import { type Address, type PublicClient, formatUnits } from "viem";
import { getLpTokensList } from "#/utils/getLpTokensList";
import { getTokensInfo } from "#/utils/getTokensInfo";
import { getTokensList } from "#/utils/getTokensList";
Expand All @@ -11,7 +11,6 @@ import { isChainIdSupported } from "#/utils/uniswapSupportedChains";
async function getUserPools(
ownerAddress: string,
chainId: SupportedChainId,
token: string,
client: PublicClient,
balancesDiff: Record<string, string>,
): Promise<IPool[]> {
Expand All @@ -21,9 +20,7 @@ async function getUserPools(
getTokensList(chainId),
]);

const lpTokens = allLpTokens.filter(
(lpToken) => lpToken.chainId === chainId && lpToken.tokens.includes(token),
);
const lpTokens = allLpTokens.filter((lpToken) => lpToken.chainId === chainId);

// Read possibly missing tokens on chain and add price Usd
const tokens = await getTokensInfo(
Expand All @@ -46,94 +43,83 @@ async function getUserPools(
return { ...lpToken, ...lpTokensInfo[idx] };
});

const userPools: IPool[] = lpTokensWithInfo
.map((lpToken) => {
const userBalance0 = lpToken.userBalance
.mul(lpToken.reserve0)
.div(lpToken.totalSupply)
.mul(99)
.div(100); // 1% slippage
const userBalance1 = lpToken.userBalance
.mul(lpToken.reserve1)
.div(lpToken.totalSupply)
.mul(99)
.div(100); // 1% slippage;

const token0 = tokens.find(
(token) => token.address === lpToken.tokens[0],
);
const token1 = tokens.find(
(token) => token.address === lpToken.tokens[1],
);

if (!token0 || !token1) return;

const userBalanceUsd0 =
(token0.priceUsd * userBalance0.toNumber()) / 10 ** token0.decimals;

const userBalanceUsd1 =
(token1.priceUsd * userBalance1.toNumber()) / 10 ** token1.decimals;

return {
id: lpToken.address as Address,
chain: String(chainId),
decimals: 18,
symbol: lpToken.symbol,
address: lpToken.address as Address,
type: "Uniswap v2",
protocolVersion: 2 as const,
totalSupply: lpToken.totalSupply,
allTokens: [
{
address: token0.address as Address,
symbol: token0.symbol,
decimals: token0.decimals,
userBalance: userBalance0,
userBalanceUsd: userBalanceUsd0,
reserve: lpToken.reserve0,
weight: 0.5,
},
{
address: token1.address as Address,
symbol: token1.symbol,
decimals: token1.decimals,
userBalance: userBalance1,
userBalanceUsd: userBalanceUsd1,
reserve: lpToken.reserve1,
weight: 0.5,
},
],
userBalance: {
walletBalance: lpToken.userBalance,
walletBalanceUsd: userBalanceUsd0 + userBalanceUsd1,
const allPools: (IPool | undefined)[] = lpTokensWithInfo.map((lpToken) => {
const userBalance0 = lpToken.userBalance
.mul(lpToken.reserve0)
.div(lpToken.totalSupply)
.toBigInt();
const userBalance1 = lpToken.userBalance
.mul(lpToken.reserve1)
.div(lpToken.totalSupply)
.toBigInt();

const token0 = tokens.find((token) => token.address === lpToken.tokens[0]);
const token1 = tokens.find((token) => token.address === lpToken.tokens[1]);

if (!token0 || !token1) return;

const userBalance0Number = Number(
formatUnits(userBalance0, token0.decimals),
);
const userBalance1Number = Number(
formatUnits(userBalance1, token1.decimals),
);

const userBalanceUsd0 = token0.priceUsd * userBalance0Number;

const userBalanceUsd1 = token1.priceUsd * userBalance1Number;

return {
id: lpToken.address as Address,
chain: String(chainId),
decimals: 18,
symbol: lpToken.symbol,
address: lpToken.address as Address,
type: "Uniswap v2",
protocolVersion: 2 as const,
totalSupply: lpToken.totalSupply,
allTokens: [
{
address: token0.address as Address,
symbol: token0.symbol,
decimals: token0.decimals,
userBalance: userBalance0,
userBalanceUsd: userBalanceUsd0,
reserve: lpToken.reserve0,
weight: 0.5,
},
};
})
{
address: token1.address as Address,
symbol: token1.symbol,
decimals: token1.decimals,
userBalance: userBalance1,
userBalanceUsd: userBalanceUsd1,
reserve: lpToken.reserve1,
weight: 0.5,
},
],
userBalance: {
walletBalance: lpToken.userBalance,
walletBalanceUsd: userBalanceUsd0 + userBalanceUsd1,
},
};
});

return allPools
.filter((pool) => pool !== undefined)
.filter((pool) => pool.userBalance.walletBalance.toString() !== "0");

return userPools;
}

export function usePools(
ownerAddress: string | undefined,
chainId: SupportedChainId | undefined,
token: string | undefined,
client: PublicClient | undefined,
balancesDiff: Record<string, Record<string, string>>,
) {
return useSWR(
[ownerAddress, chainId, token, client, balancesDiff],
async ([ownerAddress, chainId, token, client, balancesDiff]): Promise<
IPool[]
> => {
if (
!ownerAddress ||
!chainId ||
!token ||
!client ||
balancesDiff === undefined
)
[ownerAddress, chainId, client, balancesDiff],
async ([ownerAddress, chainId, client, balancesDiff]): Promise<IPool[]> => {
if (!ownerAddress || !chainId || !client || balancesDiff === undefined)
return [];

if (!isChainIdSupported(chainId)) {
Expand All @@ -146,7 +132,6 @@ export function usePools(
return await getUserPools(
ownerAddress,
chainId,
token,
client,
userBalancesDiff,
);
Expand Down
25 changes: 7 additions & 18 deletions apps/withdraw-uni-v2/src/hooks/useSelectedPool.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import { useCallback } from "react";
import useSWR from "swr";
import { isAddress } from "viem";
import { useFetchNewPoolCallback } from "./useFetchNewPoolCallback";
import { useMemo } from "react";
import { useUserPools } from "./useUserPools";

export function useSelectedPool(poolId: string) {
const fetchNewPoolCallback = useFetchNewPoolCallback();

const getSelectedPoolCallback = useCallback(
async (_poolId: string) => {
if (!fetchNewPoolCallback) return;
if (!isAddress(_poolId)) return;

const fetchedNewPool = await fetchNewPoolCallback(_poolId);
return fetchedNewPool;
},
[fetchNewPoolCallback],
);

return useSWR(poolId, getSelectedPoolCallback);
const { data: pools } = useUserPools();
return useMemo(() => {
if (!pools) return;
return pools.find((pool) => pool.id.toLowerCase() === poolId.toLowerCase());
}, [pools, poolId]);
}
Loading
Loading