Skip to content

Release #2012

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

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft

Release #2012

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1ff55f8
docs: natspec for KlerosCore view functions
jaybuidl May 14, 2025
036e897
chore: style and button changes
kemuru May 19, 2025
f20c9d4
chore: remove unused code
kemuru May 19, 2025
54d83a7
fix: avoid unnecessary calls draw() when no juror is available, requi…
jaybuidl May 19, 2025
9e8aa9e
fix: reinitializer and version for KlerosCore
jaybuidl May 19, 2025
7a5466b
chore: retrigger deploy preview
kemuru May 20, 2025
1ca9066
Merge pull request #2001 from kleros/chore(web)/style-and-button-changes
alcercu May 20, 2025
29ef9a1
Fix: Update isCurrentRound for previous round on appeal
google-labs-jules[bot] May 22, 2025
3925b6f
Fix: Update isCurrentRound for previous round on appeal
google-labs-jules[bot] May 23, 2025
ad47783
chore: timeline clarify remaining time
kemuru May 26, 2025
349783f
Merge pull request #2009 from kleros/chore/timeline-clarify-remaining…
alcercu May 26, 2025
f370669
fix(subgraph): handle-batched-disputes-request-events
tractorss May 26, 2025
3f532d2
Merge pull request #2010 from kleros/fix/subgraph-batch-dispute-handling
jaybuidl May 27, 2025
20ee602
fix: bug in color loading text in file viewer
kemuru May 27, 2025
282b91d
Merge pull request #2011 from kleros/fix(web)/color-text-loading-bug-…
alcercu May 28, 2025
411b384
Merge branch 'dev' into fix/update-iscurrentround
jaybuidl May 28, 2025
367549c
chore: subgraph version bump
jaybuidl May 28, 2025
30382a0
Merge pull request #2007 from kleros/fix/update-iscurrentround
jaybuidl May 28, 2025
e5cf1df
Merge pull request #2002 from kleros/fix/keeper-bot-useless-draws
jaybuidl May 28, 2025
e7a0759
fix: allow return in case evidence was opened in new tab
kemuru May 28, 2025
dde0dc7
fix: few more links handling
kemuru May 28, 2025
4e95c72
Merge pull request #2013 from kleros/fix/file-viewer-return-button-link
alcercu May 28, 2025
2b51d5e
chore: find-initializer-versions utility
jaybuidl May 28, 2025
4adedb5
chore: find-initializer-versions utility
jaybuidl May 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/deploy/upgrade-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const deployUpgradeAll: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await upgrade(disputeKitClassic, "initialize6", []);
await upgrade(disputeTemplateRegistry, "initialize2", []);
await upgrade(evidence, "initialize2", []);
await upgrade(core, "initialize4", []);
await upgrade(core, "initialize5", []);
await upgrade(policyRegistry, "initialize2", []);
await upgrade(sortition, "initialize3", []);
};
Expand Down
27 changes: 27 additions & 0 deletions contracts/scripts/find-initializer-versions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#! /usr/bin/env bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

declare -A rpcUrls
rpcUrls["arbitrum"]=$(mesc url arbitrum_alchemy)
rpcUrls["arbitrumSepolia"]=$(mesc url arbitrumSepolia_alchemy)
rpcUrls["arbitrumSepoliaDevnet"]=$(mesc url arbitrumSepolia_alchemy)

# event Initialized(uint64 version);
eventTopic=0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2

for c in arbitrum arbitrumSepolia arbitrumSepoliaDevnet; do
echo "--------------------------------"
echo "$c"
echo "--------------------------------"
for f in "$SCRIPT_DIR"/../deployments/"$c"/*_Proxy.json; do
address=$(jq -r .address "$f")
block=$(jq -r .receipt.blockNumber "$f")
basename "$f"
results=$(cast logs --from-block "$block" --to-block latest $eventTopic --address "$address" --rpc-url "${rpcUrls[$c]}" --json | jq -r .[].data)
initializer=$(cast --to-dec "$(echo "$results" | tail -n1)")
version=$(cast call --rpc-url "${rpcUrls[$c]}" "$address" "version()(string)" --json 2>/dev/null | jq -r '.[0]')
echo "$initializer" @v"$version"
echo
done
done
15 changes: 14 additions & 1 deletion contracts/scripts/keeperBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Cores, getContracts as getContractsForCoreType } from "./utils/contract

let request: <T>(url: string, query: string) => Promise<T>; // Workaround graphql-request ESM import
const { ethers } = hre;
const MAX_DRAW_CALLS_WITHOUT_JURORS = 10;
const MAX_DRAW_ITERATIONS = 30;
const MAX_EXECUTE_ITERATIONS = 20;
const MAX_DELAYED_STAKES_ITERATIONS = 50;
Expand Down Expand Up @@ -248,7 +249,19 @@ const drawJurors = async (dispute: { id: string; currentRoundIndex: string }, it
const { core } = await getContracts();
let success = false;
try {
await core.draw.staticCall(dispute.id, iterations, HIGH_GAS_LIMIT);
const simulatedIterations = iterations * MAX_DRAW_CALLS_WITHOUT_JURORS; // Drawing will be skipped as long as no juror is available in the next MAX_DRAW_CALLS_WITHOUT_JURORS calls to draw() given this nb of iterations.
const { drawnJurors: drawnJurorsBefore } = await core.getRoundInfo(dispute.id, dispute.currentRoundIndex);
const nbDrawnJurors = (await core.draw.staticCall(dispute.id, simulatedIterations, HIGH_GAS_LIMIT)) as bigint;
const extraJurors = nbDrawnJurors - BigInt(drawnJurorsBefore.length);
logger.debug(
`Draw: ${extraJurors} jurors available in the next ${simulatedIterations} iterations for dispute ${dispute.id}`
);
if (extraJurors <= 0n) {
logger.warn(
`Draw: skipping, no jurors available in the next ${simulatedIterations} iterations for dispute ${dispute.id}`
);
return success;
}
} catch (e) {
logger.error(`Draw: will fail for ${dispute.id}, skipping`);
return success;
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/arbitration/KlerosCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {KlerosCoreBase, IDisputeKit, ISortitionModule, IERC20} from "./KlerosCor
/// Core arbitrator contract for Kleros v2.
/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
contract KlerosCore is KlerosCoreBase {
string public constant override version = "0.9.3";
string public constant override version = "0.9.4";

// ************************************* //
// * Constructor * //
Expand Down Expand Up @@ -56,7 +56,7 @@ contract KlerosCore is KlerosCoreBase {
);
}

function initialize4() external reinitializer(4) {
function initialize5() external reinitializer(5) {
// NOP
}

Expand Down
20 changes: 19 additions & 1 deletion contracts/src/arbitration/KlerosCoreBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,8 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
/// @dev Draws jurors for the dispute. Can be called in parts.
/// @param _disputeID The ID of the dispute.
/// @param _iterations The number of iterations to run.
function draw(uint256 _disputeID, uint256 _iterations) external {
/// @return nbDrawnJurors The total number of jurors drawn in the round.
function draw(uint256 _disputeID, uint256 _iterations) external returns (uint256 nbDrawnJurors) {
Dispute storage dispute = disputes[_disputeID];
uint256 currentRound = dispute.rounds.length - 1;
Round storage round = dispute.rounds[currentRound];
Expand All @@ -616,6 +617,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
}
}
round.drawIterations += i;
return round.drawnJurors.length;
}

/// @dev Appeals the ruling of a specified dispute.
Expand Down Expand Up @@ -981,18 +983,34 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
(ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
}

/// @dev Gets the round info for a specified dispute and round.
/// @dev This function must not be called from a non-view function because it returns a dynamic array which might be very large, theoretically exceeding the block gas limit.
/// @param _disputeID The ID of the dispute.
/// @param _round The round to get the info for.
/// @return round The round info.
function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {
return disputes[_disputeID].rounds[_round];
}
Comment on lines +986 to 993
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add bounds checking for array access.

The function directly accesses disputes[_disputeID].rounds[_round] without validating that the indices are within bounds. This could cause reverts with unhelpful error messages when called with invalid parameters.

Add input validation to provide better error handling:

 function getRoundInfo(uint256 _disputeID, uint256 _round) external view returns (Round memory) {
+    if (_disputeID >= disputes.length) revert InvalidDisputeID();
+    if (_round >= disputes[_disputeID].rounds.length) revert InvalidRoundNumber();
     return disputes[_disputeID].rounds[_round];
 }

You'll need to add the corresponding custom error declarations:

error InvalidDisputeID();
error InvalidRoundNumber();
🤖 Prompt for AI Agents
In contracts/src/arbitration/KlerosCoreBase.sol around lines 984 to 991, the
function getRoundInfo accesses disputes[_disputeID].rounds[_round] without
checking if _disputeID and _round are valid indices, which can cause unhelpful
reverts. Fix this by adding input validation: first check if _disputeID is less
than the length of the disputes array and revert with a custom error
InvalidDisputeID() if not; then check if _round is less than the length of
disputes[_disputeID].rounds and revert with InvalidRoundNumber() if invalid.
Declare these custom errors in the contract as specified.


/// @dev Gets the PNK at stake per juror for a specified dispute and round.
/// @param _disputeID The ID of the dispute.
/// @param _round The round to get the info for.
/// @return pnkAtStakePerJuror The PNK at stake per juror.
function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
}
Comment on lines 999 to 1001
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add bounds checking for array access.

Similar to getRoundInfo, this function lacks input validation for _disputeID and _round parameters.

Apply this fix:

 function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
+    if (_disputeID >= disputes.length) revert InvalidDisputeID();
+    if (_round >= disputes[_disputeID].rounds.length) revert InvalidRoundNumber();
     return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
}
function getPnkAtStakePerJuror(uint256 _disputeID, uint256 _round) external view returns (uint256) {
if (_disputeID >= disputes.length) revert InvalidDisputeID();
if (_round >= disputes[_disputeID].rounds.length) revert InvalidRoundNumber();
return disputes[_disputeID].rounds[_round].pnkAtStakePerJuror;
}
🤖 Prompt for AI Agents
In contracts/src/arbitration/KlerosCoreBase.sol around lines 997 to 999, the
function getPnkAtStakePerJuror accesses the disputes and rounds arrays without
validating that _disputeID and _round are within valid bounds. Add checks to
ensure _disputeID is less than the length of disputes and _round is less than
the length of rounds for the specified dispute before accessing the arrays to
prevent out-of-bounds errors.


/// @dev Gets the number of rounds for a specified dispute.
/// @param _disputeID The ID of the dispute.
/// @return The number of rounds.
function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
return disputes[_disputeID].rounds.length;
}
Comment on lines 1006 to 1008
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add bounds checking for dispute ID.

The function should validate the _disputeID parameter before accessing the disputes array.

Apply this fix:

 function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
+    if (_disputeID >= disputes.length) revert InvalidDisputeID();
     return disputes[_disputeID].rounds.length;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
return disputes[_disputeID].rounds.length;
}
function getNumberOfRounds(uint256 _disputeID) external view returns (uint256) {
if (_disputeID >= disputes.length) revert InvalidDisputeID();
return disputes[_disputeID].rounds.length;
}
🤖 Prompt for AI Agents
In contracts/src/arbitration/KlerosCoreBase.sol around lines 1004 to 1006, the
function getNumberOfRounds lacks validation for the _disputeID parameter before
accessing the disputes array. Add a check to ensure _disputeID is within valid
bounds (e.g., less than the length of the disputes array) and revert or handle
the error if it is out of range to prevent invalid access.


/// @dev Checks if a given dispute kit is supported by a given court.
/// @param _courtID The ID of the court to check the support for.
/// @param _disputeKitID The ID of the dispute kit to check the support for.
/// @return Whether the dispute kit is supported or not.
function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {
return courts[_courtID].supportedDisputeKits[_disputeKitID];
}
Comment on lines 1014 to 1016
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add bounds checking for court ID.

The function should validate the _courtID parameter before accessing the courts array.

Apply this fix:

 function isSupported(uint96 _courtID, uint256 _disputeKitID) external view returns (bool) {
+    if (_courtID >= courts.length) revert InvalidCourtID();
     return courts[_courtID].supportedDisputeKits[_disputeKitID];
 }

Add the corresponding custom error declaration:

error InvalidCourtID();
🤖 Prompt for AI Agents
In contracts/src/arbitration/KlerosCoreBase.sol around lines 1012 to 1014, the
function isSupported accesses the courts mapping with _courtID without
validating if the court ID is valid. To fix this, add a check at the start of
the function to verify that _courtID is within the valid range of courts. If it
is not, revert with the custom error InvalidCourtID(). Also, declare the custom
error InvalidCourtID() in the contract as specified.

Expand Down
4 changes: 2 additions & 2 deletions contracts/src/arbitration/KlerosCoreNeo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
/// Core arbitrator contract for Kleros v2.
/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
contract KlerosCoreNeo is KlerosCoreBase {
string public constant override version = "0.8.0";
string public constant override version = "0.9.4";

// ************************************* //
// * Storage * //
Expand Down Expand Up @@ -67,7 +67,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
jurorNft = _jurorNft;
}

function initialize4() external reinitializer(4) {
function initialize5() external reinitializer(5) {
// NOP
}

Expand Down
13 changes: 11 additions & 2 deletions subgraph/core/src/KlerosCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,19 @@ export function handleAppealDecision(event: AppealDecision): void {
const disputeID = event.params._disputeID;
const dispute = Dispute.load(disputeID.toString());
if (!dispute) return;

// Load the current (previous) round
const previousRoundID = dispute.currentRound;
const previousRound = Round.load(previousRoundID);
if (previousRound) {
previousRound.isCurrentRound = false;
previousRound.save();
}

const newRoundIndex = dispute.currentRoundIndex.plus(ONE);
const roundID = `${disputeID}-${newRoundIndex.toString()}`;
const newRoundID = `${disputeID}-${newRoundIndex.toString()}`;
dispute.currentRoundIndex = newRoundIndex;
dispute.currentRound = roundID;
dispute.currentRound = newRoundID;
dispute.save();
const roundInfo = contract.getRoundInfo(disputeID, newRoundIndex);

Expand Down
30 changes: 28 additions & 2 deletions subgraph/core/src/entities/Dispute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,36 @@ export const updateDisputeRequestData = (event: DisputeCreation): void => {
if (!receipt) return;

const logs = receipt.logs;
const coreDisputeId = event.params._disputeID;

// note that the topic at 0th index is always the event signature
const disputeRequestEventIndex = logs.findIndex((log) => log.topics[0] == DisputeRequestSignature);
const crossChainDisputeEventIndex = logs.findIndex((log) => log.topics[0] == CrossChainDisputeIncomingSignature);
// For DisputeRequestSignature
let disputeRequestEventIndex = -1;
for (let i = 0; i < logs.length; i++) {
let log = logs[i];
if (log.topics.length > 2 && log.topics[0] == DisputeRequestSignature) {
// 3rd indexed argument in event is _arbitratorDisputeId
let decodedId = ethereum.decode("uint256", log.topics[2]);
if (decodedId != null && coreDisputeId.equals(decodedId.toBigInt())) {
disputeRequestEventIndex = i;
break;
}
}
}

// For CrossChainDisputeIncomingSignature
let crossChainDisputeEventIndex = -1;
for (let i = 0; i < logs.length; i++) {
let log = logs[i];
if (log.topics.length > 3 && log.topics[0] == CrossChainDisputeIncomingSignature) {
// 4th indexed argument in event is _arbitratorDisputeId
let decodedId = ethereum.decode("uint256", log.topics[3]);
if (decodedId != null && coreDisputeId.equals(decodedId.toBigInt())) {
crossChainDisputeEventIndex = i;
break;
}
}
}

if (crossChainDisputeEventIndex !== -1) {
const crossChainDisputeEvent = logs[crossChainDisputeEventIndex];
Expand Down
2 changes: 1 addition & 1 deletion subgraph/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kleros/kleros-v2-subgraph",
"version": "0.15.2",
"version": "0.15.4",
"drtVersion": "0.12.0",
"license": "MIT",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

### Pre-Requisites

If you haven't already, you need to follow all the previous steps of the **Contributing** section of the repo's [Contribution Guidelines](../CONTRIBUTING.md).
If you haven't already, you need to follow all the previous steps of the **Contributing** section of the repo's [Contribution Guidelines](../CONTRIBUTING.md)

### Getting Started

Expand Down
45 changes: 0 additions & 45 deletions web/src/components/AllCasesButton.tsx

This file was deleted.

12 changes: 10 additions & 2 deletions web/src/components/DisputePreview/Policies.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import styled, { css } from "styled-components";

import { useParams } from "react-router-dom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Apply consistent null safety pattern.

Similar to EvidenceCard, consider adding type safety and null checking for the route parameter to maintain consistency across components.

-import { useParams } from "react-router-dom";
+import { useParams } from "react-router-dom";

...

-  const { id } = useParams();
+  const { id } = useParams<{ id: string }>();

Also applies to: 72-72

🤖 Prompt for AI Agents
In web/src/components/DisputePreview/Policies.tsx at line 4 and also line 72,
the useParams hook usage lacks consistent null safety and type checking for the
route parameter. Update the code to explicitly type the parameters expected from
useParams and add null or undefined checks before using these parameters to
ensure type safety and prevent runtime errors, following the pattern used in
EvidenceCard for consistency.


import PaperclipIcon from "svgs/icons/paperclip.svg";
import PolicyIcon from "svgs/icons/policy.svg";

Expand Down Expand Up @@ -67,17 +69,23 @@ interface IPolicies {
}

export const Policies: React.FC<IPolicies> = ({ disputePolicyURI, courtId, attachment }) => {
const { id } = useParams();

return (
<Container>
<StyledP>Policy documents:</StyledP>
{!isUndefined(attachment) && !isUndefined(attachment.uri) ? (
<StyledInternalLink to={`/attachment/?title=${"Case Policy"}&url=${getIpfsUrl(attachment.uri)}`}>
<StyledInternalLink
to={`/attachment/?disputeId=${id}&title=${"Case Policy"}&url=${getIpfsUrl(attachment.uri)}`}
>
<StyledPaperclipIcon />
{attachment.label ?? "Attachment"}
</StyledInternalLink>
) : null}
{isUndefined(disputePolicyURI) ? null : (
<StyledInternalLink to={`/attachment/?title=${"Dispute Policy"}&url=${getIpfsUrl(disputePolicyURI)}`}>
<StyledInternalLink
to={`/attachment/?disputeId=${id}&title=${"Dispute Policy"}&url=${getIpfsUrl(disputePolicyURI)}`}
>
<StyledPolicyIcon />
Dispute Policy
</StyledInternalLink>
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/EvidenceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled, { css } from "styled-components";

import Identicon from "react-identicons";
import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding null safety for the route parameter.

The useParams hook can return undefined for route parameters. Consider adding type safety and null checking to prevent potential runtime errors.

-import { useParams } from "react-router-dom";
+import { useParams } from "react-router-dom";

...

-  const { id } = useParams();
+  const { id } = useParams<{ id: string }>();
+  
+  if (!id) {
+    console.warn("Dispute ID not found in route parameters");
+  }

Also applies to: 228-228

🤖 Prompt for AI Agents
In web/src/components/EvidenceCard.tsx at line 6 and also at line 228, the
useParams hook is used without null safety, which can cause runtime errors if
the route parameter is undefined. Add type annotations to define the expected
parameters and include null or undefined checks before using the parameter
values. This ensures safe access and prevents potential crashes due to missing
route parameters.


import { Card } from "@kleros/ui-components-library";

Expand Down Expand Up @@ -224,6 +225,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
fileURI,
}) => {
const profileLink = `/profile/1/desc/all?address=${sender}`;
const { id } = useParams();

const transactionExplorerLink = useMemo(() => {
return getTxnExplorerLink(transactionHash ?? "");
Expand Down Expand Up @@ -258,7 +260,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
</BottomLeftContent>
{fileURI && fileURI !== "-" ? (
<FileLinkContainer>
<StyledInternalLink to={`/attachment/?title=${"Evidence File"}&url=${getIpfsUrl(fileURI)}`}>
<StyledInternalLink to={`/attachment/?disputeId=${id}&title=${"Evidence File"}&url=${getIpfsUrl(fileURI)}`}>
<AttachmentIcon />
<AttachedFileText />
</StyledInternalLink>
Expand Down
4 changes: 4 additions & 0 deletions web/src/components/FileViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const StyledDocViewer = styled(DocViewer)`
#pdf-controls {
z-index: 3;
}

[class*="--loading"] {
color: ${({ theme }) => theme.secondaryText};
}
`;

/**
Expand Down
Loading
Loading