diff --git a/apps/web/pages/api/proofs/bns/index.ts b/apps/web/pages/api/proofs/bns/index.ts
index c276058..8ba2fb5 100644
--- a/apps/web/pages/api/proofs/bns/index.ts
+++ b/apps/web/pages/api/proofs/bns/index.ts
@@ -61,7 +61,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return res.status(404).json({ error: 'address is not eligible for early access' });
}
- const responseData: EarlyAccessProofResponse = {
+ const responseData: BNSProofResponse = {
...content,
proofs,
discountValidatorAddress: USERNAME_BNS_DISCOUNT_VALIDATORS[parsedChain],
diff --git a/apps/web/src/addresses/usernames.ts b/apps/web/src/addresses/usernames.ts
index dcb2409..d786cb7 100644
--- a/apps/web/src/addresses/usernames.ts
+++ b/apps/web/src/addresses/usernames.ts
@@ -39,7 +39,7 @@ export const USERNAME_EA_DISCOUNT_VALIDATORS: AddressMap = {
};
export const USERNAME_BNS_DISCOUNT_VALIDATORS: AddressMap = {
- [baseSepolia.id]: '0x',
+ [baseSepolia.id]: '0x1DE649d8b004A44491a7D3ebbb23F4B0DA89DE78',
[base.id]: '0x',
};
diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-nft.svg b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-nft.svg
new file mode 100644
index 0000000..55f870d
--- /dev/null
+++ b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/base-nft.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/bns.jpg b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/bns.jpg
new file mode 100644
index 0000000..9cc799e
Binary files /dev/null and b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/bns.jpg differ
diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
index 930acf4..8b19dbe 100644
--- a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
+++ b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx
@@ -8,6 +8,8 @@ import Link from 'next/link';
import baseBuildathonParticipant from './images/base-buildathon-participant.svg';
import summerPassLvl3 from './images/summer-pass-lvl-3.svg';
import cbidVerification from './images/cbid-verification.svg';
+import BNSOwnership from './images/bns.jpg';
+import BaseNFT from './images/base-nft.svg';
import coinbaseOneVerification from './images/coinbase-one-verification.svg';
import coinbaseVerification from './images/coinbase-verification.svg';
import { StaticImageData } from 'next/dist/shared/lib/get-img-props';
@@ -43,6 +45,12 @@ export default function RegistrationLearnMoreModal({
const SummerPassRowClasses = classNames(rowClasses, {
'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.SUMMER_PASS_LVL_3),
});
+ const BNSRowClasses = classNames(rowClasses, {
+ 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.BNS_NAME),
+ });
+ const BaseDotEthNFTRowClasses = classNames(rowClasses, {
+ 'opacity-40': hasDiscount && !allActiveDiscounts.has(Discount.BASE_ETH_NFT),
+ });
const qualifiedClasses = classNames(
'flex flex-row items-center justify-center py-3 px-1 h-5 text-xs bg-green-0 rounded ml-3',
@@ -89,9 +97,9 @@ export default function RegistrationLearnMoreModal({
width={30}
height={30}
wrapperClassName="rounded-full"
- imageClassName={CBRowClasses}
+ imageClassName={CB1RowClasses}
/>
-
Coinbase One verification
+ Coinbase One verification
@@ -110,9 +118,9 @@ export default function RegistrationLearnMoreModal({
width={30}
height={30}
wrapperClassName="rounded-full"
- imageClassName={CBRowClasses}
+ imageClassName={CBIDRowClasses}
/>
- A cb.id username
+ A cb.id username
@@ -131,9 +139,9 @@ export default function RegistrationLearnMoreModal({
width={30}
height={30}
wrapperClassName="rounded-full"
- imageClassName={CBRowClasses}
+ imageClassName={BuildathonRowClasses}
/>
- Base buildathon participant
+ Base buildathon participant
@@ -152,9 +160,9 @@ export default function RegistrationLearnMoreModal({
width={30}
height={30}
wrapperClassName="rounded-full"
- imageClassName={CBRowClasses}
+ imageClassName={SummerPassRowClasses}
/>
- Summer Pass Level 3
+ Summer Pass Level 3
@@ -164,6 +172,48 @@ export default function RegistrationLearnMoreModal({
)}
+
+
+
+
+ {allActiveDiscounts.has(Discount.BNS_NAME) && (
+
+ )}
+
+
+
+
+
+ {allActiveDiscounts.has(Discount.BASE_ETH_NFT) && (
+
+ )}
+
{!hasDiscount && (
<>
diff --git a/apps/web/src/hooks/useAggregatedDiscountValidators.ts b/apps/web/src/hooks/useAggregatedDiscountValidators.ts
index db78cda..f2a2862 100644
--- a/apps/web/src/hooks/useAggregatedDiscountValidators.ts
+++ b/apps/web/src/hooks/useAggregatedDiscountValidators.ts
@@ -4,6 +4,10 @@ import {
useCheckCBIDAttestations,
useCheckCoinbaseAttestations,
useCheckEAAttestations,
+ // useBuildathonAttestations,
+ // useSummerPassAttestations,
+ // useBaseDotEthAttestations,
+ useBNSAttestations,
} from 'apps/web/src/hooks/useAttestations';
import { useActiveDiscountValidators } from 'apps/web/src/hooks/useReadActiveDiscountValidators';
import { Discount } from 'apps/web/src/utils/usernames';
@@ -32,13 +36,21 @@ export function useAggregatedDiscountValidators() {
const { data: EAData, loading: loadingEAAttestations } = useCheckEAAttestations();
const { data: coinbaseData, loading: loadingCoinbaseAttestations } =
useCheckCoinbaseAttestations();
+ // const { data: BuildathonData, loading: loadingBuildathon } = useBuildathonAttestations();
+ // const { data: SummerPassData, loading: loadingSummerPass } = useSummerPassAttestations();
+ // const { data: BaseDotEthData, loading: loadingBaseDotEth } = useBaseDotEthAttestations();
+ const { data: BNSData, loading: loadingBNS } = useBNSAttestations();
const loadingDiscounts =
loadingCoinbaseAttestations ||
loadingCBIDAttestations ||
loadingCB1Attestations ||
loadingActiveDiscounts ||
- loadingEAAttestations;
+ loadingEAAttestations ||
+ // loadingBuildathon ||
+ // loadingSummerPass ||
+ // loadingBaseDotEth ||
+ loadingBNS;
const discountsToAttestationData = useMemo(() => {
const discountMapping: MappedDiscountData = {};
@@ -59,14 +71,51 @@ export function useAggregatedDiscountValidators() {
discountKey: validator.key,
};
}
-
if (EAData && validator.discountValidator === EAData.discountValidatorAddress) {
discountMapping[Discount.EARLY_ACCESS] = { ...EAData, discountKey: validator.key };
}
+
+ // if (
+ // BuildathonData &&
+ // validator.discountValidator === BuildathonData.discountValidatorAddress
+ // ) {
+ // discountMapping[Discount.BASE_BUILDATHON_PARTICIPANT] = {
+ // ...BuildathonData,
+ // discountKey: validator.key,
+ // };
+ // }
+ // if (
+ // SummerPassData &&
+ // validator.discountValidator === SummerPassData.discountValidatorAddress
+ // ) {
+ // discountMapping[Discount.SUMMER_PASS_LVL_3] = {
+ // ...SummerPassData,
+ // discountKey: validator.key,
+ // };
+ // }
+ // if (
+ // BaseDotEthData &&
+ // validator.discountValidator === BaseDotEthData.discountValidatorAddress
+ // ) {
+ // discountMapping[Discount.BASE_ETH_NFT] = { ...BaseDotEthData, discountKey: validator.key };
+ // }
+ if (BNSData && validator.discountValidator === BNSData.discountValidatorAddress) {
+ discountMapping[Discount.BNS_NAME] = { ...BNSData, discountKey: validator.key };
+ }
});
return discountMapping;
- }, [activeDiscountValidators, CBIDData, CB1Data, coinbaseData, EAData]);
+ }, [
+ activeDiscountValidators,
+ CBIDData,
+ CB1Data,
+ coinbaseData,
+ EAData,
+ // BuildathonData,
+ // SummerPassData,
+ // BaseDotEthData,
+ BNSData,
+ ]);
return {
data: discountsToAttestationData,
diff --git a/apps/web/src/hooks/useAttestations.ts b/apps/web/src/hooks/useAttestations.ts
index 5d094f9..6aeacad 100644
--- a/apps/web/src/hooks/useAttestations.ts
+++ b/apps/web/src/hooks/useAttestations.ts
@@ -10,6 +10,7 @@ import { Address, ReadContractErrorType, encodeAbiParameters } from 'viem';
import { useAccount, useReadContract } from 'wagmi';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { useErrors } from 'apps/web/contexts/Errors';
+import { BNSProofResponse } from 'apps/web/pages/api/proofs/bns';
export type AttestationData = {
discountValidatorAddress: Address;
@@ -225,17 +226,13 @@ export function useCheckEAAttestations(): AttestationHookReturns {
useEffect(() => {
async function checkEarlyAccess(a: string) {
- try {
- const params = new URLSearchParams();
- params.append('address', a);
- params.append('chain', basenameChain.id.toString());
- const response = await fetch(`/api/proofs/earlyAccess?${params}`);
- if (response.ok) {
- const result = (await response.json()) as EarlyAccessProofResponse;
- setEAProofResponse(result);
- }
- } catch (error) {
- logError(error, 'Error checking early access');
+ const params = new URLSearchParams();
+ params.append('address', a);
+ params.append('chain', basenameChain.id.toString());
+ const response = await fetch(`/api/proofs/earlyAccess?${params}`);
+ if (response.ok) {
+ const result = (await response.json()) as EarlyAccessProofResponse;
+ setEAProofResponse(result);
}
}
@@ -281,3 +278,75 @@ export function useCheckEAAttestations(): AttestationHookReturns {
}
return { data: null, loading: isLoading, error };
}
+
+// export function useBuildathonAttestations() {
+// return { data: null, loading: isLoading, error };
+// }
+// export function useSummerPassAttestations() {
+// return { data: null, loading: isLoading, error };
+// }
+// export function useBaseDotEthAttestations() {
+// return { data: null, loading: isLoading, error };
+// }
+
+// merkle tree discount calls api endpoint
+export function useBNSAttestations() {
+ const { address } = useAccount();
+ const [proofResponse, setProofResponse] = useState(null);
+ const { basenameChain } = useBasenameChain();
+ const { logError } = useErrors();
+
+ useEffect(() => {
+ async function checkBNS(a: string) {
+ const params = new URLSearchParams();
+ params.append('address', a);
+ params.append('chain', basenameChain.id.toString());
+ const response = await fetch(`/api/proofs/bns?${params}`);
+ if (response.ok) {
+ const result = (await response.json()) as BNSProofResponse;
+ setProofResponse(result);
+ }
+ }
+
+ if (address) {
+ checkBNS(address).catch((error) => {
+ logError(error, 'Error checking BNS discount availability');
+ });
+ }
+ }, [address, basenameChain.id, logError]);
+
+ const encodedProof = useMemo(
+ () =>
+ proofResponse?.proofs
+ ? encodeAbiParameters([{ type: 'bytes32[]' }], [proofResponse?.proofs])
+ : '0x0',
+ [proofResponse?.proofs],
+ );
+
+ const readContractArgs = useMemo(() => {
+ if (!proofResponse?.proofs || !address) {
+ return {};
+ }
+ return {
+ address: proofResponse?.discountValidatorAddress,
+ abi: EarlyAccessValidatorABI,
+ functionName: 'isValidDiscountRegistration',
+ args: [address, encodedProof],
+ };
+ }, [address, proofResponse?.discountValidatorAddress, proofResponse?.proofs, encodedProof]);
+
+ const { data: isValid, isLoading, error } = useReadContract(readContractArgs);
+
+ if (isValid && proofResponse && address) {
+ return {
+ data: {
+ discountValidatorAddress: proofResponse.discountValidatorAddress,
+ discount: Discount.BNS_NAME,
+ validationData: encodedProof,
+ },
+ loading: false,
+ error: null,
+ };
+ }
+ return { data: null, loading: isLoading, error };
+}
diff --git a/apps/web/src/utils/usernames.ts b/apps/web/src/utils/usernames.ts
index 3f3689a..a594f19 100644
--- a/apps/web/src/utils/usernames.ts
+++ b/apps/web/src/utils/usernames.ts
@@ -335,6 +335,8 @@ export enum Discount {
COINBASE_VERIFIED_ACCOUNT = 'COINBASE_VERIFIED_ACCOUNT',
BASE_BUILDATHON_PARTICIPANT = 'BASE_BUILDATHON_PARTICIPANT',
SUMMER_PASS_LVL_3 = 'SUMMER_PASS_LVL_3',
+ BNS_NAME = 'BNS_NAME',
+ BASE_ETH_NFT = 'BASE_ETH_NFT',
}
export function isValidDiscount(key: string): key is keyof typeof Discount {