Skip to content

Commit

Permalink
Infinite scroll (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptickoan authored Apr 22, 2022
1 parent b42ce00 commit 224d155
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 25 deletions.
154 changes: 148 additions & 6 deletions src/components/pages/Fuse/FusePoolsPage/FusePoolsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import { memo } from "react";
import { memo, useEffect, useState } from "react";

// Components
import DashboardBox from "components/shared/DashboardBox";
import FuseStatsBar from "../FuseStatsBar";
import FuseTabBar from "../FuseTabBar";

// Hooks
import { useIsSmallScreen } from "hooks/useIsSmallScreen";
import { useIsSmallScreen } from "hooks/useIsSmallScreen"
import { Fuse } from "../../../../esm/index";

// Utils
import { Column } from "lib/chakraUtils";
import { Center, Column, Row } from "lib/chakraUtils";
import { PoolList } from "./PoolList";
import { useFilter } from "hooks/useFilter";
import { useFusePools } from "hooks/fuse/useFusePools";
import { createMergedPools, MergedPool, fetchPoolsManual, LensFusePool, LensFusePoolData, useFusePools, useFusePoolsList, useInifinitePools } from "hooks/fuse/useFusePools";
import { useRari } from "context/RariContext";
import { useInfiniteQuery } from "react-query";
import { BigNumber } from "ethers";
import { providers } from "@0xsequence/multicall";
import { fetchCurrentETHPrice } from "utils/coingecko";
import { ChainID } from "constants/networks";
import { Spinner } from "@chakra-ui/react";
import { ModalDivider } from "components/shared/Modal";
import { Text } from "rari-components";

const FusePoolsPage = memo(() => {
const isMobile = useIsSmallScreen();
const filter = useFilter();
const filteredPools = useFusePools(filter);


return (
<>
Expand All @@ -35,11 +45,143 @@ const filteredPools = useFusePools(filter);
<FuseTabBar />

<DashboardBox width="100%" mt={4}>
<PoolList pools={filteredPools} />
{filter === "unverified-pools" ? <UnverifiedPools filter={filter}/> : <VerifiedPools filter={filter} />}
</DashboardBox>
</Column>
</>
);
});

export default FusePoolsPage;

const VerifiedPools = ({filter}: {filter: string | null}) => {
const filteredPools = useFusePools(filter);
return (
<PoolList pools={filteredPools} />
)
}

const UnverifiedPools = ({filter}: {filter: string}) => {
const [poolListLength, setPoolListLength] = useState(0)
const [poolBatch, setPoolBatch] = useState([0,20])
const [poolSlice, setPoolSlice] = useState([[]])

const { fuse, address, chainId } = useRari()
const poolList: [][] = useFusePoolsList(fuse, address)

useEffect(() => {
if(poolList) {
setPoolListLength(poolList[1].length)
setPoolSlice([poolList[0].slice(...poolBatch),poolList[1].slice(...poolBatch)])
}
}, [poolList])


const fetchPoolsManual = async ({pageParam = poolSlice}: any) => {
if (pageParam.length === 1) return
// Extract data from Directory call
let ids: string[] = (pageParam[0] ?? []).map((bn: BigNumber) =>
bn.toString()
);
let fusePools: LensFusePool[] = pageParam[1];
let comptrollers = fusePools.map((pool: any) => pool[2]);

// Query lens.getPoolSummary
let fusePoolsData: LensFusePoolData[] = await Promise.all(
comptrollers.map(async (comptroller) => {
const _data = await fuse.contracts.FusePoolLens.callStatic.getPoolSummary(
comptroller
);
const data: LensFusePoolData = {
totalSupply: _data[0],
totalBorrow: _data[1],
underlyingTokens: _data[2],
underlyingSymbols: _data[3],
whitelistedAdmin: _data[4],
};
return data;
})
).catch((err) => {
console.error("Error querying poolSummaries", err);
return [];
});

const multicallProvider = new providers.MulticallProvider(fuse.contracts.FusePoolLens.provider)
const multicallFuse = new Fuse(multicallProvider, chainId as any)
const poolRewardTokens = await Promise.all(fusePools.map((pool) => {
return multicallFuse.contracts.FusePoolLensSecondary.callStatic.getRewardSpeedsByPool(
pool.comptroller
).then((rewards) => {
//reward token list
return rewards[2]
})
}))

const fetchETHPrice = fetchCurrentETHPrice();
const merged: MergedPool[] = await createMergedPools(ids, fusePools, fusePoolsData, poolRewardTokens, fetchETHPrice);
return merged
};

const {
isLoading,
isError,
error,
data,
fetchNextPage,
isFetching,
isFetchingNextPage
//@ts-ignore
} = useInfiniteQuery(['colors'], fetchPoolsManual, {
enabled: poolList && poolSlice.length > 1,
refetchOnWindowFocus: false,
getNextPageParam: (lastPage, pages) => {
return poolSlice
}
})


const handleInifiniteScrollClick = () => {
setPoolBatch([poolBatch[0] + 20, poolBatch[1] + 20])
setPoolSlice([
poolList[0].slice(poolBatch[0] + 20, poolBatch[1] + 20),
poolList[1].slice(poolBatch[0] + 20, poolBatch[1] + 20)
])
fetchNextPage({
pageParam: [
poolList[0].slice(poolBatch[0] + 20, poolBatch[1] + 20),
poolList[1].slice(poolBatch[0] + 20, poolBatch[1] + 20)
]
})
}

return (
<>
{ data?.pages.map((page, index) => <PoolList pools={page} infiniteScroll={index > 0}/>)}

{ poolBatch[1] < poolListLength ?
<>
<ModalDivider/>
<Row
onClick={handleInifiniteScrollClick}
_hover={{cursor: "pointer", opacity: 1}}
mainAxisAlignment="center"
crossAxisAlignment="center"
height="45px"
width="100%"
flexShrink={0}
opacity={0.5}
pl={4}
pr={1}
>
<Text textAlign="center" fontWeight="bold" width={"100%"}>
Load more...
</Text>

</Row>
</>
: null
}
</>
)
}

4 changes: 3 additions & 1 deletion src/components/pages/Fuse/FusePoolsPage/PoolList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Column, Row, useIsMobile } from "lib/chakraUtils";
import { filterPoolName } from "utils/fetchFusePoolData";
import { useState } from "react";

export const PoolList = ({ pools }: { pools: MergedPool[] | null }) => {
export const PoolList = ({ pools, infiniteScroll }: { pools: MergedPool[] | null | undefined, infiniteScroll?: boolean }) => {
const { t } = useTranslation();

const isMobile = useIsMobile();
Expand All @@ -23,6 +23,7 @@ export const PoolList = ({ pools }: { pools: MergedPool[] | null }) => {
crossAxisAlignment="flex-start"
expand
>
{infiniteScroll ? null :
<Row
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
Expand Down Expand Up @@ -56,6 +57,7 @@ export const PoolList = ({ pools }: { pools: MergedPool[] | null }) => {
</>
)}
</Row>
}

<ModalDivider />

Expand Down
108 changes: 90 additions & 18 deletions src/hooks/fuse/useFusePools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export interface FusePool {
isPrivate: boolean;
}

interface LensFusePool {
export interface LensFusePool {
blockPosted: string;
name: string;
creator: string;
comptroller: string;
timestampPosted: string;
}

interface LensFusePoolData {
export interface LensFusePoolData {
totalBorrow: string;
totalSupply: string;
underlyingSymbols: string[];
Expand Down Expand Up @@ -80,20 +80,15 @@ export const fetchPoolsManual = async ({
verification = false,
chainId = 1,
blockNum,
fusePoolsDirectoryResult
}: {
fusePoolsDirectoryResult: any
fuse: Fuse;
address: string;
verification?: boolean;
chainId?: number;
blockNum?: number;
}) => {
// Query Directory
let fusePoolsDirectoryResult =
await fuse.contracts.FusePoolDirectory.callStatic.getPublicPoolsByVerification(
verification,
{ from: address }
);

// Extract data from Directory call
let ids: string[] = (fusePoolsDirectoryResult[0] ?? []).map((bn: BigNumber) =>
bn.toString()
Expand Down Expand Up @@ -136,6 +131,17 @@ export const fetchPoolsManual = async ({
return await createMergedPools(ids, fusePools, fusePoolsData, poolRewardTokens, fetchETHPrice);
};

export const fetchPoolsList = async (
fuse: Fuse,
address: string,
) => {
const answer = await fuse.contracts.FusePoolDirectory.connect(fuse.contracts.FusePoolLens.provider).callStatic.getPublicPoolsByVerification(
false,
{ from: address }
)
return answer
}

export const fetchPools = async ({
fuse,
address,
Expand Down Expand Up @@ -209,7 +215,7 @@ export const fetchPools = async ({
return await createMergedPools(ids, fusePools, fusePoolsData, poolRewardTokens, fetchETHPrice);
};

const createMergedPools = async (
export const createMergedPools = async (
ids: string[],
fusePools: LensFusePool[],
fusePoolsData: LensFusePoolData[],
Expand Down Expand Up @@ -252,14 +258,6 @@ export const useFusePools = (filter: string | null): MergedPool[] | null => {
const { data: pools } = useQuery(
`${address} fusePoolList ${filter ?? ""} chainId: ${chainId}`,
async () => {
if (chainId === ChainID.ARBITRUM && filter === "unverified-pools") {
return await fetchPoolsManual({
fuse,
address,
verification: false,
chainId,
});
}
return await fetchPools({ fuse, address, filter, chainId });
}
);
Expand Down Expand Up @@ -299,3 +297,77 @@ export const useFusePools = (filter: string | null): MergedPool[] | null => {

return filteredPools;
};

export const useFusePoolsList = (
fuse: Fuse,
address: string,
) => {
const { data: pools } = useQuery('Fuse unverified pools list', async () => await fetchPoolsList(fuse, address))

return pools
}

export const useInifinitePools = (fuse: Fuse, chainId: number, address: string) => {

const fetchPoolsManual = async ({
fusePoolsDirectoryResult
}: {
fusePoolsDirectoryResult: any
}) => {
// Extract data from Directory call
let ids: string[] = (fusePoolsDirectoryResult[0] ?? []).map((bn: BigNumber) =>
bn.toString()
);
let fusePools: LensFusePool[] = fusePoolsDirectoryResult[1];
let comptrollers = fusePools.map(({ comptroller }) => comptroller);

// Query lens.getPoolSummary
let fusePoolsData: LensFusePoolData[] = await Promise.all(
comptrollers.map(async (comptroller) => {
const _data = await fuse.contracts.FusePoolLens.callStatic.getPoolSummary(
comptroller
);
const data: LensFusePoolData = {
totalSupply: _data[0],
totalBorrow: _data[1],
underlyingTokens: _data[2],
underlyingSymbols: _data[3],
whitelistedAdmin: _data[4],
};
return data;
})
).catch((err) => {
console.error("Error querying poolSummaries", err);
return [];
});

const multicallProvider = new providers.MulticallProvider(fuse.provider)
const multicallFuse = new Fuse(multicallProvider, chainId)
const poolRewardTokens = await Promise.all(fusePools.map((pool) => {
return multicallFuse.contracts.FusePoolLensSecondary.callStatic.getRewardSpeedsByPool(
pool.comptroller
).then((rewards) => {
//reward token list
return rewards[2]
})
}))

const fetchETHPrice = fetchCurrentETHPrice();
return await createMergedPools(ids, fusePools, fusePoolsData, poolRewardTokens, fetchETHPrice);
};

const {
isLoading,
isError,
error,
data,
fetchNextPage,
isFetching,
isFetchingNextPage
//@ts-ignore
} = useInfiniteQuery(['colors'], fetchPoolsManual, {
getNextPageParam: (lastPage: any, pages: any) => {
return {}
}
})
}

1 comment on commit 224d155

@vercel
Copy link

@vercel vercel bot commented on 224d155 Apr 22, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.