diff --git a/app/[hackathon]/InteractionClient.tsx b/app/[hackathon]/InteractionClient.tsx index 676d382..59acf18 100644 --- a/app/[hackathon]/InteractionClient.tsx +++ b/app/[hackathon]/InteractionClient.tsx @@ -73,8 +73,7 @@ export default function InteractionClient() { const [syncing, setSyncing] = useState(false) const [lastSynced, setLastSynced] = useState(null) const [submissionOpen, setSubmissionOpen] = useState(false) - const [approvedTokens, setApprovedTokens] = useState([]) - const [tokenMinAmounts, setTokenMinAmounts] = useState>({}) + const [depositedTokens, setDepositedTokens] = useState([]) const [tokenSymbols, setTokenSymbols] = useState>({}) const [tokenTotals, setTokenTotals] = useState>({}) const [tokenDecimals, setTokenDecimals] = useState>({}) @@ -85,9 +84,6 @@ export default function InteractionClient() { const [sponsorName, setSponsorName] = useState("") const [sponsorImage, setSponsorImage] = useState("") const [isDepositing, setIsDepositing] = useState(false) - const [isSubmittingToken, setIsSubmittingToken] = useState(false) - const [submitTokenAddress, setSubmitTokenAddress] = useState("") - const [submitTokenName, setSubmitTokenName] = useState("") const [submitting, setSubmitting] = useState(false) const [needsApproval, setNeedsApproval] = useState(false) const [isApprovingToken, setIsApprovingToken] = useState(false) @@ -217,27 +213,18 @@ export default function InteractionClient() { // Load approved tokens and their minimums (optional on legacy contracts) // Use local copies within this function to avoid relying on async state updates - let localApprovedTokens: string[] = [] + let localDepositedTokens: string[] = [] let localTokenTotals: Record = {} let localTokenSymbols: Record = {} let localSponsors: Sponsor[] = [] try { - const tokens = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getApprovedTokensList' }) as string[] - console.log('Approved tokens from contract:', tokens) - setApprovedTokens(tokens) - const mins: Record = {} + const tokens = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getDepositedTokensList' }) as string[] + console.log('Deposited tokens from contract:', tokens) + setDepositedTokens(tokens) const symbols: Record = {} const totals: Record = {} const decimalsMap: Record = {} for (const t of tokens) { - try { - const min = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getTokenMinAmount', args: [t as `0x${string}`] }) as bigint - mins[t] = min - console.log(`✅ Token ${t} min amount:`, min.toString(), 'BigInt value:', min) - } catch (e) { - console.warn(`❌ Failed to get min amount for token ${t}:`, e) - mins[t] = BigInt(0) - } try { const total = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getTokenTotal', args: [t as `0x${string}`] }) as bigint totals[t] = total @@ -265,13 +252,11 @@ export default function InteractionClient() { } } } - console.log('📊 Setting tokenMinAmounts state:', mins) - setTokenMinAmounts(mins) setTokenSymbols(symbols) setTokenTotals(totals) setTokenDecimals(decimalsMap) // capture for local computation later in this call - localApprovedTokens = tokens + localDepositedTokens = tokens localTokenTotals = totals localTokenSymbols = symbols // Fetch sponsors via direct getter if available; fallback to logs @@ -365,12 +350,11 @@ export default function InteractionClient() { } } catch (e) { console.warn('Sponsorship functions unavailable on this contract, continuing without approved tokens.', e) - setApprovedTokens([]) - setTokenMinAmounts({}) + setDepositedTokens([]) setTokenSymbols({}) setTokenTotals({}) setSponsors([]) - localApprovedTokens = [] + localDepositedTokens = [] localTokenTotals = {} localTokenSymbols = {} localSponsors = [] @@ -448,7 +432,7 @@ export default function InteractionClient() { const total = Number(totalTokens) const sharePercent = total > 0 ? (Number(projectTokens) / total) * 100 : 0 // Compute per-token payout amounts (formatted as whole numbers) - const payouts = localApprovedTokens.map((t) => { + const payouts = localDepositedTokens.map((t: string) => { const poolTotal = localTokenTotals[t] ?? BigInt(0) const denom = totalTokens === BigInt(0) ? BigInt(1) : totalTokens const amount = (poolTotal * (projectTokens as bigint)) / denom @@ -503,8 +487,7 @@ export default function InteractionClient() { // Save extended hackathon details including all interaction data await hackathonDB.setExtendedHackathonDetails(contractAddress, chainId, { hackathonData: hackathon, - approvedTokens: localApprovedTokens, - tokenMinAmounts: tokenMinAmounts, + depositedTokens: localDepositedTokens, tokenSymbols: localTokenSymbols, tokenTotals: localTokenTotals, tokenDecimals: tokenDecimals, @@ -619,8 +602,7 @@ export default function InteractionClient() { console.log('📊 Loading hackathon data from cache with judges:', cached.hackathonData.judges?.length, cached.hackathonData.judges) // Restore all state from cache (types are already converted by IndexedDB) setHackathonData(cached.hackathonData) - setApprovedTokens(cached.approvedTokens) - setTokenMinAmounts(cached.tokenMinAmounts) + setDepositedTokens(cached.depositedTokens || []) setTokenSymbols(cached.tokenSymbols) setTokenTotals(cached.tokenTotals) setTokenDecimals(cached.tokenDecimals) @@ -928,54 +910,7 @@ export default function InteractionClient() { } } - const handleSubmitToken = async () => { - if (!contractAddress) return - if (!submitTokenAddress || !/^0x[a-fA-F0-9]{40}$/.test(submitTokenAddress)) { - return toast.error('Enter a valid ERC20 token address') - } - if (!submitTokenName.trim()) { - return toast.error('Provide a token name') - } - try { - // Preflight: avoid duplicate submission - try { - const publicClient = getPublicClient(config) - const [, , exists] = await publicClient.readContract({ - address: contractAddress, - abi: HACKHUB_ABI, - functionName: 'getTokenSubmission', - args: [submitTokenAddress as `0x${string}`] - }) as [string, string, boolean] - if (exists) { - toast.error('This token has already been submitted') - return - } - } catch { - // If getter not available, continue; contract will enforce - } - setIsSubmittingToken(true) - await writeContract({ - address: contractAddress, - abi: HACKHUB_ABI, - functionName: 'submitToken', - args: [submitTokenAddress as `0x${string}`, submitTokenName.trim()] - }) - toast.success('Token submitted for approval') - setSubmitTokenAddress('') - setSubmitTokenName('') - } catch (e: any) { - console.error(e) - const msg = String(e?.message || '') - if (msg.includes('TokenAlreadySubmitted')) { - toast.error('Token already submitted') - } else { - toast.error(e?.message || 'Submit failed') - } - } finally { - setIsSubmittingToken(false) - } - } return (
@@ -1163,14 +1098,14 @@ export default function InteractionClient() { {/* Approved Tokens */} - {approvedTokens.length > 0 && ( + {depositedTokens.length > 0 && ( Prize Pool
- {approvedTokens.map((t) => ( + {depositedTokens.map((t) => (
{t === '0x0000000000000000000000000000000000000000' ? 'Native ETH' : (tokenSymbols[t] || short(t))}
@@ -1178,17 +1113,6 @@ export default function InteractionClient() {
Total: {formatTokenAmount(tokenTotals[t] ?? BigInt(0), t)}
-
Min deposit: {(() => { - // Hardcode ETH minimum to 1 Wei - if (t === '0x0000000000000000000000000000000000000000') { - return '1 Wei' // 1 Wei = 0.000000000000000001 ETH, but showing practical minimum - } - const minAmount = tokenMinAmounts[t] - if (minAmount !== undefined && minAmount > BigInt(0)) { - return formatTokenAmount(minAmount, t) - } - return 'No minimum' - })()}
))} @@ -1310,22 +1234,7 @@ export default function InteractionClient() { )} - {/* Submit Token for Approval */} - - - Submit Token for Approval - - - - setSubmitTokenAddress(e.target.value)} placeholder="0x..." className="bg-white border-gray-300 text-black" /> - - setSubmitTokenName(e.target.value)} placeholder="e.g., USDC" className="bg-white border-gray-300 text-black" /> - -

Submit ERC20 tokens for organizer approval. ETH is always available as a sponsorship option.

-
-
+ {/* Deposit / Sponsor */} @@ -1333,14 +1242,23 @@ export default function InteractionClient() { Become a Sponsor - + +
+ + setDepositToken(e.target.value)} + placeholder="0x..." + className="bg-white border-gray-300 text-black" + /> +
setDepositAmount(e.target.value)} placeholder={isERC20Selected ? 'Amount (e.g., 100)' : 'Amount in ETH (e.g., 0.5)'} className="bg-white border-gray-300 text-black" /> {isERC20Selected && ( @@ -1360,17 +1278,9 @@ export default function InteractionClient() { - {depositToken && ( -

- Min amount to be listed: { - depositToken === '0x0000000000000000000000000000000000000000' - ? '0.0001 ETH' // Practical minimum for ETH - : tokenMinAmounts[depositToken] !== undefined && tokenMinAmounts[depositToken] > BigInt(0) - ? formatTokenAmount(tokenMinAmounts[depositToken], depositToken) - : 'No minimum required' - } -

- )} +

+ You can deposit any amount of ETH or any ERC20 token. Your contribution will be visible to all participants and will be distributed to winners based on their vote share. +

diff --git a/app/[hackathon]/judge/JudgeVotingClient.tsx b/app/[hackathon]/judge/JudgeVotingClient.tsx index 1e34371..8ce9da4 100644 --- a/app/[hackathon]/judge/JudgeVotingClient.tsx +++ b/app/[hackathon]/judge/JudgeVotingClient.tsx @@ -149,7 +149,7 @@ export default function JudgeVotingClient() { const tokens = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, - functionName: 'getApprovedTokensList' + functionName: 'getDepositedTokensList' }) as string[] setApprovedTokens(tokens) const totals: Record = {} diff --git a/app/manage/ManageClient.tsx b/app/manage/ManageClient.tsx index 3239e5a..906bcd4 100644 --- a/app/manage/ManageClient.tsx +++ b/app/manage/ManageClient.tsx @@ -30,6 +30,10 @@ const ERC20_ABI = [ "type": "function" } ] as const + +// Helper function to shorten addresses +const short = (addr: string) => `${addr.slice(0, 6)}...${addr.slice(-4)}` + import { Users, Gavel, @@ -37,7 +41,10 @@ import { Loader2, AlertCircle, ArrowLeft, - CheckCircle + CheckCircle, + Eye, + EyeOff, + RefreshCw } from "lucide-react" import { useChainId, useAccount, useWriteContract, useWaitForTransactionReceipt } from "wagmi" import { toast } from "sonner" @@ -60,15 +67,16 @@ interface HackathonInfo { endTime: number } -interface SubmittedTokenInfo { - token: string +interface SponsorInfo { + address: string name: string - submitter: string + image: string + isBlocked: boolean + totalContributions: { token: string; amount: bigint; symbol?: string }[] } -interface ApprovedTokenInfo { +interface DepositedTokenInfo { token: string - minAmount: string totalAmount: string symbol?: string decimals?: number @@ -93,10 +101,124 @@ export default function ManageHackathonPage() { const [needsWallet, setNeedsWallet] = useState(false) const [adjustingTokens, setAdjustingTokens] = useState<{[key: string]: boolean}>({}) const [tokenAdjustments, setTokenAdjustments] = useState<{[key: string]: string}>({}) - const [submittedTokens, setSubmittedTokens] = useState([]) - const [approvedTokens, setApprovedTokens] = useState([]) - const [minAmounts, setMinAmounts] = useState<{[token: string]: string}>({}) - const [approvingToken, setApprovingToken] = useState<{[token: string]: boolean}>({}) + const [sponsors, setSponsors] = useState([]) + const [depositedTokens, setDepositedTokens] = useState([]) + const [blockingSponsor, setBlockingSponsor] = useState<{[address: string]: boolean}>({}) + const [refreshingSponsors, setRefreshingSponsors] = useState(false) + + // Load sponsors and their contributions + const loadSponsorsData = async () => { + if (!hackAddr) return + try { + setRefreshingSponsors(true) + const publicClient = getPublicClient(config) + + // Get all sponsors + const sponsorAddresses = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'getAllSponsors' + }) as string[] + + // Get deposited tokens to check contributions + const depositedTokensList = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'getDepositedTokensList' + }) as string[] + + const sponsorsInfo: SponsorInfo[] = [] + + for (const sponsorAddr of sponsorAddresses) { + try { + // Get sponsor profile + const [name, image] = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'getSponsorProfile', + args: [sponsorAddr as `0x${string}`] + }) as [string, string] + + // Check if sponsor is blocked + const isBlocked = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'isSponsorBlocked', + args: [sponsorAddr as `0x${string}`] + }) as boolean + + // Get contributions for each token + const contributions: { token: string; amount: bigint; symbol?: string }[] = [] + for (const token of depositedTokensList) { + const amount = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'getSponsorTokenAmount', + args: [sponsorAddr as `0x${string}`, token as `0x${string}`] + }) as bigint + + if (amount > 0n) { + let symbol = 'Unknown' + try { + if (token === '0x0000000000000000000000000000000000000000') { + symbol = 'ETH' + } else { + symbol = await publicClient.readContract({ + address: token as `0x${string}`, + abi: ERC20_ABI, + functionName: 'symbol' + }) as string + } + } catch {} + contributions.push({ token, amount, symbol }) + } + } + + if (contributions.length > 0) { + sponsorsInfo.push({ + address: sponsorAddr, + name: name || 'Anonymous', + image: image || '', + isBlocked, + totalContributions: contributions + }) + } + } catch (error) { + console.error(`Error loading sponsor ${sponsorAddr}:`, error) + } + } + + setSponsors(sponsorsInfo) + } catch (error) { + console.error('Error loading sponsors:', error) + } finally { + setRefreshingSponsors(false) + } + } + + // Handle sponsor blocking/unblocking + const handleBlockSponsor = async (sponsorAddress: string, block: boolean) => { + if (!hackAddr || !userAddress) return + try { + setBlockingSponsor(prev => ({ ...prev, [sponsorAddress]: true })) + + await writeContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: block ? 'blockSponsor' : 'unblockSponsor', + args: [sponsorAddress as `0x${string}`] + }) + + toast.success(`Sponsor ${block ? 'blocked' : 'unblocked'} successfully`) + // Refresh sponsors data + setTimeout(() => loadSponsorsData(), 1500) + } catch (error: any) { + console.error('Error blocking/unblocking sponsor:', error) + toast.error(error?.message || `Failed to ${block ? 'block' : 'unblock'} sponsor`) + } finally { + setBlockingSponsor(prev => ({ ...prev, [sponsorAddress]: false })) + } + } // Handle judge token adjustment const handleAdjustJudgeTokens = async (judgeAddress: string, newAmount: number) => { @@ -125,51 +247,7 @@ export default function ManageHackathonPage() { } } - const handleApproveSubmittedToken = async (token: string) => { - if (!hackAddr) return - const min = minAmounts[token] - if (!min || isNaN(Number(min))) { - setError('Please enter a valid minimum amount for this token') - return - } - try { - setApprovingToken(prev => ({ ...prev, [token]: true })) - - // Convert human-readable amount to base units (wei for ETH, smallest units for ERC20) - let minAmountInBaseUnits: bigint - if (token === '0x0000000000000000000000000000000000000000') { - // ETH - convert to wei (18 decimals) - minAmountInBaseUnits = BigInt(min) * BigInt(10) ** BigInt(18) - } else { - // ERC20 - get decimals and convert to base units - try { - const publicClient = getPublicClient(config) - const decimals = await publicClient.readContract({ - address: token as `0x${string}`, - abi: ERC20_ABI, - functionName: 'decimals' - }) as number - minAmountInBaseUnits = BigInt(min) * BigInt(10) ** BigInt(decimals) - } catch { - // Default to 18 decimals if we can't get token decimals - minAmountInBaseUnits = BigInt(min) * BigInt(10) ** BigInt(18) - } - } - - await writeContract({ - address: hackAddr, - abi: HACKHUB_ABI, - functionName: 'approveToken', - args: [token as `0x${string}`, minAmountInBaseUnits] - }) - setMinAmounts(prev => ({ ...prev, [token]: '' })) - } catch (err: any) { - console.error('Error approving token:', err) - setError('Failed to approve token: ' + (err?.message || 'Unknown error')) - } finally { - setApprovingToken(prev => ({ ...prev, [token]: false })) - } - } + // Load hackathon data const loadHackathonData = async () => { @@ -262,43 +340,25 @@ export default function ManageHackathonPage() { setJudges(judgeList) - // Load submitted tokens - try { - const submitted = await publicClient.readContract({ - address: hackAddr, - abi: HACKHUB_ABI, - functionName: 'getSubmittedTokensList' - }) as string[] - const submittedInfos: SubmittedTokenInfo[] = [] - for (const t of submitted) { - const [tokenName, submitter, exists] = await publicClient.readContract({ - address: hackAddr, - abi: HACKHUB_ABI, - functionName: 'getTokenSubmission', - args: [t as `0x${string}`] - }) as [string, string, boolean] - if (exists) submittedInfos.push({ token: t, name: tokenName, submitter }) - } - setSubmittedTokens(submittedInfos) - } catch (e) { - console.error('Error loading submitted tokens', e) - } + // Load sponsors and their contributions + await loadSponsorsData() - // Load approved tokens + // Load deposited tokens try { - const approved = await publicClient.readContract({ + const deposited = await publicClient.readContract({ address: hackAddr, abi: HACKHUB_ABI, - functionName: 'getApprovedTokensList' + functionName: 'getDepositedTokensList' }) as string[] - const approvedInfos: ApprovedTokenInfo[] = [] - for (const t of approved) { - const [min, total] = await Promise.all([ - publicClient.readContract({ address: hackAddr, abi: HACKHUB_ABI, functionName: 'getTokenMinAmount', args: [t as `0x${string}`] }) as Promise, - publicClient.readContract({ address: hackAddr, abi: HACKHUB_ABI, functionName: 'getTokenTotal', args: [t as `0x${string}`] }) as Promise, - ]) + const depositedInfos: DepositedTokenInfo[] = [] + for (const t of deposited) { + const total = await publicClient.readContract({ + address: hackAddr, + abi: HACKHUB_ABI, + functionName: 'getTokenTotal', + args: [t as `0x${string}`] + }) as bigint - // Get token symbol and decimals let symbol = 'Unknown' let decimals = 18 try { @@ -306,28 +366,22 @@ export default function ManageHackathonPage() { symbol = 'ETH' decimals = 18 } else { - const [sym, dec] = await Promise.all([ - publicClient.readContract({ address: t as `0x${string}`, abi: ERC20_ABI, functionName: 'symbol' }) as Promise, - publicClient.readContract({ address: t as `0x${string}`, abi: ERC20_ABI, functionName: 'decimals' }) as Promise - ]) - symbol = sym - decimals = dec + symbol = await publicClient.readContract({ address: t as `0x${string}`, abi: ERC20_ABI, functionName: 'symbol' }) as string + decimals = await publicClient.readContract({ address: t as `0x${string}`, abi: ERC20_ABI, functionName: 'decimals' }) as number } } catch { symbol = short(t) } - - approvedInfos.push({ - token: t, - minAmount: String(min), - totalAmount: String(total), + depositedInfos.push({ + token: t, + totalAmount: formatEther(total), symbol, decimals }) } - setApprovedTokens(approvedInfos) + setDepositedTokens(depositedInfos) } catch (e) { - console.error('Error loading approved tokens', e) + console.error('Error loading deposited tokens', e) } } catch (err) { @@ -338,8 +392,7 @@ export default function ManageHackathonPage() { } } - // Token address pretty - const short = (addr: string) => `${addr.slice(0,6)}...${addr.slice(-4)}` + // Format token amounts for display - convert from base units to human-readable const formatTokenAmount = (amount: string, token: string, decimals?: number): string => { @@ -574,84 +627,123 @@ export default function ManageHackathonPage() { - {/* Submitted Tokens for Approval */} - {!hackathonInfo.concluded && ( - - - Submitted Tokens - - - {submittedTokens.length === 0 ? ( -

No token submissions yet.

- ) : ( - submittedTokens.map((t) => ( -
-
- {/* Left: token details */} -
-

{t.name || 'Token'}

-

{short(t.token)}

-

Submitted by {short(t.submitter)}

+ {/* Sponsor Management */} + + + + Sponsor Management + + + + + {sponsors.length === 0 ? ( +

No sponsors yet.

+ ) : ( + sponsors.map((sponsor) => ( +
+
+ {/* Left: sponsor details */} +
+
+ {sponsor.image && ( + {sponsor.name} + )} +
+

{sponsor.name}

+

{short(sponsor.address)}

+
+ {sponsor.isBlocked && ( + + BLOCKED + + )} +
+
+

Contributions:

+ {sponsor.totalContributions.map((contribution, idx) => ( +

+ {contribution.symbol || short(contribution.token)}: {formatEther(contribution.amount)} +

+ ))}
+
- {/* Right: input + approve button */} -
-
- setMinAmounts(prev => ({ ...prev, [t.token]: e.target.value }))} - className="w-60 bg-white border-gray-300 text-black" - /> - -
-

Enter human-readable amounts (e.g., 5 for 5 tokens). Decimals will be handled automatically.

-
+ ) : ( + <> + + Block + + )} + + )} + +

+ {sponsor.isBlocked ? 'Hidden from public view' : 'Visible to participants'} +

- )) - )} -
-
- )} +
+ )) + )} + + - {/* Approved Tokens Overview */} + {/* Prize Pool Overview */} - Approved Tokens + Prize Pool - {approvedTokens.length === 0 ? ( -

No approved tokens yet.

+ {depositedTokens.length === 0 ? ( +

No prize pool yet.

) : ( - approvedTokens.map((t) => ( + depositedTokens.map((t) => (

{t.token === '0x0000000000000000000000000000000000000000' ? 'Native ETH' : (t.symbol || short(t.token))}

-

- Min: { - t.token === '0x0000000000000000000000000000000000000000' - ? '1 Wei' // Hardcode ETH minimum to 1 Wei - : BigInt(t.minAmount) > BigInt(0) - ? formatTokenAmount(t.minAmount, t.token, t.decimals) - : 'No minimum' - } -

+

{t.token === '0x0000000000000000000000000000000000000000' ? 'ETH' : short(t.token)}

- Total: {formatTokenAmount(t.totalAmount, t.token, t.decimals)} + Total: {t.totalAmount} {t.symbol}
)) diff --git a/app/myHackathons/page.tsx b/app/myHackathons/page.tsx index 4460225..b88f75c 100644 --- a/app/myHackathons/page.tsx +++ b/app/myHackathons/page.tsx @@ -177,7 +177,7 @@ function MyHackathonsPageContent() { approvedTokens = await publicClient.readContract({ address: addr, abi: HACKHUB_ABI, - functionName: 'getApprovedTokensList' + functionName: 'getDepositedTokensList' }) as string[] for (const t of approvedTokens) { try { diff --git a/app/projects/ProjectsClient.tsx b/app/projects/ProjectsClient.tsx index deb7177..d33744d 100644 --- a/app/projects/ProjectsClient.tsx +++ b/app/projects/ProjectsClient.tsx @@ -193,7 +193,7 @@ export default function ProjectsClient() { let localTokenTotals: Record = {} let localTokenSymbols: Record = {} try { - const tokens = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getApprovedTokensList' }) as string[] + const tokens = await publicClient.readContract({ address: contractAddress, abi: HACKHUB_ABI, functionName: 'getDepositedTokensList' }) as string[] setApprovedTokens(tokens) const symbols: Record = {} const totals: Record = {} diff --git a/components/navigation.tsx b/components/navigation.tsx index 2bd6992..8f73d37 100644 --- a/components/navigation.tsx +++ b/components/navigation.tsx @@ -15,16 +15,16 @@ export default function Navigation() {
-
+
HackHub Logo
- + HackHub diff --git a/lib/indexedDB.ts b/lib/indexedDB.ts index 6153ae2..f3a8228 100644 --- a/lib/indexedDB.ts +++ b/lib/indexedDB.ts @@ -346,8 +346,9 @@ class HackathonDB { // Extended hackathon details methods (includes all interaction data) async getExtendedHackathonDetails(contractAddress: string, chainId: number): Promise<{ hackathonData: HackathonData - approvedTokens: string[] - tokenMinAmounts: Record + depositedTokens?: string[] + approvedTokens?: string[] + tokenMinAmounts?: Record tokenSymbols: Record tokenTotals: Record tokenDecimals: Record @@ -374,9 +375,9 @@ class HackathonDB { // Convert string bigints back to bigint const processed = { ...result, - tokenMinAmounts: Object.fromEntries( + tokenMinAmounts: result.tokenMinAmounts ? Object.fromEntries( Object.entries(result.tokenMinAmounts).map(([k, v]) => [k, BigInt(v)]) - ), + ) : undefined, tokenTotals: Object.fromEntries( Object.entries(result.tokenTotals).map(([k, v]) => [k, BigInt(v)]) ), @@ -406,8 +407,9 @@ class HackathonDB { chainId: number, data: { hackathonData: HackathonData - approvedTokens: string[] - tokenMinAmounts: Record + depositedTokens?: string[] + approvedTokens?: string[] + tokenMinAmounts?: Record tokenSymbols: Record tokenTotals: Record tokenDecimals: Record @@ -426,9 +428,9 @@ class HackathonDB { // Convert bigints to strings for serialization const entry: ExtendedHackathonDetails = { ...data, - tokenMinAmounts: Object.fromEntries( + tokenMinAmounts: data.tokenMinAmounts ? Object.fromEntries( Object.entries(data.tokenMinAmounts).map(([k, v]) => [k, v.toString()]) - ), + ) : undefined, tokenTotals: Object.fromEntries( Object.entries(data.tokenTotals).map(([k, v]) => [k, v.toString()]) ), diff --git a/utils/contractABI/HackHub.ts b/utils/contractABI/HackHub.ts index 9906198..297fffa 100644 --- a/utils/contractABI/HackHub.ts +++ b/utils/contractABI/HackHub.ts @@ -13,81 +13,75 @@ export const HACKHUB_ABI = [ "stateMutability": "payable", "type": "constructor" }, + { "inputs": [], "name": "InvalidParams", "type": "error" }, + { "inputs": [], "name": "NotJudge", "type": "error" }, + { "inputs": [], "name": "SubmissionClosed", "type": "error" }, + { "inputs": [], "name": "NoVotesCast", "type": "error" }, + { "inputs": [], "name": "BeforeEndTime", "type": "error" }, + { "inputs": [], "name": "AlreadyClaimed", "type": "error" }, + { "inputs": [], "name": "InsufficientTokens", "type": "error" }, + { "inputs": [], "name": "AlreadyConcluded", "type": "error" }, + { "inputs": [], "name": "AlreadySubmitted", "type": "error" }, + { "inputs": [], "name": "TokenTransferFailed", "type": "error" }, { - "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, - { "indexed": false, "internalType": "string", "name": "name", "type": "string" }, - { "indexed": true, "internalType": "address", "name": "submitter", "type": "address" } + { "indexed": false, "internalType": "address", "name": "account", "type": "address" } ], - "name": "TokenSubmitted", - "type": "event" + "name": "OwnableUnauthorizedAccount", + "type": "error" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "minAmount", "type": "uint256" } + { "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" }, + { "indexed": true, "internalType": "address", "name": "submitter", "type": "address" } ], - "name": "TokenApproved", + "name": "ProjectSubmitted", "type": "event" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "judge", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "projectId", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } ], - "name": "SponsorDeposited", + "name": "Voted", "type": "event" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "projectId", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } ], - "name": "SponsorListed", + "name": "PrizeClaimed", "type": "event" }, - { "inputs": [], "name": "InvalidParams", "type": "error" }, - { "inputs": [], "name": "NotJudge", "type": "error" }, - { "inputs": [], "name": "SubmissionClosed", "type": "error" }, - { "inputs": [], "name": "NoVotesCast", "type": "error" }, - { "inputs": [], "name": "BeforeEndTime", "type": "error" }, - { "inputs": [], "name": "AlreadyClaimed", "type": "error" }, - { "inputs": [], "name": "InsufficientTokens", "type": "error" }, - { "inputs": [], "name": "AlreadyConcluded", "type": "error" }, - { "inputs": [], "name": "AlreadySubmitted", "type": "error" }, - { "inputs": [], "name": "TokenTransferFailed", "type": "error" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" }, - { "indexed": true, "internalType": "address", "name": "submitter", "type": "address" } + { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } ], - "name": "ProjectSubmitted", + "name": "SponsorDeposited", "type": "event" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "judge", "type": "address" }, - { "indexed": true, "internalType": "uint256", "name": "projectId", "type": "uint256" }, - { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" } ], - "name": "Voted", + "name": "SponsorBlocked", "type": "event" }, { "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "uint256", "name": "projectId", "type": "uint256" }, - { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" } ], - "name": "PrizeClaimed", + "name": "SponsorUnblocked", "type": "event" }, { @@ -146,22 +140,18 @@ export const HACKHUB_ABI = [ { "inputs": [], "name": "concludeHackathon", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "projectId", "type": "uint256" }], "name": "claimPrize", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "judge", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }], "name": "adjustJudgeTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { "inputs": [{ "internalType": "uint256", "name": "additionalAmount", "type": "uint256" }], "name": "increasePrizePool", "outputs": [], "stateMutability": "payable", "type": "function" }, - { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }, { "internalType": "string", "name": "tokenName", "type": "string" }], "name": "submitToken", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "minAmount", "type": "uint256" }], "name": "approveToken", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "string", "name": "sponsorName", "type": "string" }, { "internalType": "string", "name": "sponsorImageURL", "type": "string" }], "name": "depositToToken", "outputs": [], "stateMutability": "payable", "type": "function" }, { "inputs": [], "name": "projectCount", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "judgeCount", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getAllJudges", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getParticipants", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }], "name": "getTokenTotal", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, - { "inputs": [{ "internalType": "address", "name": "sponsor", "type": "address" }, { "internalType": "address", "name": "token", "type": "address" }], "name": "getSponsorTokenAmount", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, - { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }], "name": "getTokenMinAmount", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, - { "inputs": [], "name": "getApprovedTokensList", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, + { "inputs": [], "name": "getDepositedTokensList", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "sponsor", "type": "address" }], "name": "getSponsorProfile", "outputs": [{ "internalType": "string", "name": "sponsorName", "type": "string" }, { "internalType": "string", "name": "sponsorImageURL", "type": "string" }], "stateMutability": "view", "type": "function" }, - { "inputs": [], "name": "getSubmittedTokensList", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, - { "inputs": [{ "internalType": "address", "name": "token", "type": "address" }], "name": "getTokenSubmission", "outputs": [{ "internalType": "string", "name": "tokenName", "type": "string" }, { "internalType": "address", "name": "submitter", "type": "address" }, { "internalType": "bool", "name": "exists", "type": "bool" }], "stateMutability": "view", "type": "function" }, + { "inputs": [{ "internalType": "address", "name": "sponsor", "type": "address" }, { "internalType": "address", "name": "token", "type": "address" }], "name": "getSponsorTokenAmount", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getAllSponsors", "outputs": [{ "internalType": "address[]", "name": "", "type": "address[]" }], "stateMutability": "view", "type": "function" }, - { "inputs": [], "name": "owner", "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": [{ "internalType": "address", "name": "sponsor", "type": "address" }], "name": "blockSponsor", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { "inputs": [{ "internalType": "address", "name": "sponsor", "type": "address" }], "name": "unblockSponsor", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { "inputs": [{ "internalType": "address", "name": "sponsor", "type": "address" }], "name": "isSponsorBlocked", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, + { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" } ] as const; \ No newline at end of file diff --git a/utils/contractABI/Interfaces.ts b/utils/contractABI/Interfaces.ts index 0f6b215..7b11fd6 100644 --- a/utils/contractABI/Interfaces.ts +++ b/utils/contractABI/Interfaces.ts @@ -120,6 +120,22 @@ export const OwnableABI = [ outputs: [{ name: "", type: "address", internalType: "address" }], stateMutability: "view" }, + { + type: "function", + name: "_checkOwner", + inputs: [], + outputs: [], + stateMutability: "view" + }, + { + type: "function", + name: "_transferOwnership", + inputs: [ + { name: "newOwner", type: "address", internalType: "address" } + ], + outputs: [], + stateMutability: "nonpayable" + }, { type: "event", name: "OwnershipTransferred", diff --git a/utils/contractABI/SponsorshipLib.ts b/utils/contractABI/SponsorshipLib.ts index b507830..adf228c 100644 --- a/utils/contractABI/SponsorshipLib.ts +++ b/utils/contractABI/SponsorshipLib.ts @@ -1,27 +1,7 @@ export const SPONSORSHIP_LIB_ABI = [ { "type": "error", "name": "TokenTransferFailed", "inputs": [] }, { "type": "error", "name": "InvalidParams", "inputs": [] }, - { "type": "error", "name": "TokenNotApproved", "inputs": [] }, - { "type": "error", "name": "TokenAlreadySubmitted", "inputs": [] }, - { - "type": "event", - "name": "TokenSubmitted", - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, - { "indexed": false, "internalType": "string", "name": "name", "type": "string" }, - { "indexed": true, "internalType": "address", "name": "submitter", "type": "address" } - ] - }, - { - "type": "event", - "name": "TokenApproved", - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "minAmount", "type": "uint256" } - ] - }, + { "type": "error", "name": "SponsorNotFound", "inputs": [] }, { "type": "event", "name": "SponsorDeposited", @@ -34,33 +14,19 @@ export const SPONSORSHIP_LIB_ABI = [ }, { "type": "event", - "name": "SponsorListed", + "name": "SponsorBlocked", "anonymous": false, "inputs": [ - { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" } ] }, { - "type": "function", - "stateMutability": "nonpayable", - "name": "submitToken", - "inputs": [ - { "internalType": "address", "name": "token", "type": "address" }, - { "internalType": "string", "name": "tokenName", "type": "string" } - ], - "outputs": [] - }, - { - "type": "function", - "stateMutability": "nonpayable", - "name": "approveToken", + "type": "event", + "name": "SponsorUnblocked", + "anonymous": false, "inputs": [ - { "internalType": "address", "name": "token", "type": "address" }, - { "internalType": "uint256", "name": "minAmount", "type": "uint256" } - ], - "outputs": [] + { "indexed": true, "internalType": "address", "name": "sponsor", "type": "address" } + ] }, { "type": "function", @@ -74,16 +40,6 @@ export const SPONSORSHIP_LIB_ABI = [ ], "outputs": [] }, - { - "type": "function", - "stateMutability": "payable", - "name": "addOrganizerFunds", - "inputs": [ - { "internalType": "address", "name": "token", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "outputs": [] - }, { "type": "function", "stateMutability": "nonpayable", @@ -121,18 +77,7 @@ export const SPONSORSHIP_LIB_ABI = [ { "type": "function", "stateMutability": "view", - "name": "getTokenMinAmount", - "inputs": [ - { "internalType": "address", "name": "token", "type": "address" } - ], - "outputs": [ - { "internalType": "uint256", "name": "", "type": "uint256" } - ] - }, - { - "type": "function", - "stateMutability": "view", - "name": "getApprovedTokensList", + "name": "getAllSponsors", "inputs": [], "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } @@ -141,7 +86,7 @@ export const SPONSORSHIP_LIB_ABI = [ { "type": "function", "stateMutability": "view", - "name": "getSubmittedTokensList", + "name": "getDepositedTokensList", "inputs": [], "outputs": [ { "internalType": "address[]", "name": "", "type": "address[]" } @@ -150,43 +95,39 @@ export const SPONSORSHIP_LIB_ABI = [ { "type": "function", "stateMutability": "view", - "name": "getAllSponsors", - "inputs": [], + "name": "getSponsorProfile", + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], "outputs": [ - { "internalType": "address[]", "name": "", "type": "address[]" } + { "internalType": "string", "name": "sponsorName", "type": "string" }, + { "internalType": "string", "name": "imageURL", "type": "string" } ] }, { "type": "function", - "stateMutability": "view", - "name": "getTokenSubmission", + "stateMutability": "nonpayable", + "name": "blockSponsor", "inputs": [ - { "internalType": "address", "name": "token", "type": "address" } + { "internalType": "address", "name": "sponsor", "type": "address" } ], - "outputs": [ - { "internalType": "string", "name": "name", "type": "string" }, - { "internalType": "address", "name": "submitter", "type": "address" }, - { "internalType": "bool", "name": "exists", "type": "bool" } - ] + "outputs": [] }, { "type": "function", - "stateMutability": "view", - "name": "getSponsorProfile", + "stateMutability": "nonpayable", + "name": "unblockSponsor", "inputs": [ { "internalType": "address", "name": "sponsor", "type": "address" } ], - "outputs": [ - { "internalType": "string", "name": "sponsorName", "type": "string" }, - { "internalType": "string", "name": "imageURL", "type": "string" } - ] + "outputs": [] }, { "type": "function", "stateMutability": "view", - "name": "isTokenApproved", + "name": "isSponsorBlocked", "inputs": [ - { "internalType": "address", "name": "token", "type": "address" } + { "internalType": "address", "name": "sponsor", "type": "address" } ], "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } diff --git a/utils/contractAddress.ts b/utils/contractAddress.ts index 6b07ba9..d8f187d 100644 --- a/utils/contractAddress.ts +++ b/utils/contractAddress.ts @@ -1,5 +1,5 @@ export const HackHubFactoryAddress: { [key: number]: `0x${string}` } = { - 534351: '0x8b5f09679b9a09992eebc0a5d13dc955d9864cf8', + 534351: '0x451b43037c2224493ace56865a87a9cb17540474', } export const getFactoryAddress = (chainId: number): `0x${string}` | undefined => {