From 7f031defb0571b3739bd76e7b0f50418e639ef94 Mon Sep 17 00:00:00 2001 From: katzman Date: Mon, 11 Nov 2024 17:16:01 -0800 Subject: [PATCH] feat(BAPP-790): Devcon discount validator (#1246) --- apps/web/src/addresses/usernames.ts | 5 +++ .../images/devcon.png | Bin 0 -> 2815 bytes .../RegistrationLearnMoreModal/index.tsx | 8 ++++ .../hooks/useAggregatedDiscountValidators.ts | 13 +++++- apps/web/src/hooks/useAttestations.ts | 37 ++++++++++++++++++ apps/web/src/utils/usernames.ts | 1 + 6 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/devcon.png diff --git a/apps/web/src/addresses/usernames.ts b/apps/web/src/addresses/usernames.ts index 43e6e2f9ad..110fd65b0b 100644 --- a/apps/web/src/addresses/usernames.ts +++ b/apps/web/src/addresses/usernames.ts @@ -101,3 +101,8 @@ export const BASE_WORLD_DISCOUNT_VALIDATORS: AddressMap = { [baseSepolia.id]: '0xFa69f6167F40247fe3EFF2d8375B25C5d7834c48', [base.id]: '0xfEb00a4EfF372a307fDc556Cf4359f7D679E4d11', }; + +export const DEVCON_DISCOUNT_VALIDATORS: AddressMap = { + [baseSepolia.id]: '0x5c81c392C22Cba477a70D809DE6d6Cd362A1c3DE', + [base.id]: '0xFca2EB54EaB56085e25a32BfF30fe8C452216c5F', +}; diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/devcon.png b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/images/devcon.png new file mode 100644 index 0000000000000000000000000000000000000000..3b140e499dc238a14bab3f596dd34278bb695a84 GIT binary patch literal 2815 zcmZ`*c|4Ts7k_6)b~RbTD8|?oGxiKd3_@g0mh25i3}&WgvUan!xY;g3C|j1ew&J4f z>$O!Pg`e#rvL+$i8TnP8-~HX^{harl=bZ2Noadb9{o}o5dj2d2D~uHY01g9v9dnw7 z(}kIl_9prJe*yrIJsyiSHNaxwrbHh%ycZ4tBxA3}n4ANfakum)2v41nLD+^>aY8uc zE`Bu92H$Zu-zpc#$YRXWXf5^NT0fC}5BemOXm*G79g~*X9Z!DU!g^h?S3&1q>>ZYQ%yKGoxlD~9 z@KHSjc2znzekmsv-yiOE%ZVsVON~0ckPiw{d%E)nP}O$huS)M1gI+b&Y@bHK6454o z+HUQM;Ob1;yc2QO25!d2fHci!1`dHZ0SL_k(H;N<0}k!m0AL6b_->nnBo8oP0Eol` z38WI-)Fwu6LGzrTDe@DYJAwO(d4A8Q`8W_;Dg)0$18-?fwl+3GyZU&`I$!p2!O2p+ed&1sbt;->dgI8> zaH_W#frO@NAodYxnoV~j5%7Ho`HBX@+SnA1^&#Tm%Caa~6avEvhr`v0m)+3jI(i3m z+D-%EK_>g6kw^-KB1=(_^&z?==8pcneSzMT_C#s8>8ARV+tYY<6~AmwCH$p1$p z?f3PqoH{)j+7wU4dD-aTy=kMS9StLgQdQqC^N+}ngMMRPAmNBuA8#6wjQMd_2jriF z|4ZC2Y5lJye~SFXq_==JA>wJ(oar;f$f+a$;XA;qBk2SFY2e>(bKgt5P7JF$^82TO zVI?zUo&^9#djlOUOKX+~iFjX&L7ujdI4>E8u-f+a!q$jnzPwxx@dhYwUd-LOGfu~1n-538ca=3L(}i9NLG{* zp!3*=YRSkqyP=MYYMFwmv;W|akH<1vFU2X`(_pACTP?lPk!Xq)Nsmg z7n-}PmMM;6Yzj(Blt<9Hlqlxa;4oonrW=s5ZA1ny~+ z`bUYk*)t!ibo7>$=iSjZ+tCjcD|$|TQnj>+AkD4q9R-KXEueX+dgF|(K2))e8frhd)uYz9%b0@DHswF)!=nrH*o5%IGqz`pc0d+b; zso~7ICDDc(iMhMN1%adm&2@Sp>`9LQgPKOZzx z^G-_o{hud8Fs&ZdjeCnvrqu0jIY@=yyRWe6{|m>JdhAwWUi-)nVl6czv$*oNo3-8^ zJUNzDgxV6n6=9ddQ43HQCh&_AhM*i1tJbYxlC-v5aN+%jh1_YC3zr#&S1@ak^x>yG zgU#N%pId9#Kc_BV4>(Ppb+bH)^YEz7 zjIIRo<8?v1#Ap%Z#qqAirgYQRp>9#4(CTWu(4J(0l?LJv_y(VL{-dtVorbaTuT{w} zHLO}W_8!iEV6JLwm#J{-4FK{nsT-+d(?css7nYi~7t@GKV~>HTMLplyYbMKUNd@{g zl5TS(;fa?@eBye2A1=R7;>6<@CR#$@QL`&P5vCTsKZlebCBbWr_;@X|b92krs^uAL zwos0;ZkJZ&^Vx(|@=E)%#!uQ=T$pSmY1t`?NCOj@z9h5fi+-KgMEfpvLKuhm3E<^M1yJsMu)M1oykQ6edT;C45L1IlGI{tj0&GE2tGd zkDPH;Mg7Ihe2*JaaB75b?-9F7R}!yI(Y4q|%Z}q}nr|++gr1}Sml)`t*D2O^y7@Q2 Cw4{{) literal 0 HcmV?d00001 diff --git a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx index 5d8169c427..62a8ba495d 100644 --- a/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx +++ b/apps/web/src/components/Basenames/RegistrationLearnMoreModal/index.tsx @@ -10,6 +10,7 @@ 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 DevconPNG from './images/devcon.png'; import TalentProtocolIcon from './images/TalentProtocol.svg'; import coinbaseOneVerification from './images/coinbase-one-verification.svg'; import coinbaseVerification from './images/coinbase-verification.svg'; @@ -95,6 +96,13 @@ const DISCOUNT_ITEMS: DiscountItem[] = [ label: 'Base around the world NFT', tooltipContent: 'Available for anyone holding one of the Base around the world NFTs', }, + { + discount: Discount.DEVCON, + icon: DevconPNG, + alt: 'icon of Devcon', + label: 'Devcon attendance NFT', + tooltipContent: 'Available for anyone holding one of the Base Devcon NFTs', + }, ]; export default function RegistrationLearnMoreModal({ diff --git a/apps/web/src/hooks/useAggregatedDiscountValidators.ts b/apps/web/src/hooks/useAggregatedDiscountValidators.ts index 0e80c6023e..d34263d162 100644 --- a/apps/web/src/hooks/useAggregatedDiscountValidators.ts +++ b/apps/web/src/hooks/useAggregatedDiscountValidators.ts @@ -8,6 +8,7 @@ import { useCheckCBIDAttestations, useCheckCoinbaseAttestations, useCheckEAAttestations, + useDevconAttestations, useDiscountCodeAttestations, useSummerPassAttestations, useTalentProtocolAttestations, @@ -58,6 +59,7 @@ export function useAggregatedDiscountValidators(code?: string) { const { data: TalentProtocolData, loading: loadingTalentProtocolAttestations } = useTalentProtocolAttestations(); const { data: BaseWorldData, loading: loadingBaseWorld } = useBaseWorldAttestations(); + const { data: DevconData, loading: loadingDevcon } = useDevconAttestations(); const loadingDiscounts = loadingCoinbaseAttestations || @@ -71,7 +73,8 @@ export function useAggregatedDiscountValidators(code?: string) { loadingBNS || loadingDiscountCode || loadingTalentProtocolAttestations || - loadingBaseWorld; + loadingBaseWorld || + loadingDevcon; const discountsToAttestationData = useMemo(() => { const discountMapping: MappedDiscountData = {}; @@ -153,6 +156,13 @@ export function useAggregatedDiscountValidators(code?: string) { discountKey: validator.key, }; } + + if (DevconData && validator.discountValidator === DevconData.discountValidatorAddress) { + discountMapping[Discount.DEVCON] = { + ...DevconData, + discountKey: validator.key, + }; + } }); return discountMapping; @@ -169,6 +179,7 @@ export function useAggregatedDiscountValidators(code?: string) { DiscountCodeData, TalentProtocolData, BaseWorldData, + DevconData, ]); return { diff --git a/apps/web/src/hooks/useAttestations.ts b/apps/web/src/hooks/useAttestations.ts index aab973f6e1..a849032785 100644 --- a/apps/web/src/hooks/useAttestations.ts +++ b/apps/web/src/hooks/useAttestations.ts @@ -12,6 +12,7 @@ import { BASE_DOT_ETH_ERC721_DISCOUNT_VALIDATOR, BASE_WORLD_DISCOUNT_VALIDATORS, BUILDATHON_ERC721_DISCOUNT_VALIDATOR, + DEVCON_DISCOUNT_VALIDATORS, TALENT_PROTOCOL_DISCOUNT_VALIDATORS, USERNAME_1155_DISCOUNT_VALIDATORS, } from 'apps/web/src/addresses/usernames'; @@ -638,3 +639,39 @@ export function useBaseWorldAttestations() { return { data: null, loading: isLoading, error }; } + +const devconTokenIds = [BigInt(100), BigInt(101)]; + +export function useDevconAttestations() { + const { address } = useAccount(); + const { basenameChain } = useBasenameChain(); + + const discountValidatorAddress = DEVCON_DISCOUNT_VALIDATORS[basenameChain.id]; + + const readContractArgs = useMemo(() => { + if (!address) { + return {}; + } + return { + address: discountValidatorAddress, + abi: ERC1155DiscountValidatorV2, + functionName: 'isValidDiscountRegistration', + args: [address, encodeAbiParameters([{ type: 'uint256[]' }], [devconTokenIds])], + }; + }, [address, discountValidatorAddress]); + + const { data: isValid, isLoading, error } = useReadContract({ ...readContractArgs, query: {} }); + if (isValid && address) { + return { + data: { + discountValidatorAddress, + discount: Discount.DEVCON, + validationData: encodeAbiParameters([{ type: 'uint256[]' }], [devconTokenIds]), + }, + 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 dc8a783835..43041fbe88 100644 --- a/apps/web/src/utils/usernames.ts +++ b/apps/web/src/utils/usernames.ts @@ -399,6 +399,7 @@ export enum Discount { DISCOUNT_CODE = 'DISCOUNT_CODE', TALENT_PROTOCOL = 'TALENT_PROTOCOL', BASE_WORLD = 'BASE_WORLD', + DEVCON = 'DEVCON', } export function isValidDiscount(key: string): key is keyof typeof Discount {