-
Notifications
You must be signed in to change notification settings - Fork 48
Support for Gated Dispute Kits and other improvements #2050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
1ff6beb
f5c1d67
bc76907
8818c80
4d0c513
38030e1
008bd22
fe7419c
7912160
434e608
168740b
6eb5bc6
fa2520c
c6562bb
c6b51c1
ce63962
b5fff19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ const disputeDetailsQuery = graphql(` | |
nbVotes | ||
disputeKit { | ||
id | ||
address | ||
} | ||
} | ||
currentRoundIndex | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,163 @@ | ||||||||||||||||||||
import { useEffect, useState } from "react"; | ||||||||||||||||||||
|
||||||||||||||||||||
import { useChainId } from "wagmi"; | ||||||||||||||||||||
|
||||||||||||||||||||
import { DisputeKits } from "consts/index"; | ||||||||||||||||||||
|
||||||||||||||||||||
interface UseDisputeKitAddressesParams { | ||||||||||||||||||||
disputeKitAddress?: string; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
interface UseDisputeKitAddressesAllReturn { | ||||||||||||||||||||
availableDisputeKits: Record<string, DisputeKits>; | ||||||||||||||||||||
isLoading: boolean; | ||||||||||||||||||||
error: string | null; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
const DISPUTE_KIT_CONFIG = { | ||||||||||||||||||||
[DisputeKits.Classic]: "disputeKitClassicAddress", | ||||||||||||||||||||
[DisputeKits.Shutter]: "disputeKitShutterAddress", | ||||||||||||||||||||
[DisputeKits.Gated]: "disputeKitGatedAddress", | ||||||||||||||||||||
[DisputeKits.GatedShutter]: "disputeKitGatedShutterAddress", | ||||||||||||||||||||
} as const; | ||||||||||||||||||||
|
||||||||||||||||||||
/** | ||||||||||||||||||||
* Hook to get dispute kit name based on address | ||||||||||||||||||||
* @param disputeKitAddress - Optional specific dispute kit address to identify | ||||||||||||||||||||
* @returns The human-readable name of the dispute kit and loading state | ||||||||||||||||||||
*/ | ||||||||||||||||||||
export const useDisputeKitAddresses = ({ disputeKitAddress }: UseDisputeKitAddressesParams = {}) => { | ||||||||||||||||||||
const chainId = useChainId(); | ||||||||||||||||||||
const [disputeKitName, setDisputeKitName] = useState<DisputeKits | undefined>(undefined); | ||||||||||||||||||||
const [isLoading, setIsLoading] = useState(true); | ||||||||||||||||||||
const [error, setError] = useState<string | null>(null); | ||||||||||||||||||||
|
||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||
const loadDisputeKitName = async () => { | ||||||||||||||||||||
try { | ||||||||||||||||||||
setIsLoading(true); | ||||||||||||||||||||
setError(null); | ||||||||||||||||||||
|
||||||||||||||||||||
// If no dispute kit address is provided, we can't determine the type | ||||||||||||||||||||
if (!disputeKitAddress) { | ||||||||||||||||||||
setDisputeKitName(undefined); | ||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// If no chainId, we can't look up from generated contracts | ||||||||||||||||||||
if (!chainId) { | ||||||||||||||||||||
setDisputeKitName(undefined); | ||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Dynamic import to handle cases where generated contracts might not be available | ||||||||||||||||||||
try { | ||||||||||||||||||||
const generatedContracts = await import("hooks/contracts/generated"); | ||||||||||||||||||||
|
||||||||||||||||||||
// Check each dispute kit to see if the address matches | ||||||||||||||||||||
for (const [humanName, contractKey] of Object.entries(DISPUTE_KIT_CONFIG)) { | ||||||||||||||||||||
const addressMapping = generatedContracts[contractKey as keyof typeof generatedContracts]; | ||||||||||||||||||||
|
||||||||||||||||||||
if (addressMapping && typeof addressMapping === "object" && chainId in addressMapping) { | ||||||||||||||||||||
const contractAddress = addressMapping[chainId as keyof typeof addressMapping] as string; | ||||||||||||||||||||
if ( | ||||||||||||||||||||
contractAddress && | ||||||||||||||||||||
typeof contractAddress === "string" && | ||||||||||||||||||||
contractAddress.toLowerCase() === disputeKitAddress.toLowerCase() | ||||||||||||||||||||
) { | ||||||||||||||||||||
setDisputeKitName(humanName as DisputeKits); | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// If no address matches, return undefined | ||||||||||||||||||||
setDisputeKitName(undefined); | ||||||||||||||||||||
} catch { | ||||||||||||||||||||
// If we can't import generated contracts, return undefined | ||||||||||||||||||||
setDisputeKitName(undefined); | ||||||||||||||||||||
} | ||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||
console.error("Failed to determine dispute kit name:", err); | ||||||||||||||||||||
setError("Failed to determine dispute kit type"); | ||||||||||||||||||||
setDisputeKitName(undefined); | ||||||||||||||||||||
} finally { | ||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||
} | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
loadDisputeKitName(); | ||||||||||||||||||||
}, [chainId, disputeKitAddress]); | ||||||||||||||||||||
|
||||||||||||||||||||
return { | ||||||||||||||||||||
disputeKitName, | ||||||||||||||||||||
isLoading, | ||||||||||||||||||||
error, | ||||||||||||||||||||
}; | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
/** | ||||||||||||||||||||
* Hook to get all dispute kit addresses for the current chain | ||||||||||||||||||||
* @returns All dispute kit addresses, loading state, and error state | ||||||||||||||||||||
*/ | ||||||||||||||||||||
export const useDisputeKitAddressesAll = (): UseDisputeKitAddressesAllReturn => { | ||||||||||||||||||||
const chainId = useChainId(); | ||||||||||||||||||||
const [availableDisputeKits, setAvailableDisputeKits] = useState<Record<string, DisputeKits>>({}); | ||||||||||||||||||||
const [isLoading, setIsLoading] = useState(true); | ||||||||||||||||||||
const [error, setError] = useState<string | null>(null); | ||||||||||||||||||||
|
||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||
const loadAllDisputeKitAddresses = async () => { | ||||||||||||||||||||
try { | ||||||||||||||||||||
setIsLoading(true); | ||||||||||||||||||||
setError(null); | ||||||||||||||||||||
|
||||||||||||||||||||
// If no chainId, we can't look up from generated contracts | ||||||||||||||||||||
if (!chainId) { | ||||||||||||||||||||
setAvailableDisputeKits({}); | ||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Dynamic import to handle cases where generated contracts might not be available | ||||||||||||||||||||
try { | ||||||||||||||||||||
const generatedContracts = await import("hooks/contracts/generated"); | ||||||||||||||||||||
const newAvailableDisputeKits: Record<string, DisputeKits> = {}; | ||||||||||||||||||||
|
||||||||||||||||||||
// Iterate through all dispute kits and get their addresses | ||||||||||||||||||||
for (const [humanName, contractKey] of Object.entries(DISPUTE_KIT_CONFIG)) { | ||||||||||||||||||||
const addressMapping = generatedContracts[contractKey as keyof typeof generatedContracts]; | ||||||||||||||||||||
|
||||||||||||||||||||
if (addressMapping && typeof addressMapping === "object" && chainId in addressMapping) { | ||||||||||||||||||||
const contractAddress = addressMapping[chainId as keyof typeof addressMapping] as string; | ||||||||||||||||||||
if (contractAddress && typeof contractAddress === "string") { | ||||||||||||||||||||
newAvailableDisputeKits[contractAddress.toLowerCase()] = humanName as DisputeKits; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
setAvailableDisputeKits(newAvailableDisputeKits); | ||||||||||||||||||||
} catch { | ||||||||||||||||||||
// If we can't import generated contracts, return empty object | ||||||||||||||||||||
setAvailableDisputeKits({}); | ||||||||||||||||||||
} | ||||||||||||||||||||
Comment on lines
+142
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Empty catch block suppresses errors silently The empty catch block could hide important errors during development. Log the error for debugging purposes: - } catch {
+ } catch (importError) {
+ console.warn('Failed to import generated contracts:', importError);
// If we can't import generated contracts, return empty object
setAvailableDisputeKits({});
} 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||
console.error("Failed to load dispute kit addresses:", err); | ||||||||||||||||||||
setError("Failed to load dispute kit addresses"); | ||||||||||||||||||||
setAvailableDisputeKits({}); | ||||||||||||||||||||
} finally { | ||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||
} | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
loadAllDisputeKitAddresses(); | ||||||||||||||||||||
}, [chainId]); | ||||||||||||||||||||
|
||||||||||||||||||||
return { | ||||||||||||||||||||
availableDisputeKits, | ||||||||||||||||||||
isLoading, | ||||||||||||||||||||
error, | ||||||||||||||||||||
}; | ||||||||||||||||||||
}; | ||||||||||||||||||||
Comment on lines
+1
to
+163
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding unit tests for the new hooks These hooks contain critical logic for dispute kit identification and would benefit from comprehensive unit tests to ensure reliability. Would you like me to generate unit tests for these hooks or open an issue to track this task? 🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -7,7 +7,9 @@ import { useAccount } from "wagmi"; | |||
|
||||
import VoteIcon from "svgs/icons/voted.svg"; | ||||
|
||||
import { DisputeKits } from "consts/index"; | ||||
import { Periods } from "consts/periods"; | ||||
import { useDisputeKitAddresses } from "hooks/useDisputeKitAddresses"; | ||||
import { useLockOverlayScroll } from "hooks/useLockOverlayScroll"; | ||||
import { useVotingContext } from "hooks/useVotingContext"; | ||||
import { formatDate } from "utils/date"; | ||||
|
@@ -17,8 +19,8 @@ import { isLastRound } from "utils/isLastRound"; | |||
import { useAppealCost } from "queries/useAppealCost"; | ||||
import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; | ||||
|
||||
import { responsiveSize } from "styles/responsiveSize"; | ||||
import { landscapeStyle } from "styles/landscapeStyle"; | ||||
import { responsiveSize } from "styles/responsiveSize"; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused import detected The Remove the unused import: -import { responsiveSize } from "styles/responsiveSize"; 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||
|
||||
import { getPeriodEndTimestamp } from "components/DisputeView"; | ||||
import InfoCard from "components/InfoCard"; | ||||
|
@@ -28,8 +30,6 @@ import Classic from "./Classic"; | |||
import Shutter from "./Shutter"; | ||||
import VotingHistory from "./VotingHistory"; | ||||
|
||||
import { getDisputeKitName } from "consts/index"; | ||||
|
||||
const Container = styled.div` | ||||
padding: 20px 16px 16px; | ||||
|
||||
|
@@ -70,10 +70,10 @@ const Voting: React.FC<IVoting> = ({ arbitrable, currentPeriodIndex, dispute }) | |||
const timesPerPeriod = disputeData?.dispute?.court?.timesPerPeriod; | ||||
const finalDate = useFinalDate(lastPeriodChange, currentPeriodIndex, timesPerPeriod); | ||||
|
||||
const disputeKitId = disputeData?.dispute?.currentRound?.disputeKit?.id; | ||||
const disputeKitName = disputeKitId ? getDisputeKitName(Number(disputeKitId)) : undefined; | ||||
const isClassicDisputeKit = disputeKitName?.toLowerCase().includes("classic") ?? false; | ||||
const isShutterDisputeKit = disputeKitName?.toLowerCase().includes("shutter") ?? false; | ||||
const disputeKitAddress = disputeData?.dispute?.currentRound?.disputeKit?.address; | ||||
const { disputeKitName } = useDisputeKitAddresses({ disputeKitAddress }); | ||||
const isClassicDisputeKit = disputeKitName === DisputeKits.Classic; | ||||
const isShutterDisputeKit = disputeKitName === DisputeKits.Shutter; | ||||
|
||||
const isCommitOrVotePeriod = useMemo( | ||||
() => [Periods.vote, Periods.commit].includes(currentPeriodIndex), | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Empty catch block suppresses errors silently
The empty catch block could hide important errors during development.
Log the error for debugging purposes:
📝 Committable suggestion
🤖 Prompt for AI Agents