Skip to content

Commit 9c6b84b

Browse files
committed
fix: (HOT) temp solution to correctly handle burned licenses
1 parent 5844a4b commit 9c6b84b

File tree

2 files changed

+89
-27
lines changed

2 files changed

+89
-27
lines changed

app/licenses/page.tsx

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import ErrorComponent from '@/app/server-components/shared/ErrorComponent';
2-
import { getLicensesTotalSupply } from '@/lib/api/blockchain';
3-
import { LicenseItem } from '@/typedefs/general';
4-
import { unstable_cache } from 'next/cache';
5-
import List from '../server-components/Licenses/List';
6-
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
7-
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';
1+
import ErrorComponent from '@/app/server-components/shared/ErrorComponent';
2+
import { getAllLicenseTokenIds } from '@/lib/api/blockchain';
3+
import { LicenseItem } from '@/typedefs/general';
4+
import { unstable_cache } from 'next/cache';
5+
import List from '../server-components/Licenses/List';
6+
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
7+
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';
88

99
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
1010
const resolvedSearchParams = await searchParams;
@@ -22,7 +22,7 @@ export async function generateMetadata({ searchParams }: { searchParams?: Promis
2222
};
2323
}
2424

25-
const getCachedSupply = unstable_cache(getLicensesTotalSupply, ['licenses-total-supply'], { revalidate: 300 });
25+
const getCachedLicenseTokenIds = unstable_cache(getAllLicenseTokenIds, ['licenses-token-ids'], { revalidate: 300 });
2626

2727
export default async function LicensesPage(props: {
2828
searchParams?: Promise<{
@@ -32,25 +32,24 @@ export default async function LicensesPage(props: {
3232
const searchParams = await props.searchParams;
3333
const currentPage = Number(searchParams?.page) || 1;
3434

35-
let ndTotalSupply: number, mndTotalSupply: number;
36-
let licenses: LicenseItem[];
37-
38-
try {
39-
const { ndTotalSupply: ndTotalSupplyStr, mndTotalSupply: mndTotalSupplyStr } = await getCachedSupply();
40-
41-
ndTotalSupply = Number(ndTotalSupplyStr);
42-
mndTotalSupply = Number(mndTotalSupplyStr);
43-
44-
licenses = [
45-
...Array.from({ length: Number(mndTotalSupply) }, (_, i) => ({
46-
licenseId: i + 1,
47-
licenseType: i === 0 ? ('GND' as const) : ('MND' as const),
48-
})),
49-
...Array.from({ length: Number(ndTotalSupply) }, (_, i) => ({
50-
licenseId: i + 1,
51-
licenseType: 'ND' as const,
52-
})),
53-
];
35+
let ndTotalSupply: number, mndTotalSupply: number;
36+
let licenses: LicenseItem[];
37+
38+
try {
39+
const { ndLicenseIds, mndLicenseIds } = await getCachedLicenseTokenIds();
40+
ndTotalSupply = ndLicenseIds.length;
41+
mndTotalSupply = mndLicenseIds.length;
42+
43+
licenses = [
44+
...mndLicenseIds.map((licenseId) => ({
45+
licenseId,
46+
licenseType: licenseId === 1 ? ('GND' as const) : ('MND' as const),
47+
})),
48+
...ndLicenseIds.map((licenseId) => ({
49+
licenseId,
50+
licenseType: 'ND' as const,
51+
})),
52+
];
5453
} catch (error) {
5554
console.error(error);
5655
console.log('[Licenses Page] Failed to fetch license data');

lib/api/blockchain.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,69 @@ export async function getLicensesTotalSupply(): Promise<{
278278
};
279279
}
280280

281+
const LICENSE_ENUMERATION_CHUNK_SIZE = 200;
282+
283+
const getEnumerableLicenseIds = async (
284+
publicClient: Awaited<ReturnType<typeof getPublicClient>>,
285+
address: types.EthAddress,
286+
abi: typeof NDContractAbi | typeof MNDContractAbi,
287+
totalSupply: bigint,
288+
): Promise<number[]> => {
289+
if (totalSupply === 0n) {
290+
return [];
291+
}
292+
293+
const total = Number(totalSupply);
294+
const licenseIds: number[] = [];
295+
296+
for (let start = 0; start < total; start += LICENSE_ENUMERATION_CHUNK_SIZE) {
297+
const end = Math.min(start + LICENSE_ENUMERATION_CHUNK_SIZE, total);
298+
const tokenIds = await publicClient.multicall({
299+
contracts: Array.from({ length: end - start }, (_, index) => ({
300+
address,
301+
abi,
302+
functionName: 'tokenByIndex' as const,
303+
args: [BigInt(start + index)],
304+
})),
305+
allowFailure: false,
306+
});
307+
308+
licenseIds.push(...tokenIds.map((tokenId) => Number(tokenId)));
309+
}
310+
311+
return licenseIds.sort((a, b) => a - b);
312+
};
313+
314+
export async function getAllLicenseTokenIds(): Promise<{
315+
mndLicenseIds: number[];
316+
ndLicenseIds: number[];
317+
}> {
318+
const publicClient = await getPublicClient();
319+
320+
const [mndTotalSupply, ndTotalSupply] = await Promise.all([
321+
publicClient.readContract({
322+
address: config.mndContractAddress,
323+
abi: MNDContractAbi,
324+
functionName: 'totalSupply',
325+
}),
326+
publicClient.readContract({
327+
address: config.ndContractAddress,
328+
abi: NDContractAbi,
329+
functionName: 'totalSupply',
330+
}),
331+
]);
332+
333+
const [mndLicenseIds, ndLicenseIds] = await Promise.all([
334+
getEnumerableLicenseIds(publicClient, config.mndContractAddress, MNDContractAbi, mndTotalSupply),
335+
getEnumerableLicenseIds(publicClient, config.ndContractAddress, NDContractAbi, ndTotalSupply),
336+
]);
337+
338+
return {
339+
mndLicenseIds,
340+
ndLicenseIds,
341+
};
342+
}
343+
281344
export async function getLicenseHolders(licenseType: 'ND' | 'MND' | 'GND'): Promise<
282345
{
283346
ownerOf: EvmAddress | undefined;

0 commit comments

Comments
 (0)