Skip to content

Commit 237f51a

Browse files
authored
Merge pull request #29 from Ratio1/develop
Develop
2 parents 6c3c0b1 + b1eab32 commit 237f51a

File tree

22 files changed

+1545
-370
lines changed

22 files changed

+1545
-370
lines changed

.env.production.devnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ NEXT_PUBLIC_ORACLES_URL=https://devnet-oracle.ratio1.ai
1010
NEXT_PUBLIC_R1_CA=0x277CbD0Cf25F4789Bc04035eCd03d811FAf73691
1111
NEXT_PUBLIC_ND_CA=0x90025B92240E3070d5CdcB3f44D6411855c55a73
1212
NEXT_PUBLIC_MND_CA=0x17B8934dc5833CdBa1eF42D13D65D677C4727748
13+
NEXT_PUBLIC_ADOPTION_ORACLE_CA=0x01AA13bEe0fCCbe67C93f7fFCBF2bBc21ccE1874
1314
NEXT_PUBLIC_READER_CA=0xFcF04c9A67330431Af75a546615E4881BD8bdC78
1415
NEXT_PUBLIC_EXPLORER_URL=https://sepolia.basescan.org
1516

.env.production.mainnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ NEXT_PUBLIC_ORACLES_URL=https://oracle.ratio1.ai
1010
NEXT_PUBLIC_R1_CA=0x6444C6c2D527D85EA97032da9A7504d6d1448ecF
1111
NEXT_PUBLIC_ND_CA=0xE658DF6dA3FB5d4FBa562F1D5934bd0F9c6bd423
1212
NEXT_PUBLIC_MND_CA=0x0C431e546371C87354714Fcc1a13365391A549E2
13+
NEXT_PUBLIC_ADOPTION_ORACLE_CA=0x93caaC52b4D0a452012218591B0b53cD41C3F830
1314
NEXT_PUBLIC_READER_CA=0xa2fDD4c7E93790Ff68a01f01AA789D619F12c6AC
1415
NEXT_PUBLIC_EXPLORER_URL=https://basescan.org
1516

.env.production.testnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ NEXT_PUBLIC_ORACLES_URL=https://testnet-oracle.ratio1.ai
1010
NEXT_PUBLIC_R1_CA=0xCC96f389F45Fc08b4fa8e2bC4C7DA9920292ec64
1111
NEXT_PUBLIC_ND_CA=0x18E86a5829CA1F02226FA123f30d90dCd7cFd0ED
1212
NEXT_PUBLIC_MND_CA=0xa8d7FFCE91a888872A9f5431B4Dd6c0c135055c1
13+
NEXT_PUBLIC_ADOPTION_ORACLE_CA=0x670383EB0c53e3Db3383D8Ce598E0bc316F2854E
1314
NEXT_PUBLIC_READER_CA=0xd1c7Dca934B37FAA402EB2EC64F6644d6957bE3b
1415
NEXT_PUBLIC_EXPLORER_URL=https://sepolia.basescan.org
1516

app/account/[ownerEthAddr]/page.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ export default async function NodeOperatorPage({ params }) {
102102
return <NotFound />;
103103
}
104104

105+
const totalCurveReleased = licenses.reduce((acc, license) => acc + BigInt(license.totalClaimedAmount), 0n);
106+
const totalAwbBalance = licenses.reduce((acc, license) => acc + BigInt(license.awbBalance ?? '0'), 0n);
107+
const totalWalletClaimed = totalCurveReleased > totalAwbBalance ? totalCurveReleased - totalAwbBalance : 0n;
108+
const totalAssigned = licenses.reduce((acc, license) => acc + BigInt(license.totalAssignedAmount), 0n);
109+
105110
return (
106111
<div className="responsive-col">
107112
<BorderedCard>
@@ -131,32 +136,30 @@ export default async function NodeOperatorPage({ params }) {
131136

132137
<CardHorizontal
133138
label="Total $R1 Claimed"
134-
value={
135-
<div className="text-primary">
136-
{fBI(
137-
licenses.reduce((acc, license) => acc + BigInt(license.totalClaimedAmount), 0n),
138-
18,
139-
)}
140-
</div>
141-
}
139+
value={<div className="text-primary">{fBI(totalWalletClaimed, 18)}</div>}
142140
isSmall
143141
isFlexible
144142
widthClasses="min-w-[268px]"
145143
/>
146144

145+
{totalAwbBalance > 0n && (
146+
<CardHorizontal
147+
label="Total in AWB"
148+
value={<div className="text-orange-500">{fBI(totalAwbBalance, 18)}</div>}
149+
isSmall
150+
isFlexible
151+
widthClasses="min-w-[268px]"
152+
/>
153+
)}
154+
147155
<CardHorizontal
148156
label="Licenses Usage (Total)"
149157
value={
150158
<div className="w-full min-w-52 xs:min-w-56 md:min-w-60">
151159
<UsageStats
152-
totalClaimedAmount={licenses.reduce(
153-
(acc, license) => acc + BigInt(license.totalClaimedAmount),
154-
0n,
155-
)}
156-
totalAssignedAmount={licenses.reduce(
157-
(acc, license) => acc + BigInt(license.totalAssignedAmount),
158-
0n,
159-
)}
160+
totalClaimedAmount={totalCurveReleased}
161+
totalAssignedAmount={totalAssigned}
162+
awbBalance={totalAwbBalance}
160163
/>
161164
</div>
162165
}

app/licenses/page.tsx

Lines changed: 89 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,97 @@
11
import ErrorComponent from '@/app/server-components/shared/ErrorComponent';
2-
import { getAllLicenseTokenIds } from '@/lib/api/blockchain';
3-
import { LicenseItem } from '@/typedefs/general';
2+
import { PAGE_SIZE } from '@/config';
3+
import { getLicensesPage } from '@/lib/api/blockchain';
4+
import { LicenseListItem } from '@/typedefs/general';
45
import { unstable_cache } from 'next/cache';
56
import List from '../server-components/Licenses/List';
67
import { BorderedCard } from '../server-components/shared/cards/BorderedCard';
78
import { CardHorizontal } from '../server-components/shared/cards/CardHorizontal';
8-
9-
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
10-
const resolvedSearchParams = await searchParams;
11-
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
12-
const canonical = Number.isFinite(pageParam) && pageParam > 1 ? `/licenses?page=${pageParam}` : '/licenses';
13-
14-
return {
15-
title: 'Licenses',
16-
openGraph: {
17-
title: 'Licenses',
18-
},
19-
alternates: {
20-
canonical,
21-
},
22-
};
23-
}
24-
25-
const getCachedLicenseTokenIds = unstable_cache(getAllLicenseTokenIds, ['licenses-token-ids'], { revalidate: 300 });
26-
27-
export default async function LicensesPage(props: {
28-
searchParams?: Promise<{
29-
page?: string;
30-
}>;
31-
}) {
32-
const searchParams = await props.searchParams;
33-
const currentPage = Number(searchParams?.page) || 1;
34-
35-
let ndTotalSupply: number, mndTotalSupply: number;
36-
let licenses: LicenseItem[];
9+
10+
export async function generateMetadata({ searchParams }: { searchParams?: Promise<{ page?: string }> }) {
11+
const resolvedSearchParams = await searchParams;
12+
const pageParam = Number.parseInt(resolvedSearchParams?.page ?? '', 10);
13+
const canonical = Number.isFinite(pageParam) && pageParam > 1 ? `/licenses?page=${pageParam}` : '/licenses';
14+
15+
return {
16+
title: 'Licenses',
17+
openGraph: {
18+
title: 'Licenses',
19+
},
20+
alternates: {
21+
canonical,
22+
},
23+
};
24+
}
25+
26+
const getCachedLicensesPage = unstable_cache(
27+
async (currentPage: number) => {
28+
const page = currentPage > 0 ? currentPage : 1;
29+
const offset = (page - 1) * PAGE_SIZE;
30+
const data = await getLicensesPage(offset, PAGE_SIZE);
31+
32+
return {
33+
...data,
34+
ndTotalSupply: data.ndTotalSupply.toString(),
35+
mndTotalSupply: data.mndTotalSupply.toString(),
36+
};
37+
},
38+
['licenses-page'],
39+
{ revalidate: 300 },
40+
);
41+
42+
export default async function LicensesPage(props: {
43+
searchParams?: Promise<{
44+
page?: string;
45+
}>;
46+
}) {
47+
const searchParams = await props.searchParams;
48+
const currentPage = Number(searchParams?.page) || 1;
49+
50+
let ndTotalSupply: bigint, mndTotalSupply: bigint;
51+
let licensesCount: number;
52+
let licenses: LicenseListItem[];
3753

3854
try {
39-
const { ndLicenseIds, mndLicenseIds } = await getCachedLicenseTokenIds();
40-
ndTotalSupply = ndLicenseIds.length;
41-
mndTotalSupply = mndLicenseIds.length;
55+
const {
56+
ndTotalSupply: ndSupply,
57+
mndTotalSupply: mndSupply,
58+
licenses: pageLicenses,
59+
} = await getCachedLicensesPage(currentPage);
60+
61+
ndTotalSupply = BigInt(ndSupply);
62+
mndTotalSupply = BigInt(mndSupply);
63+
licenses = pageLicenses;
64+
licensesCount = Number(ndTotalSupply + mndTotalSupply);
65+
} catch (error) {
66+
console.error(error);
67+
console.log('[Licenses Page] Failed to fetch license data');
68+
return <NotFound />;
69+
}
70+
71+
return (
72+
<>
73+
<div className="w-full">
74+
<BorderedCard>
75+
<div className="card-title-big font-bold">Licenses</div>
76+
77+
<div className="flexible-row">
78+
<CardHorizontal
79+
label="Total"
80+
value={licensesCount.toString()}
81+
isFlexible
82+
widthClasses="min-w-[192px]"
83+
/>
84+
<CardHorizontal label="ND" value={ndTotalSupply.toString()} isFlexible widthClasses="min-w-[192px]" />
85+
<CardHorizontal label="MND" value={mndTotalSupply.toString()} isFlexible widthClasses="min-w-[192px]" />
86+
</div>
87+
</BorderedCard>
88+
</div>
89+
90+
<List licenses={licenses} currentPage={currentPage} totalLicenses={licensesCount} />
91+
</>
92+
);
93+
}
4294

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-
];
53-
} catch (error) {
54-
console.error(error);
55-
console.log('[Licenses Page] Failed to fetch license data');
56-
return <NotFound />;
57-
}
58-
59-
return (
60-
<>
61-
<div className="w-full">
62-
<BorderedCard>
63-
<div className="card-title-big font-bold">Licenses</div>
64-
65-
<div className="flexible-row">
66-
<CardHorizontal
67-
label="Total"
68-
value={ndTotalSupply + mndTotalSupply}
69-
isFlexible
70-
widthClasses="min-w-[192px]"
71-
/>
72-
<CardHorizontal label="ND" value={ndTotalSupply} isFlexible widthClasses="min-w-[192px]" />
73-
<CardHorizontal label="MND" value={mndTotalSupply} isFlexible widthClasses="min-w-[192px]" />
74-
</div>
75-
</BorderedCard>
76-
</div>
77-
78-
<List licenses={licenses} currentPage={currentPage} />
79-
</>
80-
);
81-
}
82-
83-
function NotFound() {
84-
return <ErrorComponent title="Error" description="The licenses data could not be loaded. Please try again later." />;
85-
}
95+
function NotFound() {
96+
return <ErrorComponent title="Error" description="The licenses data could not be loaded. Please try again later." />;
97+
}

app/node/[nodeAddr]/page.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,10 @@ const fetchLicenseDetailsAndNodeAvailability = async (
8686
nodeResponse: types.OraclesAvailabilityResult & types.OraclesDefaultResult;
8787
}> => {
8888
let nodeAddress: types.EthAddress,
89-
totalAssignedAmount: bigint,
90-
totalClaimedAmount: bigint,
91-
firstMiningEpoch: bigint | undefined,
89+
totalAssignedAmount: bigint,
90+
totalClaimedAmount: bigint,
91+
awbBalance: bigint,
92+
firstMiningEpoch: bigint | undefined,
9293
lastClaimEpoch: bigint,
9394
assignTimestamp: bigint,
9495
lastClaimOracle: types.EthAddress,
@@ -102,9 +103,10 @@ const fetchLicenseDetailsAndNodeAvailability = async (
102103
try {
103104
({
104105
nodeAddress,
105-
totalAssignedAmount,
106-
totalClaimedAmount,
107-
firstMiningEpoch,
106+
totalAssignedAmount,
107+
totalClaimedAmount,
108+
awbBalance,
109+
firstMiningEpoch,
108110
lastClaimEpoch,
109111
assignTimestamp,
110112
lastClaimOracle,
@@ -127,9 +129,10 @@ const fetchLicenseDetailsAndNodeAvailability = async (
127129

128130
const license: types.License = {
129131
nodeAddress,
130-
totalAssignedAmount,
131-
totalClaimedAmount,
132-
firstMiningEpoch,
132+
totalAssignedAmount,
133+
totalClaimedAmount,
134+
awbBalance,
135+
firstMiningEpoch,
133136
lastClaimEpoch,
134137
assignTimestamp,
135138
lastClaimOracle,

app/server-components/Licenses/License.tsx

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import ClientWrapper from '@/components/shared/ClientWrapper';
22
import { CopyableAddress } from '@/components/shared/CopyableValue';
3-
import { cachedGetLicense } from '@/lib/api/cache';
43
import { routePath } from '@/lib/routes';
54
import { isZeroAddress } from '@/lib/utils';
6-
import * as types from '@/typedefs/blockchain';
5+
import { LicenseListItem } from '@/typedefs/general';
76
import { Skeleton } from '@heroui/skeleton';
87
import clsx from 'clsx';
98
import { Suspense } from 'react';
@@ -14,39 +13,32 @@ import { SmallTag } from '../shared/SmallTag';
1413
import NodeSmallCard from './NodeSmallCard';
1514

1615
interface Props {
17-
licenseType: 'ND' | 'MND' | 'GND';
18-
licenseId: string;
16+
license: LicenseListItem;
1917
}
2018

21-
export default async function License({ licenseType, licenseId }: Props) {
22-
let owner: types.EthAddress;
23-
let nodeAddress: types.EthAddress;
24-
let totalAssignedAmount: string;
25-
let totalClaimedAmount: string;
26-
let assignTimestamp: string;
27-
let isBanned: boolean;
28-
29-
try {
30-
({ owner, nodeAddress, totalAssignedAmount, totalClaimedAmount, assignTimestamp, isBanned } = await cachedGetLicense(
31-
licenseType,
32-
licenseId,
33-
));
34-
} catch (error: any) {
35-
if (!error.message.includes('ERC721: invalid token ID')) {
36-
console.error({ licenseType, licenseId }, error);
37-
}
38-
return null;
39-
}
19+
export default function License({ license }: Props) {
20+
const {
21+
licenseType,
22+
licenseId,
23+
owner,
24+
nodeAddress,
25+
totalAssignedAmount,
26+
totalClaimedAmount,
27+
assignTimestamp,
28+
awbBalance,
29+
isBanned,
30+
} = license;
4031

4132
return (
4233
<BorderedCard useCustomWrapper useFixedWidthLarge>
4334
<div className="row justify-between gap-3 py-2 md:py-3 lg:gap-6">
4435
{/* License */}
4536
<LicenseSmallCard
46-
licenseId={Number(licenseId)}
37+
licenseId={licenseId}
4738
licenseType={licenseType}
4839
totalAssignedAmount={BigInt(totalAssignedAmount)}
4940
totalClaimedAmount={BigInt(totalClaimedAmount)}
41+
awbBalance={BigInt(awbBalance || '0')}
5042
isBanned={isBanned}
5143
isLink
5244
hideType

0 commit comments

Comments
 (0)