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: implement oracle rpc calls #39

Merged
merged 13 commits into from
Sep 16, 2024
10 changes: 6 additions & 4 deletions packages/automated-dispute/src/eboActor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,10 @@ export class EboActor {
throw new ResponseAlreadyProposed(responseBody);
}

const proposerAddress = this.protocolProvider.getAccountAddress();

const response: Response["prophetData"] = {
// TODO: check if this is the correct proposer
proposer: request.prophetData.requester,
proposer: proposerAddress,
requestId: request.id,
response: responseBody,
};
Expand Down Expand Up @@ -625,9 +626,10 @@ export class EboActor {

const request = this.getActorRequest();

const disputer = this.protocolProvider.getAccountAddress();

const dispute: Dispute["prophetData"] = {
// TODO: check if this is the correct disputer
disputer: this.actorRequest.id,
disputer: disputer,
proposer: eventResponse.proposer,
responseId: event.metadata.responseId,
requestId: request.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class InvalidAccountOnClient extends Error {
constructor(message?: string) {
super(
`The account on the client is invalid. ${message ? `Reason: ${message}` : "Unknown reason."}`,
);

this.name = "InvalidAccountOnClient";
}
}
1 change: 1 addition & 0 deletions packages/automated-dispute/src/exceptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./invalidEpoch.exception.js";
export * from "./invalidRequestBody.exception.js";
export * from "./invalidRequester.exception.js";
export * from "./transactionExecutionError.exception.js";
export * from "./InvalidAccountOnClient.exception.js";
76 changes: 38 additions & 38 deletions packages/automated-dispute/src/interfaces/protocolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ export interface IReadProvider {
/**
* Retrieves events from the protocol within a specified block range.
*
* @param _fromBlock The starting block number.
* @param _toBlock The ending block number.
* @param fromBlock The starting block number.
* @param toBlock The ending block number.
* @returns A promise that resolves with an array of protocol events.
*/
getEvents(_fromBlock: bigint, _toBlock: bigint): Promise<EboEvent<EboEventName>[]>;
getEvents(fromBlock: bigint, toBlock: bigint): Promise<EboEvent<EboEventName>[]>;

/**
* Checks whether the specified address has staked assets.
*
* @param _address The address to check.
* @param address The address to check.
* @returns A promise that resolves with a boolean indicating whether the address has staked assets.
*/
hasStakedAssets(_address: Address): Promise<boolean>;
hasStakedAssets(address: Address): Promise<boolean>;

/**
* Gets the list of available chains that the protocol supports.
Expand All @@ -72,88 +72,88 @@ export interface IWriteProvider {
/**
* Proposes a response to a request.
*
* @param _request The request data.
* @param _response The response data.
* @param request The request data.
* @param response The response data.
* @returns A promise that resolves when the response is proposed.
*/
proposeResponse(
_request: Request["prophetData"],
_response: Response["prophetData"],
request: Request["prophetData"],
response: Response["prophetData"],
): Promise<void>;

/**
* Disputes a proposed response.
*
* @param _request The request data.
* @param _response The response data.
* @param _dispute The dispute data.
* @param request The request data.
* @param response The response data.
* @param dispute The dispute data.
* @returns A promise that resolves when the response is disputed.
*/
disputeResponse(
_request: Request["prophetData"],
_response: Response["prophetData"],
_dispute: Dispute["prophetData"],
request: Request["prophetData"],
response: Response["prophetData"],
dispute: Dispute["prophetData"],
): Promise<void>;
/**
* Pledges support for a dispute.
*
* @param _request The request data for the dispute.
* @param _dispute The dispute data.
* @param request The request data for the dispute.
* @param dispute The dispute data.
* @returns A promise that resolves when the pledge is made.
*/
pledgeForDispute(
_request: Request["prophetData"],
_dispute: Dispute["prophetData"],
request: Request["prophetData"],
dispute: Dispute["prophetData"],
): Promise<void>;

/**
* Pledges against a dispute.
*
* @param _request The request data for the dispute.
* @param _dispute The dispute data.
* @param request The request data for the dispute.
* @param dispute The dispute data.
* @returns A promise that resolves when the pledge is made.
*/
pledgeAgainstDispute(
_request: Request["prophetData"],
_dispute: Dispute["prophetData"],
request: Request["prophetData"],
dispute: Dispute["prophetData"],
): Promise<void>;

/**
* Settles a dispute by finalizing the response.
*
* @param _request The request data.
* @param _response The response data.
* @param _dispute The dispute data.
* @param request The request data.
* @param response The response data.
* @param dispute The dispute data.
* @returns A promise that resolves when the dispute is settled.
*/
settleDispute(
_request: Request["prophetData"],
_response: Response["prophetData"],
_dispute: Dispute["prophetData"],
request: Request["prophetData"],
response: Response["prophetData"],
dispute: Dispute["prophetData"],
): Promise<void>;

/**
* Escalates a dispute to a higher authority or layer.
*
* @param _request The request data.
* @param _response The response data.
* @param _dispute The dispute data.
* @param request The request data.
* @param response The response data.
* @param dispute The dispute data.
* @returns A promise that resolves when the dispute is escalated.
*/
escalateDispute(
_request: Request["prophetData"],
_response: Response["prophetData"],
_dispute: Dispute["prophetData"],
request: Request["prophetData"],
response: Response["prophetData"],
dispute: Dispute["prophetData"],
): Promise<void>;

/**
* Finalizes a request after the response and dispute resolution are complete.
*
* @param _request The request data.
* @param _response The response data.
* @param request The request data.
* @param response The response data.
* @returns A promise that resolves when the request is finalized.
*/
finalize(_request: Request["prophetData"], _response: Response["prophetData"]): Promise<void>;
finalize(request: Request["prophetData"], response: Response["prophetData"]): Promise<void>;
}

/**
Expand Down
18 changes: 17 additions & 1 deletion packages/automated-dispute/src/protocolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import { arbitrum } from "viem/chains";
import type { EboEvent, EboEventName } from "./types/events.js";
import type { Dispute, Request, Response } from "./types/prophet.js";
import { eboRequestCreatorAbi, epochManagerAbi, oracleAbi } from "./abis/index.js";
import { RpcUrlsEmpty, TransactionExecutionError } from "./exceptions/index.js";
import {
InvalidAccountOnClient,
RpcUrlsEmpty,
TransactionExecutionError,
} from "./exceptions/index.js";
import {
IProtocolProvider,
IReadProvider,
Expand Down Expand Up @@ -132,6 +136,18 @@ export class ProtocolProvider implements IProtocolProvider {
getAvailableChains: this.getAvailableChains.bind(this),
};

/**
* Returns the address of the account used for transactions.
*
* @returns {Address} The account address.
*/
public getAccountAddress(): Address {
if (!this.writeClient.account) {
throw new InvalidAccountOnClient();
}
return this.writeClient.account.address;
}

/**
* Gets the current epoch, the block number and its timestamp of the current epoch
*
Expand Down
28 changes: 27 additions & 1 deletion packages/automated-dispute/tests/eboActor/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Address } from "viem";

import { Request, RequestId } from "../../src/types/prophet";
import { Dispute, Request, RequestId, Response } from "../../src/types/prophet";

export const mockedPrivateKey =
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
Expand All @@ -11,6 +11,20 @@ export const DEFAULT_MOCKED_PROTOCOL_CONTRACTS = {
eboRequestCreator: "0xabcdef" as Address,
};

export const DEFAULT_MOCKED_RESPONSE_DATA: Response = {
id: "0x1234567890123456789012345678901234567890",
createdAt: 1625097600n,
prophetData: {
proposer: "0x9876543210987654321098765432109876543210" as Address,
requestId: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef" as Address,
response: {
chainId: "eip155:1",
block: 123456n,
epoch: 1n,
},
},
};

export const DEFAULT_MOCKED_REQUEST_CREATED_DATA: Request = {
id: "0x01" as RequestId,
chainId: "eip155:1",
Expand Down Expand Up @@ -42,3 +56,15 @@ export const DEFAULT_MOCKED_REQUEST_CREATED_DATA: Request = {
},
},
};

export const DEFAULT_MOCKED_DISPUTE_DATA: Dispute = {
id: "0x3456789012345678901234567890123456789012",
createdAt: 1625097800n,
status: "Active",
prophetData: {
disputer: "0x5678901234567890123456789012345678901234",
proposer: DEFAULT_MOCKED_RESPONSE_DATA.prophetData.proposer,
requestId: DEFAULT_MOCKED_REQUEST_CREATED_DATA.id,
responseId: DEFAULT_MOCKED_RESPONSE_DATA.id,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe("onDisputeStatusChanged", () => {
});

it("proposes a new response when dispute status goes into NoResolution", async () => {
const proposerAddress = "0x1234567890abcdef1234567890abcdef12345678";
const dispute = mocks.buildDispute(actorRequest, response, { status: "Escalated" });
const event: EboEvent<"DisputeStatusChanged"> = {
name: "DisputeStatusChanged",
Expand Down Expand Up @@ -78,21 +79,23 @@ describe("onDisputeStatusChanged", () => {
response.prophetData.response.block + 1n,
);

vi.spyOn(protocolProvider, "getAccountAddress").mockReturnValue(proposerAddress);

const mockProposeResponse = vi.spyOn(protocolProvider, "proposeResponse");

actor.enqueue(event);

await actor.processEvents();

expect(mockProposeResponse).toHaveBeenCalledWith(
expect.objectContaining({}),
actorRequest.prophetData,
expect.objectContaining({
proposer: expect.any(String),
requestId: "0x01",
proposer: proposerAddress,
requestId: actorRequest.id,
response: {
block: 2n,
chainId: "eip155:1",
epoch: 1n,
chainId: actorRequest.chainId,
epoch: actorRequest.epoch,
},
}),
);
Expand Down
33 changes: 17 additions & 16 deletions packages/automated-dispute/tests/eboActor/onRequestCreated.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ describe("EboActor", () => {
);

const indexedEpochBlockNumber = 48n;
const proposerAddress = "0x1234567890123456789012345678901234567890";

vi.spyOn(blockNumberService, "getEpochBlockNumber").mockResolvedValue(
indexedEpochBlockNumber,
);

vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(protocolEpoch);
vi.spyOn(protocolProvider, "getAccountAddress").mockReturnValue(proposerAddress);

const proposeResponseMock = vi.spyOn(protocolProvider, "proposeResponse");

Expand All @@ -88,7 +90,7 @@ describe("EboActor", () => {
expect(proposeResponseMock).toHaveBeenCalledWith(
expect.objectContaining(request.prophetData),
expect.objectContaining({
proposer: expect.any(String),
proposer: proposerAddress,
requestId: requestCreatedEvent.metadata.requestId,
response: {
block: indexedEpochBlockNumber,
Expand All @@ -111,24 +113,23 @@ describe("EboActor", () => {

const proposeResponseMock = vi.spyOn(protocolProvider, "proposeResponse");

const previousResponses = new Map<string, Response>();
previousResponses.set("0x01", {
id: "0x01",
createdAt: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)),
prophetData: {
proposer: "0x02",
requestId: requestId,
response: {
block: indexedEpochBlockNumber,
chainId: requestCreatedEvent.metadata.chainId,
epoch: protocolEpoch.currentEpoch,
const previousResponses: Response[] = [
{
id: "0x01",
createdAt: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)),
prophetData: {
proposer: "0x02",
requestId: requestId,
response: {
block: indexedEpochBlockNumber,
chainId: requestCreatedEvent.metadata.chainId,
epoch: protocolEpoch.currentEpoch,
},
},
},
});
];

vi.spyOn(registry, "getResponses").mockReturnValue(
Object.values(previousResponses),
);
vi.spyOn(registry, "getResponses").mockReturnValue(previousResponses);

actor.enqueue(requestCreatedEvent);

Expand Down
Loading