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

feat: add response and dispute fetchers #97

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions packages/automated-dispute/src/interfaces/protocolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import type {
AccessControl,
BondEscalation,
Dispute,
DisputeId,
EboEvent,
EboEventName,
Epoch,
Request,
RequestId,
Response,
ResponseId,
} from "../types/index.js";
import { ProtocolContractsNames } from "../constants.js";

Expand Down Expand Up @@ -80,6 +82,20 @@ export interface IReadProvider {
* @returns A Promise that resolves to the BondEscalation data.
*/
getEscalation(requestId: RequestId): Promise<BondEscalation>;

/**
* Fetches the response data for a given response ID.
*
* @param responseId response ID
*/
getResponse(responseId: ResponseId): Promise<Response["prophetData"] | undefined>;

/**
* Fetches the dispute data for a given dispute ID.
*
* @param disputeId dispute ID
*/
getDispute(disputeId: DisputeId): Promise<Dispute["prophetData"] | undefined>;
}

/**
Expand Down
51 changes: 51 additions & 0 deletions packages/automated-dispute/src/providers/protocolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ export class ProtocolProvider implements IProtocolProvider {
getAccountingModuleAddress: this.getAccountingModuleAddress.bind(this),
getApprovedModules: this.getApprovedModules.bind(this),
getEscalation: this.getEscalation.bind(this),
getResponse: this.getResponse.bind(this),
getDispute: this.getDispute.bind(this),
};

/**
Expand Down Expand Up @@ -1197,6 +1199,55 @@ export class ProtocolProvider implements IProtocolProvider {
}
}

async getResponse(responseId: ResponseId): Promise<Response["prophetData"] | undefined> {
const responses = await this.oracleContract.getEvents.ResponseProposed({
_responseId: responseId,
});

if (!responses || responses.length === 0) return undefined;
if (responses.length > 1) {
this.logger.warn("Multiple responses found for the same response ID", { responseId });

return undefined;
}

const response = responses[0]?.args?._response;

if (!response) return undefined;

return {
proposer: response.proposer as Address,
response: response.response as Hex,
requestId: response.requestId as RequestId,
};
}

async getDispute(disputeId: DisputeId): Promise<Dispute["prophetData"] | undefined> {
const disputes = await this.oracleContract.getEvents.ResponseDisputed({
_disputeId: disputeId,
});

if (!disputes || disputes.length === 0) return undefined;
if (disputes.length > 1) {
this.logger.warn("Multiple disputes found for the same dispute ID", {
disputeId: disputeId,
});

return undefined;
}

const dispute = disputes[0]?.args?._dispute;

if (!dispute) return undefined;

return {
disputer: dispute.disputer as Address,
proposer: dispute.proposer as Address,
requestId: dispute.requestId as RequestId,
responseId: dispute.responseId as ResponseId,
};
}

/**
* Fetches the escalation data for a given request ID.
*
Expand Down
205 changes: 204 additions & 1 deletion packages/automated-dispute/tests/services/protocolProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from "../../src/exceptions/index.js";
import { ProtocolProvider } from "../../src/index.js";
import { ProtocolContractsAddresses } from "../../src/interfaces/index.js";
import { EboEvent } from "../../src/types/index.js";
import { DisputeId, EboEvent, RequestId, ResponseId } from "../../src/types/index.js";
import { mockLogger } from "../mocks/logger.mocks.js";
import {
DEFAULT_MOCKED_DISPUTE_DATA,
Expand Down Expand Up @@ -1306,6 +1306,209 @@ describe("ProtocolProvider", () => {
});
});

describe("getResponse", () => {
it("returns the response", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);

const responseId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as ResponseId;

const mockResponse = {
proposer: "0x123",
requestId: "0x456",
response: "0x789",
};

protocolProvider["oracleContract"].getEvents = {
ResponseProposed: vi
.fn()
.mockResolvedValue([{ args: { _response: mockResponse } }]),
AccessModuleSet: vi.fn(),
DisputeEscalated: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
ResponseDisputed: vi.fn(),
};

await expect(protocolProvider.getResponse(responseId)).resolves.toEqual(mockResponse);
});

it("returns undefined when multiple responses found", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);

const mockResponse = {
proposer: "0x123",
requestId: "0x456",
response: "0x789",
};

const responseId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as ResponseId;

protocolProvider["oracleContract"].getEvents = {
ResponseProposed: vi
.fn()
.mockResolvedValue([
{ args: { _response: mockResponse } },
{ args: { _response: mockResponse } },
]),
AccessModuleSet: vi.fn(),
DisputeEscalated: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
ResponseDisputed: vi.fn(),
};

await expect(protocolProvider.getResponse(responseId)).resolves.toBeUndefined();
});

it("returns undefined when no response found", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);

const responseId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as ResponseId;

protocolProvider["oracleContract"].getEvents = {
ResponseProposed: vi.fn().mockResolvedValue([]),
AccessModuleSet: vi.fn(),
DisputeEscalated: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
ResponseDisputed: vi.fn(),
};

await expect(protocolProvider.getResponse(responseId)).resolves.toBeUndefined();
});
});

describe("getDispute", () => {
it("returns the dispute", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);

const disputeId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as DisputeId;

const mockDispute = {
_requestId: "0x123",
_disputeId: disputeId,
_dispute: {
disputer: "0x01" as Address,
proposer: "0x01" as Address,
requestId: "0x123" as RequestId,
responseId: "0x456" as ResponseId,
},
};

protocolProvider["oracleContract"].getEvents = {
ResponseDisputed: vi.fn().mockResolvedValue([{ args: mockDispute }]),
DisputeEscalated: vi.fn(),
AccessModuleSet: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
ResponseProposed: vi.fn(),
};

await expect(protocolProvider.getDispute(disputeId)).resolves.toEqual(
mockDispute._dispute,
);
});

it("returns undefined when multiple disputes found", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);
const disputeId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as DisputeId;

const mockDispute = {
args: {
_requestId: "0x123",
_disputeId: disputeId,
_dispute: {
disputer: "0x01" as Address,
proposer: "0x01" as Address,
requestId: "0x123" as RequestId,
responseId: "0x456" as ResponseId,
},
},
};

protocolProvider["oracleContract"].getEvents = {
ResponseDisputed: vi.fn().mockResolvedValue([mockDispute, mockDispute]),
AccessModuleSet: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
DisputeEscalated: vi.fn(),
ResponseProposed: vi.fn(),
};

await expect(protocolProvider.getDispute(disputeId)).resolves.toBeUndefined();
});

it("returns undefined when no dispute found", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfigBase,
mockContractAddress,
mockedPrivateKey,
mockServiceProviderAddress,
mockLogger(),
mockBlockNumberService,
);
const disputeId = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as DisputeId;

protocolProvider["oracleContract"].getEvents = {
ResponseDisputed: vi.fn().mockResolvedValue([]),
AccessModuleSet: vi.fn(),
DisputeResolved: vi.fn(),
DisputeStatusUpdated: vi.fn(),
RequestCreated: vi.fn(),
OracleRequestFinalized: vi.fn(),
DisputeEscalated: vi.fn(),
ResponseProposed: vi.fn(),
};

await expect(protocolProvider.getDispute(disputeId)).resolves.toBeUndefined();
});
});

describe("Service Provider Address", () => {
it("uses the provided serviceProviderAddress from config", () => {
const protocolProvider = new ProtocolProvider(
Expand Down