diff --git a/apps/agent/src/config/schemas.ts b/apps/agent/src/config/schemas.ts
index bb6035ad..3d6328f8 100644
--- a/apps/agent/src/config/schemas.ts
+++ b/apps/agent/src/config/schemas.ts
@@ -75,7 +75,6 @@ const blockNumberServiceSchema = z.object({
const processorSchema = z.object({
msBetweenChecks: z.number().int().positive(),
accountingModules: z.object({
- requestModule: addressSchema,
responseModule: addressSchema,
escalationModule: addressSchema,
}),
diff --git a/packages/automated-dispute/src/interfaces/protocolProvider.ts b/packages/automated-dispute/src/interfaces/protocolProvider.ts
index 7a9e93b4..76de58b5 100644
--- a/packages/automated-dispute/src/interfaces/protocolProvider.ts
+++ b/packages/automated-dispute/src/interfaces/protocolProvider.ts
@@ -48,20 +48,13 @@ export interface IReadProvider {
*/
getAccountingModuleAddress(): Address;
- /**
- * Gets the list of approved modules' addresses based on the wallet's account address.
- *
- * @returns A promise that resolves with an array of approved modules.
- */
- getAccountingApprovedModules(): Promise
;
-
/**
* Gets the list of approved modules' addresses for a given wallet address.
*
* @param user The address of the user.
* @returns A promise that resolves with an array of approved modules for the user.
*/
- getApprovedModules(user: Address): Promise;
+ getApprovedModules(user: Address): Promise;
}
/**
@@ -164,13 +157,6 @@ export interface IWriteProvider {
*/
finalize(request: Request["prophetData"], response: Response["prophetData"]): Promise;
- /**
- * Approves modules needed by the accounting contract.
- *
- * @param modules an array of addresses for the modules to be approved
- */
- approveAccountingModules(modules: Address[]): Promise;
-
/**
* Approves a module in the accounting extension contract.
*
diff --git a/packages/automated-dispute/src/providers/protocolProvider.ts b/packages/automated-dispute/src/providers/protocolProvider.ts
index e5179e9e..aeccf52d 100644
--- a/packages/automated-dispute/src/providers/protocolProvider.ts
+++ b/packages/automated-dispute/src/providers/protocolProvider.ts
@@ -1,6 +1,7 @@
import { BlockNumberService, UnsupportedChain } from "@ebo-agent/blocknumber";
import { Caip2ChainId, HexUtils, UnixTimestamp } from "@ebo-agent/shared";
import {
+ Account,
Address,
BaseError,
Block,
@@ -43,7 +44,6 @@ import {
import {
BlockNumberServiceRequiredError,
ErrorFactory,
- InvalidAccountOnClient,
InvalidBlockHashError,
InvalidBlockRangeError,
RpcUrlsEmpty,
@@ -75,7 +75,7 @@ type ProtocolRpcConfig = {
export class ProtocolProvider implements IProtocolProvider {
private l1ReadClient: PublicClient>;
private l2ReadClient: PublicClient>;
- private l2WriteClient: WalletClient>;
+ private l2WriteClient: WalletClient, Chain, Account>;
private readonly blockNumberService?: BlockNumberService;
private oracleContract: GetContractReturnType<
@@ -135,11 +135,13 @@ export class ProtocolProvider implements IProtocolProvider {
abi: oracleAbi,
client: this.l2WriteClient,
});
+
this.epochManagerContract = getContract({
address: contracts.epochManager,
abi: epochManagerAbi,
client: this.l2ReadClient,
});
+
this.eboRequestCreatorContract = getContract({
address: contracts.eboRequestCreator,
abi: eboRequestCreatorAbi,
@@ -148,6 +150,7 @@ export class ProtocolProvider implements IProtocolProvider {
wallet: this.l2WriteClient,
},
});
+
this.bondEscalationContract = getContract({
address: contracts.bondEscalationModule,
abi: bondEscalationModuleAbi,
@@ -156,6 +159,7 @@ export class ProtocolProvider implements IProtocolProvider {
wallet: this.l2WriteClient,
},
});
+
this.horizonAccountingExtensionContract = getContract({
address: contracts.horizonAccountingExtension,
abi: horizonAccountingExtensionAbi,
@@ -175,7 +179,6 @@ export class ProtocolProvider implements IProtocolProvider {
settleDispute: this.settleDispute.bind(this),
escalateDispute: this.escalateDispute.bind(this),
finalize: this.finalize.bind(this),
- approveAccountingModules: this.approveAccountingModules.bind(this),
approveModule: this.approveModule.bind(this),
};
@@ -185,7 +188,6 @@ export class ProtocolProvider implements IProtocolProvider {
getEvents: this.getEvents.bind(this),
getAvailableChains: this.getAvailableChains.bind(this),
getAccountingModuleAddress: this.getAccountingModuleAddress.bind(this),
- getAccountingApprovedModules: this.getAccountingApprovedModules.bind(this),
getApprovedModules: this.getApprovedModules.bind(this),
};
@@ -216,7 +218,7 @@ export class ProtocolProvider implements IProtocolProvider {
config: RpcConfig,
chain: Chain,
privateKey: Hex,
- ): WalletClient> {
+ ): WalletClient, Chain, Account> {
const { urls, timeout, retryInterval } = config;
const account = privateKeyToAccount(privateKey);
@@ -257,12 +259,8 @@ export class ProtocolProvider implements IProtocolProvider {
* Returns the address of the account used for transactions.
*
* @returns {Address} The account address.
- * @throws {InvalidAccountOnClient} Throws if the write client does not have an assigned account.
*/
public getAccountAddress(): Address {
- if (!this.l2WriteClient.account) {
- throw new InvalidAccountOnClient();
- }
return this.l2WriteClient.account.address;
}
@@ -760,20 +758,17 @@ export class ProtocolProvider implements IProtocolProvider {
/**
* Gets the list of approved modules' addresses for a given user.
*
- * @param {Address} user - The address of the user.
+ * @param {Address} user - The address of the user. If not specified, it fallbacks to the L2 account address.
* @returns {Promise} A promise that resolves with an array of approved modules for the user.
*/
- async getApprovedModules(user: Address): Promise {
- return [...(await this.horizonAccountingExtensionContract.read.approvedModules([user]))];
- }
+ async getApprovedModules(user?: Address): Promise {
+ const bondAddress = user ?? this.getAccountAddress();
- async getAccountingApprovedModules(): Promise {
- // TODO: implement actual method
- return [];
- }
+ const modules = await this.horizonAccountingExtensionContract.read.approvedModules([
+ bondAddress,
+ ]);
- async approveAccountingModules(_modules: Address[]): Promise {
- // TODO: implement actual method
+ return modules;
}
// TODO: waiting for ChainId to be merged for _chains parameter
diff --git a/packages/automated-dispute/src/services/eboProcessor.ts b/packages/automated-dispute/src/services/eboProcessor.ts
index 2f435da2..9d55db94 100644
--- a/packages/automated-dispute/src/services/eboProcessor.ts
+++ b/packages/automated-dispute/src/services/eboProcessor.ts
@@ -1,14 +1,7 @@
import { isNativeError } from "util/types";
import { BlockNumberService } from "@ebo-agent/blocknumber";
-import {
- Caip2ChainId,
- Caip2Utils,
- HexUtils,
- ILogger,
- stringify,
- UnixTimestamp,
-} from "@ebo-agent/shared";
-import { Block, ContractFunctionRevertedError } from "viem";
+import { Caip2ChainId, Caip2Utils, ILogger, stringify, UnixTimestamp } from "@ebo-agent/shared";
+import { Address, Block, ContractFunctionRevertedError } from "viem";
import {
PastEventEnqueueError,
@@ -86,8 +79,8 @@ export class EboProcessor {
* @throws {PendingModulesApproval} when there is at least one module pending approval
*/
private async checkAllModulesApproved() {
- const approvedModules: HexUtils[] =
- await this.protocolProvider.getAccountingApprovedModules();
+ const approvedModules: readonly Address[] =
+ await this.protocolProvider.getApprovedModules();
const summary: Record<"approved" | "notApproved", Partial> = {
approved: {},
diff --git a/packages/automated-dispute/src/templates/index.ts b/packages/automated-dispute/src/templates/index.ts
index 1a3bdd54..803f9797 100644
--- a/packages/automated-dispute/src/templates/index.ts
+++ b/packages/automated-dispute/src/templates/index.ts
@@ -19,12 +19,13 @@ export const pendingApprovedModulesError = (
approvedModules: Partial,
notApprovedModules: Partial,
) => {
- const approvedModulesList = Object.entries(approvedModules).map(
- ([key, value]) => `* ${key} at ${value}\n`,
- );
- const notApprovedModulesList = Object.entries(notApprovedModules).map(
- ([key, value]) => `* ${key} at ${value}\n`,
- );
+ const approvedModulesList = Object.entries(approvedModules)
+ .map(([key, value]) => `* ${key} at ${value}`)
+ .join("\n");
+
+ const notApprovedModulesList = Object.entries(notApprovedModules)
+ .map(([key, value]) => `* ${key} at ${value}`)
+ .join("\n");
return `
The EBO agent cannot proceed until certain actions are resolved by the operator.
diff --git a/packages/automated-dispute/src/types/prophet.ts b/packages/automated-dispute/src/types/prophet.ts
index 052aa57c..eb21b609 100644
--- a/packages/automated-dispute/src/types/prophet.ts
+++ b/packages/automated-dispute/src/types/prophet.ts
@@ -107,7 +107,6 @@ export interface Dispute {
}
export type AccountingModules = {
- requestModule: Address;
responseModule: Address;
escalationModule: Address;
};
diff --git a/packages/automated-dispute/tests/services/eboProcessor.spec.ts b/packages/automated-dispute/tests/services/eboProcessor.spec.ts
index 320a4d73..a30282ef 100644
--- a/packages/automated-dispute/tests/services/eboProcessor.spec.ts
+++ b/packages/automated-dispute/tests/services/eboProcessor.spec.ts
@@ -53,7 +53,7 @@ describe("EboProcessor", () => {
notifier,
);
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue([]);
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue([]);
const result = processor.start();
@@ -87,9 +87,7 @@ describe("EboProcessor", () => {
},
};
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -153,9 +151,7 @@ describe("EboProcessor", () => {
number: (currentEpoch.firstBlockNumber + 10n) as UnixTimestamp,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -182,9 +178,7 @@ describe("EboProcessor", () => {
number: (currentEpoch.firstBlockNumber + 10n) as UnixTimestamp,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -227,9 +221,7 @@ describe("EboProcessor", () => {
},
};
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
vi.spyOn(actorsManager, "createActor").mockReturnValue(actor);
@@ -279,9 +271,7 @@ describe("EboProcessor", () => {
},
};
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
vi.spyOn(actorsManager, "createActor").mockReturnValue(actor);
@@ -327,9 +317,7 @@ describe("EboProcessor", () => {
})
.mockResolvedValueOnce([]);
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getLastFinalizedBlock")
.mockResolvedValueOnce({ number: initialCurrentBlock + 10n } as unknown as Block<
@@ -403,9 +391,7 @@ describe("EboProcessor", () => {
},
};
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
vi.spyOn(actorsManager, "createActor").mockReturnValue(actor);
@@ -440,9 +426,7 @@ describe("EboProcessor", () => {
number: currentEpoch.firstBlockNumber + 10n,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
@@ -513,9 +497,7 @@ describe("EboProcessor", () => {
number: currentEpoch.firstBlockNumber + 10n,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
@@ -617,9 +599,7 @@ describe("EboProcessor", () => {
"finalized"
>;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -663,9 +643,7 @@ describe("EboProcessor", () => {
number: 1n,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -707,9 +685,7 @@ describe("EboProcessor", () => {
number: 1n,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(
lastFinalizedBlock,
@@ -747,9 +723,7 @@ describe("EboProcessor", () => {
number: currentEpoch.number + 10n,
} as unknown as Block;
- vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue(
- allModulesApproved,
- );
+ vi.spyOn(protocolProvider, "getApprovedModules").mockResolvedValue(allModulesApproved);
vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch);
vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);
diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts
index ba62d243..e2678283 100644
--- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts
+++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts
@@ -11,7 +11,7 @@ import {
http,
WaitForTransactionReceiptTimeoutError,
} from "viem";
-import { privateKeyToAccount } from "viem/accounts";
+import { privateKeyToAccount, privateKeyToAddress } from "viem/accounts";
import { arbitrum } from "viem/chains";
import { afterEach, beforeEach, describe, expect, it, Mock, vi } from "vitest";
@@ -24,7 +24,6 @@ import {
} from "../../src/abis/index.js";
import {
BlockNumberServiceRequiredError,
- InvalidAccountOnClient,
RpcUrlsEmpty,
TransactionExecutionError,
} from "../../src/exceptions/index.js";
@@ -643,19 +642,6 @@ describe("ProtocolProvider", () => {
const expectedAddress = privateKeyToAccount(mockedPrivateKey).address;
expect(protocolProvider.getAccountAddress()).toBe(expectedAddress);
});
-
- it("throws InvalidAccountOnClient when there's no account", () => {
- const protocolProvider = new ProtocolProvider(
- mockRpcConfig,
- mockContractAddress,
- mockedPrivateKey,
- mockBlockNumberService,
- );
-
- (protocolProvider["l2WriteClient"] as any).account = undefined;
-
- expect(() => protocolProvider.getAccountAddress()).toThrow(InvalidAccountOnClient);
- });
});
describe("pledgeForDispute", () => {
@@ -864,6 +850,29 @@ describe("ProtocolProvider", () => {
).toHaveBeenCalledWith([mockUserAddress]);
});
+ it("uses private key account as default", async () => {
+ const protocolProvider = new ProtocolProvider(
+ mockRpcConfig,
+ mockContractAddress,
+ mockedPrivateKey,
+ );
+
+ const approvedModules = [];
+
+ const mockHorizonAccountingApprovedModules = vi
+ .spyOn(
+ protocolProvider["horizonAccountingExtensionContract"].read,
+ "approvedModules",
+ )
+ .mockResolvedValue(approvedModules);
+
+ await protocolProvider.getApprovedModules();
+
+ expect(mockHorizonAccountingApprovedModules).toHaveBeenCalledWith([
+ privateKeyToAddress(mockedPrivateKey),
+ ]);
+ });
+
it("throws error when RPC client fails", async () => {
const protocolProvider = new ProtocolProvider(
mockRpcConfig,