Skip to content
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

Fix: Ensure that SDK getDispute() returns the RTA/Invalid answer #1831

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Changes from 2 commits
Commits
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 kleros-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kleros/kleros-sdk",
"version": "2.1.10",
"version": "2.1.11",
"description": "SDK for Kleros version 2",
"repository": "[email protected]:kleros/kleros-v2.git",
"homepage": "https://github.com/kleros/kleros-v2/tree/master/kleros-sdk#readme",
13 changes: 13 additions & 0 deletions kleros-sdk/src/utils/getDispute.ts
Original file line number Diff line number Diff line change
@@ -56,5 +56,18 @@ export const getDispute = async (disputeParameters: GetDisputeParameters): Promi

const populatedTemplate = populateTemplate(templateData, data);

// Ensure Refuse to Arbitrate option exists
if (!populatedTemplate.answers?.some((answer) => answer.id && Number(answer.id) === 0)) {
populatedTemplate.answers = [
{
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
},
...(populatedTemplate.answers || []),
];
}

return populatedTemplate;
};
222 changes: 222 additions & 0 deletions kleros-sdk/test/getDispute.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { getDispute } from "../src/utils/getDispute";
import fetchDisputeDetails from "../src/requests/fetchDisputeDetails";
import fetchDisputeTemplateFromId from "../src/requests/fetchDisputeTemplateFromId";

// Mock the dependencies
vi.mock("../src/requests/fetchDisputeDetails");
vi.mock("../src/requests/fetchDisputeTemplateFromId");

describe("getDispute", () => {
const mockDisputeId = 123n;
const mockCoreSubgraph = "https://api.thegraph.com/subgraphs/name/kleros/core";
const mockDtrSubgraph = "https://api.thegraph.com/subgraphs/name/kleros/dtr";

const mockDisputeDetails = {
dispute: {
templateId: 1,
arbitrated: { id: "0x1234" },
arbitrableChainId: 1,
externalDisputeId: 123,
},
};

beforeEach(() => {
vi.resetAllMocks();
});

it("should add Refuse to Arbitrate option when answers array is empty", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(1);
expect(result?.answers[0]).toEqual({
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
});
});

it("should add Refuse to Arbitrate option when it doesn't exist in answers", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
{
id: "0x2",
title: "No",
description: "No Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(3);
expect(result?.answers[0]).toEqual({
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
});
expect(result?.answers[1].id).toBe("0x1");
expect(result?.answers[2].id).toBe("0x2");
});

it("should not add Refuse to Arbitrate option when it already exists with id 0x0", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
},
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(2);
expect(result?.answers[0].id).toBe("0x0");
expect(result?.answers[1].id).toBe("0x1");
});

it("should not add Refuse to Arbitrate option when it already exists with id 0x00", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x00",
title: "Custom Refuse Title",
description: "Custom Refuse Description",
reserved: true,
},
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(2);
expect(result?.answers[0].id).toBe("0x00");
expect(result?.answers[0].title).toBe("Custom Refuse Title");
expect(result?.answers[1].id).toBe("0x1");
});

it("should throw NotFoundError when dispute details are not found", async () => {
vi.mocked(fetchDisputeDetails).mockResolvedValue({ dispute: null } as any);

await expect(
getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
})
).rejects.toThrow("Dispute details not found");
});

it("should throw NotFoundError when template is not found", async () => {
vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(undefined);

await expect(
getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
})
).rejects.toThrow("Template not found");
});
});