Skip to content

Commit

Permalink
Merge pull request #65 from bleu/pedro/cow-425-uniswap-v2-withdraw-co…
Browse files Browse the repository at this point in the history
…w-review-pt1

fix: elena comments pt1
  • Loading branch information
yvesfracari authored Dec 5, 2024
2 parents b7591de + e71a943 commit 5ec65eb
Show file tree
Hide file tree
Showing 14 changed files with 257 additions and 237 deletions.
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

0 comments on commit 5ec65eb

Please sign in to comment.