Skip to content

Commit

Permalink
fix: wait for disputestatus event
Browse files Browse the repository at this point in the history
  • Loading branch information
0xyaco committed Oct 25, 2024
1 parent c8b7399 commit e711311
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 90 deletions.
27 changes: 24 additions & 3 deletions apps/agent/test/e2e/scenarios/01_happy_path/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
ProphetCodec,
ProtocolProvider,
} from "@ebo-agent/automated-dispute";
import { Request, RequestId } from "@ebo-agent/automated-dispute/dist/types/prophet.js";
import { RequestId } from "@ebo-agent/automated-dispute/dist/types/prophet.js";
import { BlockNumberService } from "@ebo-agent/blocknumber";
import { Caip2ChainId, Logger, UnixTimestamp } from "@ebo-agent/shared";
import { Caip2ChainId, Logger } from "@ebo-agent/shared";
import { CreateServerReturnType } from "prool";
import {
Account,
Expand Down Expand Up @@ -522,7 +522,28 @@ describe.sequential("single agent", () => {

await anvilClient.increaseTime({ seconds: 60 * 60 * 24 * 7 * 4 });

// FIXME: check for `DisputeStatusUpdated(DISP1.id, DISP1, "Won")`
const disputeSettledEvent = await waitForEvent({
client: anvilClient,
filter: {
address: protocolContracts["Oracle"],
fromBlock: initBlock,
event: getAbiItem({ abi: oracleAbi, name: "DisputeStatusUpdated" }),
strict: true,
},
matcher: (log) => {
const status = ProphetCodec.decodeDisputeStatus(log.args._status);

return (
log.args._disputeId === badResponseDisputedEvent.args._disputeId &&
status === "Won"
);
},
pollingIntervalMs: 100,
blockTimeout: initBlock + 1000n,
});

expect(disputeSettledEvent).toBeDefined();

const [requestFinalizedEvent, newEpochEvent] = await Promise.all([
waitForEvent({
client: anvilClient,
Expand Down
1 change: 1 addition & 0 deletions apps/scripts/test/approveAccountingModules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("approveModules script", () => {
"Approved module: Bonded Response Module at address 0xBondedResponseModule",
),
);

expect(console.log).toHaveBeenCalledWith(
expect.stringContaining(
"Approved module: Bond Escalation Module at address 0xBondEscalationModule",
Expand Down
2 changes: 0 additions & 2 deletions packages/automated-dispute/src/providers/protocolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { arbitrum, arbitrumSepolia, mainnet, sepolia } from "viem/chains";
import type {
Dispute,
DisputeId,
DisputeStatus,
EboEvent,
EboEventName,
Epoch,
Expand All @@ -48,7 +47,6 @@ import {
InvalidBlockRangeError,
RpcUrlsEmpty,
TransactionExecutionError,
UnknownDisputeStatus,
} from "../exceptions/index.js";
import { ProphetCodec } from "../external.js";
import {
Expand Down
3 changes: 1 addition & 2 deletions packages/automated-dispute/src/services/eboActor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BlockNumberService } from "@ebo-agent/blocknumber";
import { Caip2ChainId, HexUtils, ILogger, stringify, UnixTimestamp } from "@ebo-agent/shared";
import { Caip2ChainId, ILogger, stringify, UnixTimestamp } from "@ebo-agent/shared";
import { Mutex } from "async-mutex";
import { Heap } from "heap-js";
import { ContractFunctionRevertedError } from "viem";
Expand All @@ -14,7 +14,6 @@ import type {
Request,
Response,
ResponseBody,
ResponseId,
} from "../types/index.js";
import { ErrorHandler } from "../exceptions/errorHandler.js";
import {
Expand Down
9 changes: 8 additions & 1 deletion packages/automated-dispute/src/services/prophetCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ const DISPUTE_MODULE_DATA_REQUEST_ABI_FIELDS = [

const RESPONSE_RESPONSE_ABI_FIELDS = [{ name: "block", type: "uint256" }] as const;

const DISPUTE_STATUS_ENUM: DisputeStatus[] = ["None", "Active", "Won", "Lost", "NoResolution"];
const DISPUTE_STATUS_ENUM: DisputeStatus[] = [
"None",
"Active",
"Escalated",
"Won",
"Lost",
"NoResolution",
];

/** Class to encode/decode Prophet's structs into/from a byte array */
export class ProphetCodec {
Expand Down
55 changes: 18 additions & 37 deletions packages/automated-dispute/tests/services/eboActor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
PastEventEnqueueError,
RequestMismatch,
} from "../../src/exceptions/index.js";
import { EboEvent, Request, RequestId, ResponseId } from "../../src/types/index.js";
import { EboEvent, ErrorContext, Request, RequestId, ResponseId } from "../../src/types/index.js";
import mocks from "../mocks/index.js";
import { DEFAULT_MOCKED_REQUEST_CREATED_DATA } from "../services/eboActor/fixtures.js";

Expand Down Expand Up @@ -494,56 +494,37 @@ describe("EboActor", () => {
const response = mocks.buildResponse(request);
const dispute = mocks.buildDispute(request, response);

const abi: Abi = [
{
type: "error",
name: "BondEscalationModule_ShouldBeEscalated",
inputs: [],
},
];
const shouldBeEscalatedName = "BondEscalationModule_ShouldBeEscalated";

const errorName = "BondEscalationModule_ShouldBeEscalated";
const data = encodeErrorResult({
abi,
errorName,
args: [],
const customError = new CustomContractError(shouldBeEscalatedName, {
shouldNotify: false,
shouldReenqueue: false,
shouldTerminate: false,
});

const contractError = new ContractFunctionRevertedError({
abi,
data,
functionName: "settleDispute",
});
vi.spyOn(protocolProvider, "settleDispute").mockRejectedValue(customError);

vi.spyOn(protocolProvider, "settleDispute").mockRejectedValue(contractError);
const escalateDisputeMock = vi
.spyOn(protocolProvider, "escalateDispute")
.mockResolvedValue();

const customError = new CustomContractError(errorName, {
shouldNotify: false,
shouldReenqueue: false,
shouldTerminate: false,
});
vi.spyOn(customError, "on").mockImplementation((err, errorHandler) => {
expect(err).toMatch(shouldBeEscalatedName);
expect(errorHandler).toBeTypeOf("function");

errorHandler({} as ErrorContext);

expect(escalateDisputeMock).toHaveBeenCalledWith(
request.prophetData,
response.prophetData,
dispute.prophetData,
);

const onSpy = vi.spyOn(customError, "on").mockImplementation((eventName, handler) => {
if (eventName === errorName) {
handler();
}
return customError;
});

vi.spyOn(ErrorFactory, "createError").mockReturnValue(customError);

await actor["settleDispute"](request, response, dispute);

expect(onSpy).toHaveBeenCalledWith(errorName, expect.any(Function));

expect(escalateDisputeMock).toHaveBeenCalledWith(
request.prophetData,
response.prophetData,
dispute.prophetData,
);
expect(logger.info).toHaveBeenCalledWith(`Dispute ${dispute.id} escalated.`);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ describe("EboActor", () => {

await actor.onLastBlockUpdated(newBlockNumber as UnixTimestamp);

expect(logger.debug).toBeCalledWith(
expect(logger.info).toBeCalledWith(
expect.stringMatching(`Proposal window for request ${request.id} not closed yet.`),
);

Expand Down
32 changes: 31 additions & 1 deletion packages/automated-dispute/tests/services/prophetCodec.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { isHex } from "viem";
import { describe, expect, it } from "vitest";

import { UnknownDisputeStatus } from "../../src/exceptions";
import { ProphetCodec } from "../../src/services";
import { Response } from "../../src/types";
import { DisputeStatus, Response } from "../../src/types";

describe("ProphetCodec", () => {
describe("encodeResponse", () => {
Expand All @@ -24,6 +25,35 @@ describe("ProphetCodec", () => {
});
});

describe("decodeDisputeStatus", () => {
const testCases: Array<{ input: number; expected: DisputeStatus }> = [
{ input: 0, expected: "None" },
{ input: 1, expected: "Active" },
{ input: 2, expected: "Escalated" },
{ input: 3, expected: "Won" },
{ input: 4, expected: "Lost" },
{ input: 5, expected: "NoResolution" },
];

testCases.forEach(({ input, expected }) => {
it(`maps status ${input} to '${expected}'`, () => {
const result = ProphetCodec.decodeDisputeStatus(input);

expect(result).toBe(expected);
});
});

it("throws UnknownDisputeStatus for invalid status", () => {
const invalidStatuses = [-1, 6, 999];

invalidStatuses.forEach((status) => {
expect(() => {
ProphetCodec.decodeDisputeStatus(status);
}).toThrow(UnknownDisputeStatus);
});
});
});

describe.todo("decodeResponse");

describe.todo("decodeRequestRequestModuleData");
Expand Down
51 changes: 8 additions & 43 deletions packages/automated-dispute/tests/services/protocolProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Caip2ChainId } from "@ebo-agent/shared";
import { Caip2ChainId, HexUtils } from "@ebo-agent/shared";
import {
Address,
ContractFunctionRevertedError,
Expand All @@ -25,11 +25,10 @@ import {
InvalidAccountOnClient,
RpcUrlsEmpty,
TransactionExecutionError,
UnknownDisputeStatus,
} from "../../src/exceptions/index.js";
import { ProtocolContractsAddresses } from "../../src/interfaces/index.js";
import { ProtocolProvider } from "../../src/providers/index.js";
import { DisputeStatus, EboEvent } from "../../src/types/index.js";
import { EboEvent } from "../../src/types/index.js";
import {
DEFAULT_MOCKED_DISPUTE_DATA,
DEFAULT_MOCKED_REQUEST_CREATED_DATA,
Expand Down Expand Up @@ -890,6 +889,10 @@ describe("ProtocolProvider", () => {
});

describe("getEvents", () => {
afterEach(() => {
vi.restoreAllMocks();
});

it("successfully merges and sorts events from all sources", async () => {
const request = DEFAULT_MOCKED_REQUEST_CREATED_DATA;

Expand All @@ -899,6 +902,8 @@ describe("ProtocolProvider", () => {
mockedPrivateKey,
);

vi.spyOn(HexUtils, "normalize").mockReturnValue("0x01");

// FIXME: types are sketchy here
const mockRequestCreatorEvents: EboEvent<"RequestCreated">[] = [
{
Expand Down Expand Up @@ -1037,44 +1042,4 @@ describe("ProtocolProvider", () => {
});
});
});

describe("mapDisputeStatus", () => {
const testCases: Array<{ input: number; expected: DisputeStatus }> = [
{ input: 0, expected: "None" },
{ input: 1, expected: "Active" },
{ input: 2, expected: "Escalated" },
{ input: 3, expected: "Won" },
{ input: 4, expected: "Lost" },
{ input: 5, expected: "NoResolution" },
];

testCases.forEach(({ input, expected }) => {
it(`maps status ${input} to '${expected}'`, () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfig,
mockContractAddress,
mockedPrivateKey,
);

const result = (protocolProvider as any).mapDisputeStatus(input);
expect(result).toBe(expected);
});
});

it("throws UnknownDisputeStatus for invalid status", () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfig,
mockContractAddress,
mockedPrivateKey,
);

const invalidStatuses = [-1, 6, 999];

invalidStatuses.forEach((status) => {
expect(() => {
(protocolProvider as any).mapDisputeStatus(status);
}).toThrow(UnknownDisputeStatus);
});
});
});
});

0 comments on commit e711311

Please sign in to comment.