Commit 5dce68a6 authored by aballerr's avatar aballerr Committed by GitHub

feat: Implementing claims logic, adding error state and minor copy change (#5357)

* Implementing claims logic
parent 9dd8ad1d
[
{
"inputs": [
{
"internalType": "address",
"name": "token_",
"type": "address"
},
{
"internalType": "bytes32",
"name": "merkleRoot_",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "endTime_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AlreadyClaimed",
"type": "error"
},
{
"inputs": [],
"name": "ClaimWindowFinished",
"type": "error"
},
{
"inputs": [],
"name": "EndTimeInPast",
"type": "error"
},
{
"inputs": [],
"name": "InvalidProof",
"type": "error"
},
{
"inputs": [],
"name": "NoWithdrawDuringClaim",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Claimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes32[]",
"name": "merkleProof",
"type": "bytes32[]"
}
],
"name": "claim",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "endTime",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "isClaimed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "merkleRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "token",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdraw",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
import { BigNumber } from '@ethersproject/bignumber'
import type { TransactionResponse } from '@ethersproject/providers'
import { useWeb3React } from '@web3-react/core'
import uniswapNftAirdropClaim from 'abis/uniswap-nft-airdrop-claim.json'
import airdropBackgroundv2 from 'assets/images/airdopBackground.png' import airdropBackgroundv2 from 'assets/images/airdopBackground.png'
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button' import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
import { OpacityHoverState } from 'components/Common' import { OpacityHoverState } from 'components/Common'
import Loader from 'components/Loader' import Loader from 'components/Loader'
import { UNISWAP_NFT_AIRDROP_CLAIM_ADDRESS } from 'constants/addresses'
import { useContract } from 'hooks/useContract'
import { ChevronRightIcon } from 'nft/components/icons' import { ChevronRightIcon } from 'nft/components/icons'
import { useState } from 'react' import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable'
import { CollectionRewardsFetcher } from 'nft/queries/genie/GetAirdorpMerkle'
import { Airdrop, Rewards } from 'nft/types/airdrop'
import { useEffect, useState } from 'react'
import { AlertTriangle } from 'react-feather'
import { useModalIsOpen, useToggleModal } from 'state/application/hooks' import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer' import { ApplicationModal } from 'state/application/reducer'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
...@@ -23,7 +33,6 @@ const Body = styled.div` ...@@ -23,7 +33,6 @@ const Body = styled.div`
const ClaimButton = styled(ThemeButton)` const ClaimButton = styled(ThemeButton)`
width: 100%; width: 100%;
background-color: ${({ theme }) => theme.accentAction}; background-color: ${({ theme }) => theme.accentAction};
margin-top: 40px;
border-radius: 12px; border-radius: 12px;
color: ${({ theme }) => theme.white}; color: ${({ theme }) => theme.white};
` `
...@@ -117,6 +126,22 @@ const SyledCloseIcon = styled(CloseIcon)` ...@@ -117,6 +126,22 @@ const SyledCloseIcon = styled(CloseIcon)`
${OpacityHoverState} ${OpacityHoverState}
` `
const Error = styled.div`
display: flex;
color: ${({ theme }) => theme.accentCritical};
font-weight: 500;
line-height: 24px;
border-radius: 16px;
padding: 12px 20px;
font-size: 14px;
align-items: center;
gap: 12px;
`
const ReactLinkWrap = styled.div`
margin-bottom: 40px;
`
const RewardsText = styled.span` const RewardsText = styled.span`
font-size: 12px; font-size: 12px;
line-height: 16px; line-height: 16px;
...@@ -142,91 +167,166 @@ const MainHeader = styled.span` ...@@ -142,91 +167,166 @@ const MainHeader = styled.span`
color: ${({ theme }) => theme.white}; color: ${({ theme }) => theme.white};
` `
const EtherscanLinkWrap = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
`
enum RewardAmounts {
tradingRewardAmount = 300,
holderRewardAmount = 1000,
combinedAmount = 1300,
}
const AirdropModal = () => { const AirdropModal = () => {
const [isClaimed, setClaimed] = useState(false) const { account, provider } = useWeb3React()
const [claim, setClaim] = useState<Rewards>()
const [isClaimed, setIsClaimed] = useState(false)
const [hash, setHash] = useState('')
const [error, setError] = useState(false)
const setIsClaimAvailable = useIsNftClaimAvailable((state) => state.setIsClaimAvailable)
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [totalAmount] = useState(300) const [totalAmount, setTotalAmount] = useState(0)
const isOpen = useModalIsOpen(ApplicationModal.UNISWAP_NFT_AIRDROP_CLAIM) const isOpen = useModalIsOpen(ApplicationModal.UNISWAP_NFT_AIRDROP_CLAIM)
const usdcAirdropToggle = useToggleModal(ApplicationModal.UNISWAP_NFT_AIRDROP_CLAIM) const usdcAirdropToggle = useToggleModal(ApplicationModal.UNISWAP_NFT_AIRDROP_CLAIM)
const dismiss = () => { const contract = useContract(UNISWAP_NFT_AIRDROP_CLAIM_ADDRESS, uniswapNftAirdropClaim)
usdcAirdropToggle()
const displayError = () => {
setIsSubmitting(false)
setError(true)
setTimeout(() => { setTimeout(() => {
setClaimed(false) setError(false)
}, 500) }, 5000)
} }
const submit = () => { useEffect(() => {
setIsSubmitting(true) if (account && provider && contract) {
;(async () => {
try {
const { data } = await CollectionRewardsFetcher(account)
const claim = data.find((claim) => claim?.rewardType === Airdrop.GENIE_UNISWAP_USDC_AIRDROP)
setTimeout(() => { if (!claim) return
const [isClaimed] = await contract.connect(provider).functions.isClaimed(claim?.index)
if (claim && isClaimed === false) {
const usdAmount = BigNumber.from(claim.amount).div(10 ** 6)
setClaim(claim)
setTotalAmount(usdAmount.toNumber())
setIsClaimAvailable(true)
}
} catch (err) {
displayError()
}
})()
}
}, [account, contract, provider, setIsClaimAvailable])
const makeClaim = async () => {
try {
if (contract && claim && claim.amount && claim.merkleProof && provider) {
setIsSubmitting(true)
const response: TransactionResponse = await contract
.connect(provider?.getSigner())
.functions.claim(claim.index, account, claim?.amount, claim?.merkleProof)
setHash(response.hash)
setIsSubmitting(false)
setIsClaimed(true)
setIsClaimAvailable(false)
}
} catch (err) {
setIsSubmitting(false) setIsSubmitting(false)
setClaimed(true) displayError()
}, 1000) }
} }
return ( return (
<Modal hideBorder isOpen={isOpen} onDismiss={dismiss} maxHeight={90} maxWidth={400}> <>
<ModalWrap> <Modal hideBorder isOpen={isOpen} onDismiss={usdcAirdropToggle} maxHeight={90} maxWidth={400}>
{isClaimed ? ( <ModalWrap>
<ClaimContainer> {isClaimed ? (
<ThemedText.HeadlineSmall>Congratulations!</ThemedText.HeadlineSmall> <ClaimContainer>
<SuccessText> <ThemedText.HeadlineSmall>Congratulations!</ThemedText.HeadlineSmall>
You have successfully claimed {totalAmount} USDC. Thank you for supporting Genie.xyz. <SuccessText>
</SuccessText> You have successfully claimed {totalAmount} USDC. Thank you for supporting Genie.xyz.
<EtherscanLink href="https://etherscan.io/" target="_blank"> </SuccessText>
<ThemedText.Link> <EtherscanLink href={`https://etherscan.io/tx/${hash}`} target="_blank">
<div style={{ display: 'flex', alignItems: 'center', textAlign: 'center', justifyContent: 'center' }}> <ThemedText.Link>
<span style={{ marginRight: 8 }}>Etherscan</span> <EtherscanLinkWrap>
<ChevronRightIcon /> <span>Etherscan</span>
</div> <ChevronRightIcon />
</ThemedText.Link> </EtherscanLinkWrap>
</EtherscanLink> </ThemedText.Link>
</EtherscanLink>
<CloseButton size={ButtonSize.medium} emphasis={ButtonEmphasis.medium} onClick={dismiss}>
Close <CloseButton size={ButtonSize.medium} emphasis={ButtonEmphasis.medium} onClick={usdcAirdropToggle}>
</CloseButton> Close
</ClaimContainer> </CloseButton>
) : ( </ClaimContainer>
<> ) : (
<ImageContainer> <>
<TextContainer> <ImageContainer>
<SyledCloseIcon onClick={dismiss} stroke="white" /> <TextContainer>
<MainHeader>Uniswap NFT Airdrop</MainHeader> <SyledCloseIcon onClick={usdcAirdropToggle} stroke="white" />
<USDCLabel>{totalAmount} USDC</USDCLabel> <MainHeader>Uniswap NFT Airdrop</MainHeader>
<Line /> <USDCLabel>{totalAmount} USDC</USDCLabel>
<RewardsDetailsContainer> <Line />
<RewardsText>Trading rewards</RewardsText> <CurrencyText>300 USDC</CurrencyText> <RewardsDetailsContainer>
</RewardsDetailsContainer> <RewardsText>Trading rewards</RewardsText>{' '}
<RewardsDetailsContainer> <CurrencyText>
<RewardsText>Genie NFT holder rewards</RewardsText> <CurrencyText>0</CurrencyText> {totalAmount === RewardAmounts.tradingRewardAmount || totalAmount === RewardAmounts.combinedAmount
</RewardsDetailsContainer> ? `${RewardAmounts.tradingRewardAmount} USDC`
</TextContainer> : '0'}
<StyledImage src={airdropBackgroundv2} /> </CurrencyText>
</ImageContainer> </RewardsDetailsContainer>
<Body> <RewardsDetailsContainer>
<RewardsInformationText> <RewardsText>Genie NFT holder rewards</RewardsText>{' '}
As a long time supporter of Genie you’ve been awarded {totalAmount} USDC tokens. Read more about Uniswap <CurrencyText>
NFT. {totalAmount !== RewardAmounts.tradingRewardAmount
</RewardsInformationText> ? `${RewardAmounts.holderRewardAmount} USDC`
<LinkWrap href="https://uniswap.org/blog/uniswap-nft-aggregator-announcement" target="_blank"> : '0'}
<ThemedText.Link>Read more about Uniswap NFT.</ThemedText.Link> </CurrencyText>
</LinkWrap> </RewardsDetailsContainer>
</TextContainer>
<ClaimButton <StyledImage src={airdropBackgroundv2} />
onClick={submit} </ImageContainer>
size={ButtonSize.medium} <Body>
emphasis={ButtonEmphasis.medium} <RewardsInformationText>
disabled={isSubmitting} As a long time supporter of Genie, you’ve been awarded {totalAmount} USDC tokens.
> </RewardsInformationText>
{isSubmitting && <Loader stroke="white" />} <ReactLinkWrap>
<span>Claim{isSubmitting && 'ing'} USDC</span> <LinkWrap href="https://uniswap.org/blog/uniswap-nft-aggregator-announcement" target="_blank">
</ClaimButton> <ThemedText.Link>Read more about Uniswap NFT.</ThemedText.Link>
</Body> </LinkWrap>
</> </ReactLinkWrap>
)}
</ModalWrap> {error && (
</Modal> <Error>
<AlertTriangle />
Claim USDC failed. Please try again later
</Error>
)}
<ClaimButton
onClick={makeClaim}
size={ButtonSize.medium}
emphasis={ButtonEmphasis.medium}
disabled={isSubmitting}
>
{isSubmitting && <Loader stroke="white" />}
<span>Claim{isSubmitting && 'ing'} USDC</span>
</ClaimButton>
</Body>
</>
)}
</ModalWrap>
</Modal>
</>
) )
} }
......
...@@ -11,7 +11,7 @@ import { ApplicationModal } from 'state/application/reducer' ...@@ -11,7 +11,7 @@ import { ApplicationModal } from 'state/application/reducer'
const Bag = lazy(() => import('nft/components/bag/Bag')) const Bag = lazy(() => import('nft/components/bag/Bag'))
const TransactionCompleteModal = lazy(() => import('nft/components/collection/TransactionCompleteModal')) const TransactionCompleteModal = lazy(() => import('nft/components/collection/TransactionCompleteModal'))
const AirdropModal = lazy(() => import('components/AidropModal')) const AirdropModal = lazy(() => import('components/AirdropModal'))
export default function TopLevelModals() { export default function TopLevelModals() {
const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM) const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM)
......
...@@ -9,6 +9,7 @@ import useCopyClipboard from 'hooks/useCopyClipboard' ...@@ -9,6 +9,7 @@ import useCopyClipboard from 'hooks/useCopyClipboard'
import useStablecoinPrice from 'hooks/useStablecoinPrice' import useStablecoinPrice from 'hooks/useStablecoinPrice'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { useProfilePageState, useSellAsset, useWalletCollections } from 'nft/hooks' import { useProfilePageState, useSellAsset, useWalletCollections } from 'nft/hooks'
import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable'
import { ProfilePageStateType } from 'nft/types' import { ProfilePageStateType } from 'nft/types'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { Copy, ExternalLink, Power } from 'react-feather' import { Copy, ExternalLink, Power } from 'react-feather'
...@@ -117,6 +118,7 @@ const AuthenticatedHeader = () => { ...@@ -117,6 +118,7 @@ const AuthenticatedHeader = () => {
const setSellPageState = useProfilePageState((state) => state.setProfilePageState) const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
const resetSellAssets = useSellAsset((state) => state.reset) const resetSellAssets = useSellAsset((state) => state.reset)
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters) const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
const unclaimedAmount: CurrencyAmount<Token> | undefined = useUserUnclaimedAmount(account) const unclaimedAmount: CurrencyAmount<Token> | undefined = useUserUnclaimedAmount(account)
const isUnclaimed = useUserHasAvailableClaim(account) const isUnclaimed = useUserHasAvailableClaim(account)
...@@ -187,7 +189,7 @@ const AuthenticatedHeader = () => { ...@@ -187,7 +189,7 @@ const AuthenticatedHeader = () => {
<Trans>Claim</Trans> {unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} <Trans>reward</Trans> <Trans>Claim</Trans> {unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} <Trans>reward</Trans>
</UNIButton> </UNIButton>
)} )}
{nftFlag === NftVariant.Enabled && ( {nftFlag === NftVariant.Enabled && isClaimAvailable && (
<UNIButton size={ButtonSize.medium} emphasis={ButtonEmphasis.medium} onClick={openNftModal}> <UNIButton size={ButtonSize.medium} emphasis={ButtonEmphasis.medium} onClick={openNftModal}>
<Trans>Claim Uniswap NFT Airdrop</Trans> <Trans>Claim Uniswap NFT Airdrop</Trans>
</UNIButton> </UNIButton>
......
...@@ -7,6 +7,7 @@ import WalletDropdown from 'components/WalletDropdown' ...@@ -7,6 +7,7 @@ import WalletDropdown from 'components/WalletDropdown'
import { getConnection } from 'connection/utils' import { getConnection } from 'connection/utils'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft' import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { Portal } from 'nft/components/common/Portal' import { Portal } from 'nft/components/common/Portal'
import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable'
import { getIsValidSwapQuote } from 'pages/Swap' import { getIsValidSwapQuote } from 'pages/Swap'
import { darken } from 'polished' import { darken } from 'polished'
import { useMemo, useRef } from 'react' import { useMemo, useRef } from 'react'
...@@ -14,6 +15,7 @@ import { AlertTriangle, ChevronDown, ChevronUp } from 'react-feather' ...@@ -14,6 +15,7 @@ import { AlertTriangle, ChevronDown, ChevronUp } from 'react-feather'
import { useAppSelector } from 'state/hooks' import { useAppSelector } from 'state/hooks'
import { useDerivedSwapInfo } from 'state/swap/hooks' import { useDerivedSwapInfo } from 'state/swap/hooks'
import styled, { useTheme } from 'styled-components/macro' import styled, { useTheme } from 'styled-components/macro'
import { colors } from 'theme/colors'
import { flexRowNoWrap } from 'theme/styles' import { flexRowNoWrap } from 'theme/styles'
import { useOnClickOutside } from '../../hooks/useOnClickOutside' import { useOnClickOutside } from '../../hooks/useOnClickOutside'
...@@ -95,11 +97,16 @@ const Web3StatusConnectWrapper = styled.div<{ faded?: boolean }>` ...@@ -95,11 +97,16 @@ const Web3StatusConnectWrapper = styled.div<{ faded?: boolean }>`
} }
` `
const Web3StatusConnected = styled(Web3StatusGeneric)<{ pending?: boolean; isNftActive?: boolean }>` const Web3StatusConnected = styled(Web3StatusGeneric)<{
pending?: boolean
isNftActive?: boolean
isClaimAvailable?: boolean
}>`
background-color: ${({ pending, theme }) => (pending ? theme.deprecated_primary1 : theme.deprecated_bg1)}; background-color: ${({ pending, theme }) => (pending ? theme.deprecated_primary1 : theme.deprecated_bg1)};
border: 1px solid ${({ pending, theme }) => (pending ? theme.deprecated_primary1 : theme.deprecated_bg1)}; border: 1px solid ${({ pending, theme }) => (pending ? theme.deprecated_primary1 : theme.deprecated_bg1)};
color: ${({ pending, theme }) => (pending ? theme.deprecated_white : theme.deprecated_text1)}; color: ${({ pending, theme }) => (pending ? theme.deprecated_white : theme.deprecated_text1)};
font-weight: 500; font-weight: 500;
border: ${({ isClaimAvailable }) => isClaimAvailable && `1px solid ${colors.purple300}`};
:hover, :hover,
:focus { :focus {
border: 1px solid ${({ theme }) => darken(0.05, theme.deprecated_bg3)}; border: 1px solid ${({ theme }) => darken(0.05, theme.deprecated_bg3)};
...@@ -202,6 +209,7 @@ function Web3StatusInner() { ...@@ -202,6 +209,7 @@ function Web3StatusInner() {
const toggleWalletDropdown = useToggleWalletDropdown() const toggleWalletDropdown = useToggleWalletDropdown()
const toggleWalletModal = useToggleWalletModal() const toggleWalletModal = useToggleWalletModal()
const walletIsOpen = useModalIsOpen(ApplicationModal.WALLET_DROPDOWN) const walletIsOpen = useModalIsOpen(ApplicationModal.WALLET_DROPDOWN)
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
const error = useAppSelector((state) => state.connection.errorByConnectionType[getConnection(connector).type]) const error = useAppSelector((state) => state.connection.errorByConnectionType[getConnection(connector).type])
const isNftActive = useNftFlag() === NftVariant.Enabled const isNftActive = useNftFlag() === NftVariant.Enabled
...@@ -241,6 +249,7 @@ function Web3StatusInner() { ...@@ -241,6 +249,7 @@ function Web3StatusInner() {
isNftActive={isNftActive} isNftActive={isNftActive}
onClick={toggleWallet} onClick={toggleWallet}
pending={hasPendingTransactions} pending={hasPendingTransactions}
isClaimAvailable={isClaimAvailable}
> >
{!hasPendingTransactions && <StatusIcon size={24} connectionType={connectionType} />} {!hasPendingTransactions && <StatusIcon size={24} connectionType={connectionType} />}
{hasPendingTransactions ? ( {hasPendingTransactions ? (
......
...@@ -8,6 +8,8 @@ type AddressMap = { [chainId: number]: string } ...@@ -8,6 +8,8 @@ type AddressMap = { [chainId: number]: string }
export const UNI_ADDRESS: AddressMap = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984') export const UNI_ADDRESS: AddressMap = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
export const UNISWAP_NFT_AIRDROP_CLAIM_ADDRESS = '0x8B799381ac40b838BBA4131ffB26197C432AFe78'
export const V2_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V2_FACTORY_ADDRESS) export const V2_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V2_FACTORY_ADDRESS)
export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D')
......
import create from 'zustand'
import { devtools } from 'zustand/middleware'
interface NFTClaim {
isClaimAvailable: boolean
setIsClaimAvailable: (isClaimAvailable: boolean) => void
}
export const useIsNftClaimAvailable = create<NFTClaim>()(
devtools(
(set) => ({
isClaimAvailable: false,
setIsClaimAvailable: (isClaimAvailable: boolean) => {
set(() => ({ isClaimAvailable }))
},
}),
{ name: 'useIsNftClaimAvailable' }
)
)
import { Rewards } from 'nft/types/airdrop'
interface CollectionrRewardsResponse {
data: Array<Rewards>
}
export const CollectionRewardsFetcher = async (address: string): Promise<CollectionrRewardsResponse> => {
const url = `${process.env.REACT_APP_TEMP_API_URL}/nft/rewards/${address}?category=GENIE_UNISWAP_USDC_AIRDROP`
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 3000)
const r = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
clearInterval(timeoutId)
const data = await r.json()
return data
}
export enum Airdrop {
LOOKS_RARE_NFT_COMMERCE_REWARDS = 'LOOKS_RARE_NFT_COMMERCE_REWARDS',
GENIE_UNISWAP_USDC_AIRDROP = 'GENIE_UNISWAP_USDC_AIRDROP',
}
export interface Rewards {
amount: string
walletAddress: string
tokenAddress: string
merkleProof: Array<string>
rewardType: Airdrop
chainId: number
index: number
}
...@@ -83,6 +83,7 @@ export const colors = { ...@@ -83,6 +83,7 @@ export const colors = {
blueVibrant: '#587BFF', blueVibrant: '#587BFF',
// TODO: add magenta 50-900 // TODO: add magenta 50-900
magentaVibrant: '#FC72FF', magentaVibrant: '#FC72FF',
purple300: '#8440F2',
purple900: '#1C0337', purple900: '#1C0337',
// TODO: add all other vibrant variations // TODO: add all other vibrant variations
networkEthereum: '#627EEA', networkEthereum: '#627EEA',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment