From 1d0d9ae19993c410c408ff9d397e1b3b1c6e9ba6 Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Tue, 19 Nov 2024 19:51:37 -0500 Subject: [PATCH 1/6] feat: add service provider address to config --- apps/agent/.env.example | 4 + apps/agent/README.md | 1 + apps/agent/src/config/index.ts | 1 + apps/agent/src/config/schemas.ts | 9 ++ packages/automated-dispute/src/config.ts | 19 +++ .../src/providers/protocolProvider.ts | 25 ++- .../tests/services/protocolProvider.spec.ts | 152 +++++++++++++----- .../src/services/blockNumberService.ts | 8 +- 8 files changed, 170 insertions(+), 49 deletions(-) diff --git a/apps/agent/.env.example b/apps/agent/.env.example index ec54d70..fdf5d6a 100644 --- a/apps/agent/.env.example +++ b/apps/agent/.env.example @@ -18,3 +18,7 @@ EBO_AGENT_CONFIG_FILE_PATH="./config.example.yml" # Discord webhook notifications DISCORD_WEBHOOK=YOUR_DISCORD_WEBHOOK + +# Optional: Service Provider Address for Access Control Modules +# If not specified, it will be derived from PROTOCOL_PROVIDER_PRIVATE_KEY +SERVICE_PROVIDER_ADDRESS=0xYourServiceProviderAddressHere diff --git a/apps/agent/README.md b/apps/agent/README.md index 53b33cc..08e577a 100644 --- a/apps/agent/README.md +++ b/apps/agent/README.md @@ -38,6 +38,7 @@ cp .env.example .env | `BLOCK_NUMBER_BLOCKMETA_TOKEN` | Bearer token for the Blockmeta service (see notes below on how to obtain) | Yes | | `EBO_AGENT_CONFIG_FILE_PATH` | Path to the agent YAML configuration file | Yes | | `DISCORD_WEBHOOK` | Your Discord channel webhook for notifications [Learn how to create a Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) | No | +| `SERVICE_PROVIDER_ADDRESS` | Service provider address to use with access control modules | No | **Notes:** diff --git a/apps/agent/src/config/index.ts b/apps/agent/src/config/index.ts index 96fea4d..6a845e1 100644 --- a/apps/agent/src/config/index.ts +++ b/apps/agent/src/config/index.ts @@ -68,4 +68,5 @@ export const config = { }, processor: { ...configData.processor }, DISCORD_WEBHOOK: envData.DISCORD_WEBHOOK ?? "", + SERVICE_PROVIDER_ADDRESS: envData.SERVICE_PROVIDER_ADDRESS ?? "", } as const; diff --git a/apps/agent/src/config/schemas.ts b/apps/agent/src/config/schemas.ts index 3712ebb..8e20d12 100644 --- a/apps/agent/src/config/schemas.ts +++ b/apps/agent/src/config/schemas.ts @@ -23,6 +23,13 @@ const rpcUrlsSchema = z .transform((str) => str.split(",")) .refine((arr) => arr.every((url) => z.string().url().safeParse(url).success)); +const serviceProviderAddressSchema = z + .string() + .refine((val) => isAddress(val), { + message: "serviceProviderAddress must be a valid blockchain address", + }) + .optional(); + export const envSchema = z.object({ PROTOCOL_PROVIDER_PRIVATE_KEY: z.string().refine((key) => isHex(key)), PROTOCOL_PROVIDER_L1_RPC_URLS: rpcUrlsSchema, @@ -31,9 +38,11 @@ export const envSchema = z.object({ BLOCK_NUMBER_BLOCKMETA_TOKEN: z.string(), EBO_AGENT_CONFIG_FILE_PATH: z.string(), DISCORD_WEBHOOK: z.string().optional(), + SERVICE_PROVIDER_ADDRESS: serviceProviderAddressSchema, }); const addressSchema = z.string().refine((address) => isAddress(address)); + const rpcConfigSchema = z.object({ chainId: z .string() diff --git a/packages/automated-dispute/src/config.ts b/packages/automated-dispute/src/config.ts index 14d9f5c..49d8da0 100644 --- a/packages/automated-dispute/src/config.ts +++ b/packages/automated-dispute/src/config.ts @@ -1,7 +1,26 @@ +import { isAddress } from "viem"; import { z } from "zod"; const ConfigSchema = z.object({ DISCORD_WEBHOOK: z.string().url().optional(), + accessControl: z + .object({ + /** + * The service provider address used with access control modules. + * This is an optional field. If not provided, it will be derived from the PRIVATE_KEY. + */ + serviceProviderAddress: z + .string() + .refine((val) => isAddress(val), { + message: "serviceProviderAddress must be a valid blockchain address", + }) + .optional(), + }) + .optional(), }); +/** + * Parses and validates the environment variables using the defined schema. + * If validation fails, it throws an error detailing the issues. + */ export const config = ConfigSchema.parse(process.env); diff --git a/packages/automated-dispute/src/providers/protocolProvider.ts b/packages/automated-dispute/src/providers/protocolProvider.ts index 44b9d64..0e1adcd 100644 --- a/packages/automated-dispute/src/providers/protocolProvider.ts +++ b/packages/automated-dispute/src/providers/protocolProvider.ts @@ -71,15 +71,23 @@ type RpcConfig = { type ProtocolRpcConfig = { l1: RpcConfig; l2: RpcConfig; + accessControl?: { + serviceProviderAddress: Address; + }; }; // TODO: add default caching strategy for RPC client export class ProtocolProvider implements IProtocolProvider { private l1ReadClient: PublicClient>; - private l2ReadClient: PublicClient>; - private l2WriteClient: WalletClient, Chain, Account>; + private readonly l2ReadClient: PublicClient>; + private readonly l2WriteClient: WalletClient< + FallbackTransport, + Chain, + Account + >; private readonly blockNumberService?: BlockNumberService; + private readonly serviceProviderAddress: Address; private oracleContract: GetContractReturnType< typeof oracleAbi, @@ -173,6 +181,12 @@ export class ProtocolProvider implements IProtocolProvider { wallet: this.l2WriteClient, }, }); + if (this.rpcConfig.accessControl?.serviceProviderAddress) { + this.serviceProviderAddress = this.rpcConfig.accessControl.serviceProviderAddress; + } else { + const account = privateKeyToAccount(privateKey); + this.serviceProviderAddress = account.address; + } } public write: IWriteProvider = { @@ -197,6 +211,13 @@ export class ProtocolProvider implements IProtocolProvider { getEscalation: this.getEscalation.bind(this), }; + /** + * @returns {Address} The address of the service provider. + */ + public getServiceProviderAddress(): Address { + return this.serviceProviderAddress; + } + private createReadClient( config: RpcConfig, chain: Chain, diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts index eb2023a..9435996 100644 --- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts +++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts @@ -51,8 +51,17 @@ vi.mock("viem", async () => { }; }); +vi.mock("viem/accounts", async () => { + const actual = await vi.importActual("viem/accounts"); + return { + ...actual, + privateKeyToAccount: vi.fn(), + privateKeyToAddress: vi.fn(), + }; +}); + describe("ProtocolProvider", () => { - const mockRpcConfig = { + const mockRpcConfigBase = { l1: { chainId: "eip155:1" as Caip2ChainId, urls: ["http://localhost:8545"], @@ -68,6 +77,20 @@ describe("ProtocolProvider", () => { transactionReceiptConfirmations: 1, }, }; + const mockServiceProviderAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address; + const mockDerivedAddress = "0xDerivedAddressFromPrivateKey" as Address; + + const mockRpcConfigWithServiceProvider = { + ...mockRpcConfigBase, + accessControl: { + serviceProviderAddress: mockServiceProviderAddress, + }, + }; + + const mockRpcConfigWithoutServiceProvider = { + ...mockRpcConfigBase, + // accessControl is omitted to simulate derivation from PRIVATE_KEY + }; const mockContractAddress: ProtocolContractsAddresses = { oracle: "0x1234567890123456789012345678901234567890", @@ -82,6 +105,9 @@ describe("ProtocolProvider", () => { } as unknown as BlockNumberService; beforeEach(() => { + vi.resetModules(); + vi.clearAllMocks(); + (getContract as Mock).mockImplementation(({ address, abi }) => { if (abi === oracleAbi && address === mockContractAddress.oracle) { return { address }; @@ -153,6 +179,18 @@ describe("ProtocolProvider", () => { getContractEvents: vi.fn(), })); + (privateKeyToAccount as Mock).mockReturnValue({ + address: mockDerivedAddress, + publicKey: "0xPublicKey", + signMessage: vi.fn(), + signTransaction: vi.fn(), + signTypedData: vi.fn(), + source: "privateKey", + type: "local", + }); + + (privateKeyToAddress as Mock).mockReturnValue(mockDerivedAddress); + const mockAccount = privateKeyToAccount(mockedPrivateKey); (createWalletClient as Mock).mockReturnValue({ @@ -171,7 +209,7 @@ describe("ProtocolProvider", () => { describe("constructor", () => { it("creates a new ProtocolProvider instance successfully", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigWithoutServiceProvider, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -181,7 +219,7 @@ describe("ProtocolProvider", () => { expect(createPublicClient).toHaveBeenCalledWith({ chain: arbitrum, transport: fallback( - mockRpcConfig.l2.urls.map((url) => + mockRpcConfigBase.l2.urls.map((url) => http(url, { timeout: protocolProvider["TIMEOUT"], retryDelay: protocolProvider["RETRY_INTERVAL"], @@ -193,7 +231,7 @@ describe("ProtocolProvider", () => { expect(createWalletClient).toHaveBeenCalledWith({ chain: arbitrum, transport: fallback( - mockRpcConfig.l2.urls.map((url) => + mockRpcConfigWithoutServiceProvider.l2.urls.map((url) => http(url, { timeout: protocolProvider["TIMEOUT"], retryDelay: protocolProvider["RETRY_INTERVAL"], @@ -228,7 +266,7 @@ describe("ProtocolProvider", () => { expect( () => new ProtocolProvider( - { ...mockRpcConfig, l1: { ...mockRpcConfig.l1, urls: [] } }, + { ...mockRpcConfigBase, l1: { ...mockRpcConfigBase.l1, urls: [] } }, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -241,7 +279,7 @@ describe("ProtocolProvider", () => { expect( () => new ProtocolProvider( - { ...mockRpcConfig, l2: { ...mockRpcConfig.l2, urls: [] } }, + { ...mockRpcConfigBase, l2: { ...mockRpcConfigBase.l2, urls: [] } }, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -268,7 +306,7 @@ describe("ProtocolProvider", () => { } as unknown as BlockNumberService; const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -295,13 +333,13 @@ describe("ProtocolProvider", () => { expect(mockBlockNumberService.getEpochBlockNumber).toHaveBeenCalledWith( mockEpochTimestamp, - mockRpcConfig.l2.chainId, + mockRpcConfigBase.l2.chainId, ); }); it("throws BlockNumberServiceRequiredError when blockNumberService is not provided", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -315,7 +353,7 @@ describe("ProtocolProvider", () => { it("throws when current epoch request fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -336,7 +374,7 @@ describe("ProtocolProvider", () => { it("throws when current epoch block request fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -364,7 +402,7 @@ describe("ProtocolProvider", () => { describe("proposeResponse", () => { it("successfully proposes a response", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -381,7 +419,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -402,7 +440,7 @@ describe("ProtocolProvider", () => { it("throws when transaction couldn't be confirmed", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -423,7 +461,7 @@ describe("ProtocolProvider", () => { it("throws ContractFunctionRevertedError when viem throws it", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -447,7 +485,7 @@ describe("ProtocolProvider", () => { it("throws WaitForTransactionReceiptTimeoutError when waitForTransactionReceipt times out", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -470,7 +508,7 @@ describe("ProtocolProvider", () => { describe("disputeResponse", () => { it("successfully disputes a response", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -492,7 +530,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -520,7 +558,7 @@ describe("ProtocolProvider", () => { describe("escalateDispute", () => { it("successfully escalates a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -542,7 +580,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -580,7 +618,7 @@ describe("ProtocolProvider", () => { describe("finalize", () => { it("successfully finalizes a request", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -597,7 +635,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -620,7 +658,7 @@ describe("ProtocolProvider", () => { describe("createRequest", () => { it("creates a request successfully", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -657,22 +695,20 @@ describe("ProtocolProvider", () => { describe("getAccountAddress", () => { it("returns the correct account address", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), mockBlockNumberService, ); - - const expectedAddress = privateKeyToAccount(mockedPrivateKey).address; - expect(protocolProvider.getAccountAddress()).toBe(expectedAddress); + expect(protocolProvider.getAccountAddress()).toBe(mockDerivedAddress); }); }); describe("pledgeForDispute", () => { it("successfully pledges for a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -689,7 +725,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -712,7 +748,7 @@ describe("ProtocolProvider", () => { describe("pledgeAgainstDispute", () => { it("successfully pledges against a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -732,7 +768,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -758,7 +794,7 @@ describe("ProtocolProvider", () => { describe("settleDispute", () => { it("successfully settles a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -780,7 +816,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -808,7 +844,7 @@ describe("ProtocolProvider", () => { describe("approveModule", () => { it("successfully approves a module", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -837,7 +873,7 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -859,7 +895,7 @@ describe("ProtocolProvider", () => { describe("approvedModules", () => { it("successfully retrieves approved modules for a user", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -886,7 +922,7 @@ describe("ProtocolProvider", () => { it("uses private key account as default", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -911,7 +947,7 @@ describe("ProtocolProvider", () => { it("throws error when RPC client fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -934,7 +970,7 @@ describe("ProtocolProvider", () => { describe("getOracleEvents", () => { it("successfully fetches and parses Oracle events", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1004,7 +1040,7 @@ describe("ProtocolProvider", () => { const request = DEFAULT_MOCKED_REQUEST_CREATED_DATA; const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1155,7 +1191,7 @@ describe("ProtocolProvider", () => { describe("getAvailableChains", () => { it("successfully retrieves available chains", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1183,7 +1219,7 @@ describe("ProtocolProvider", () => { it("returns an empty array if no chains are allowed", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1204,7 +1240,7 @@ describe("ProtocolProvider", () => { it("throws FetchAvailableChainsError when RPC call fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1224,7 +1260,7 @@ describe("ProtocolProvider", () => { describe("getAccountingModuleAddress", () => { it("returns the correct accounting module address", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -1236,4 +1272,32 @@ describe("ProtocolProvider", () => { ); }); }); + + describe("Service Provider Address", () => { + it("uses the provided serviceProviderAddress from env", () => { + const protocolProvider = new ProtocolProvider( + mockRpcConfigWithServiceProvider, + mockContractAddress, + mockedPrivateKey, + mockLogger(), + mockBlockNumberService, + ); + + expect(protocolProvider.getServiceProviderAddress()).toBe(mockServiceProviderAddress); + }); + + it("derives serviceProviderAddress from PRIVATE_KEY when not provided", () => { + const derivedAddress = "0xDerivedAddressFromPrivateKey" as Address; + + const protocolProvider = new ProtocolProvider( + mockRpcConfigWithoutServiceProvider, + mockContractAddress, + mockedPrivateKey, + mockLogger(), + mockBlockNumberService, + ); + + expect(protocolProvider.getServiceProviderAddress()).toBe(derivedAddress); + }); + }); }); diff --git a/packages/blocknumber/src/services/blockNumberService.ts b/packages/blocknumber/src/services/blockNumberService.ts index 1d9baa2..617bfeb 100644 --- a/packages/blocknumber/src/services/blockNumberService.ts +++ b/packages/blocknumber/src/services/blockNumberService.ts @@ -8,9 +8,11 @@ import { import { createPublicClient, fallback, http } from "viem"; import { ChainWithoutProvider, EmptyRpcUrls, UnsupportedChain } from "../exceptions/index.js"; -import { BlockmetaClientConfig } from "../providers/blockmetaJsonBlockNumberProvider.js"; -import { BlockNumberProvider } from "../providers/blockNumberProvider.js"; -import { BlockNumberProviderFactory } from "../providers/blockNumberProviderFactory.js"; +import { + BlockmetaClientConfig, + BlockNumberProvider, + BlockNumberProviderFactory, +} from "../providers/index.js"; type RpcUrl = NonNullable[0]>; From e6accab572477308555c6c3f93306f06f6a5fd40 Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:09:53 -0500 Subject: [PATCH 2/6] chore: cleanup types and docs --- apps/agent/src/config/index.ts | 4 +++- apps/agent/src/config/schemas.ts | 5 +++++ apps/scripts/utilities/approveAccountingModules.ts | 11 ++++++++++- .../tests/services/protocolProvider.spec.ts | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/agent/src/config/index.ts b/apps/agent/src/config/index.ts index 6a845e1..1d72e60 100644 --- a/apps/agent/src/config/index.ts +++ b/apps/agent/src/config/index.ts @@ -68,5 +68,7 @@ export const config = { }, processor: { ...configData.processor }, DISCORD_WEBHOOK: envData.DISCORD_WEBHOOK ?? "", - SERVICE_PROVIDER_ADDRESS: envData.SERVICE_PROVIDER_ADDRESS ?? "", + accessControl: envData.SERVICE_PROVIDER_ADDRESS + ? { serviceProviderAddress: envData.SERVICE_PROVIDER_ADDRESS } + : undefined, } as const; diff --git a/apps/agent/src/config/schemas.ts b/apps/agent/src/config/schemas.ts index 8e20d12..8a43359 100644 --- a/apps/agent/src/config/schemas.ts +++ b/apps/agent/src/config/schemas.ts @@ -52,6 +52,10 @@ const rpcConfigSchema = z.object({ retryInterval: z.number().int().positive(), }); +const accessControlSchema = z.object({ + serviceProviderAddress: addressSchema.optional(), +}); + const protocolProviderConfigSchema = z.object({ rpcsConfig: z.object({ l1: rpcConfigSchema, @@ -64,6 +68,7 @@ const protocolProviderConfigSchema = z.object({ bondEscalationModule: addressSchema, horizonAccountingExtension: addressSchema, }), + accessControl: accessControlSchema.optional(), }); const blockNumberServiceSchema = z.object({ diff --git a/apps/scripts/utilities/approveAccountingModules.ts b/apps/scripts/utilities/approveAccountingModules.ts index c0f42f6..e0e721e 100644 --- a/apps/scripts/utilities/approveAccountingModules.ts +++ b/apps/scripts/utilities/approveAccountingModules.ts @@ -2,7 +2,7 @@ import { ProtocolProvider } from "@ebo-agent/automated-dispute/src/index.js"; import { mockLogger } from "@ebo-agent/automated-dispute/tests/mocks/logger.mocks.js"; import { Caip2ChainId } from "@ebo-agent/shared"; import * as dotenv from "dotenv"; -import { Address, Hex, isHex } from "viem"; +import { Address, Hex, isAddress, isHex } from "viem"; import { z } from "zod"; dotenv.config(); @@ -70,6 +70,12 @@ const envSchema = z.object({ CONTRACTS_ADDRESSES: stringToJSONSchema.pipe(contractsAddressesSchema), BONDED_RESPONSE_MODULE_ADDRESS: z.string().min(1, "BONDED_RESPONSE_MODULE_ADDRESS is required"), BOND_ESCALATION_MODULE_ADDRESS: z.string().min(1, "BOND_ESCALATION_MODULE_ADDRESS is required"), + SERVICE_PROVIDER_ADDRESS: z + .string() + .refine((val) => isAddress(val), { + message: "SERVICE_PROVIDER_ADDRESS must be a valid blockchain address", + }) + .optional(), }); const envResult = envSchema.safeParse(process.env); @@ -99,6 +105,9 @@ const rpcConfig = { timeout: env.TIMEOUT, retryInterval: env.RETRY_INTERVAL, }, + accessControl: env.SERVICE_PROVIDER_ADDRESS + ? { serviceProviderAddress: env.SERVICE_PROVIDER_ADDRESS as Address } + : undefined, }; const contracts = env.CONTRACTS_ADDRESSES; diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts index 9435996..1ec7d96 100644 --- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts +++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts @@ -1286,7 +1286,7 @@ describe("ProtocolProvider", () => { expect(protocolProvider.getServiceProviderAddress()).toBe(mockServiceProviderAddress); }); - it("derives serviceProviderAddress from PRIVATE_KEY when not provided", () => { + it("derives serviceProviderAddress from PROTOCOL_PROVIDER_PRIVATE_KEY when not provided", () => { const derivedAddress = "0xDerivedAddressFromPrivateKey" as Address; const protocolProvider = new ProtocolProvider( From f764db0ed69908568a32d9568370e5653c765e4f Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:11:42 -0500 Subject: [PATCH 3/6] chore: cleanup docs --- packages/automated-dispute/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/automated-dispute/src/config.ts b/packages/automated-dispute/src/config.ts index 49d8da0..1f59148 100644 --- a/packages/automated-dispute/src/config.ts +++ b/packages/automated-dispute/src/config.ts @@ -7,7 +7,7 @@ const ConfigSchema = z.object({ .object({ /** * The service provider address used with access control modules. - * This is an optional field. If not provided, it will be derived from the PRIVATE_KEY. + * This is an optional field. If not provided, it will be derived from the PROTOCOL_PROVIDER_PRIVATE_KEY. */ serviceProviderAddress: z .string() From e5db40f4030d971fddb700adea60c51f6bdc3009 Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:13:07 -0500 Subject: [PATCH 4/6] chore: cleanup docs --- .../automated-dispute/tests/services/protocolProvider.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts index 1ec7d96..832626e 100644 --- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts +++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts @@ -89,7 +89,7 @@ describe("ProtocolProvider", () => { const mockRpcConfigWithoutServiceProvider = { ...mockRpcConfigBase, - // accessControl is omitted to simulate derivation from PRIVATE_KEY + // accessControl is omitted to simulate derivation from PROTOCOL_PROVIDER_PRIVATE_KEY }; const mockContractAddress: ProtocolContractsAddresses = { From 0d7cd9d049b9271632a4f0ff024958e7ac36e322 Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:42:42 -0500 Subject: [PATCH 5/6] fix: pr comments --- apps/agent/.env.example | 6 +-- apps/agent/README.md | 1 - apps/agent/config.example.yml | 2 + apps/agent/src/config/index.ts | 3 -- apps/agent/src/config/schemas.ts | 17 +++---- .../utilities/approveAccountingModules.ts | 3 -- packages/automated-dispute/src/config.ts | 15 ------ .../src/providers/protocolProvider.ts | 49 +++++++++---------- .../tests/services/protocolProvider.spec.ts | 12 ++--- 9 files changed, 37 insertions(+), 71 deletions(-) diff --git a/apps/agent/.env.example b/apps/agent/.env.example index fdf5d6a..d825fc7 100644 --- a/apps/agent/.env.example +++ b/apps/agent/.env.example @@ -17,8 +17,4 @@ BLOCK_NUMBER_BLOCKMETA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNlIjoidH EBO_AGENT_CONFIG_FILE_PATH="./config.example.yml" # Discord webhook notifications -DISCORD_WEBHOOK=YOUR_DISCORD_WEBHOOK - -# Optional: Service Provider Address for Access Control Modules -# If not specified, it will be derived from PROTOCOL_PROVIDER_PRIVATE_KEY -SERVICE_PROVIDER_ADDRESS=0xYourServiceProviderAddressHere +DISCORD_WEBHOOK=YOUR_DISCORD_WEBHOOK \ No newline at end of file diff --git a/apps/agent/README.md b/apps/agent/README.md index 08e577a..53b33cc 100644 --- a/apps/agent/README.md +++ b/apps/agent/README.md @@ -38,7 +38,6 @@ cp .env.example .env | `BLOCK_NUMBER_BLOCKMETA_TOKEN` | Bearer token for the Blockmeta service (see notes below on how to obtain) | Yes | | `EBO_AGENT_CONFIG_FILE_PATH` | Path to the agent YAML configuration file | Yes | | `DISCORD_WEBHOOK` | Your Discord channel webhook for notifications [Learn how to create a Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) | No | -| `SERVICE_PROVIDER_ADDRESS` | Service provider address to use with access control modules | No | **Notes:** diff --git a/apps/agent/config.example.yml b/apps/agent/config.example.yml index 60f0e14..e61103b 100644 --- a/apps/agent/config.example.yml +++ b/apps/agent/config.example.yml @@ -16,6 +16,8 @@ protocolProvider: eboRequestCreator: "0x1234567890123456789012345678901234567890" # EBO Request Creator contract bondEscalationModule: "0x1234567890123456789012345678901234567890" # Bond Escalation Module contract horizonAccountingExtension: "0x1234567890123456789012345678901234567890" # Accounting extension contract + accessControl: + serviceProviderAddress: "0x1234567890123456789012345678901234567890" # Service Provider Address blockNumberService: blockmetaConfig: diff --git a/apps/agent/src/config/index.ts b/apps/agent/src/config/index.ts index 1d72e60..96fea4d 100644 --- a/apps/agent/src/config/index.ts +++ b/apps/agent/src/config/index.ts @@ -68,7 +68,4 @@ export const config = { }, processor: { ...configData.processor }, DISCORD_WEBHOOK: envData.DISCORD_WEBHOOK ?? "", - accessControl: envData.SERVICE_PROVIDER_ADDRESS - ? { serviceProviderAddress: envData.SERVICE_PROVIDER_ADDRESS } - : undefined, } as const; diff --git a/apps/agent/src/config/schemas.ts b/apps/agent/src/config/schemas.ts index 8a43359..dc83d15 100644 --- a/apps/agent/src/config/schemas.ts +++ b/apps/agent/src/config/schemas.ts @@ -23,13 +23,6 @@ const rpcUrlsSchema = z .transform((str) => str.split(",")) .refine((arr) => arr.every((url) => z.string().url().safeParse(url).success)); -const serviceProviderAddressSchema = z - .string() - .refine((val) => isAddress(val), { - message: "serviceProviderAddress must be a valid blockchain address", - }) - .optional(); - export const envSchema = z.object({ PROTOCOL_PROVIDER_PRIVATE_KEY: z.string().refine((key) => isHex(key)), PROTOCOL_PROVIDER_L1_RPC_URLS: rpcUrlsSchema, @@ -38,7 +31,6 @@ export const envSchema = z.object({ BLOCK_NUMBER_BLOCKMETA_TOKEN: z.string(), EBO_AGENT_CONFIG_FILE_PATH: z.string(), DISCORD_WEBHOOK: z.string().optional(), - SERVICE_PROVIDER_ADDRESS: serviceProviderAddressSchema, }); const addressSchema = z.string().refine((address) => isAddress(address)); @@ -52,8 +44,13 @@ const rpcConfigSchema = z.object({ retryInterval: z.number().int().positive(), }); -const accessControlSchema = z.object({ - serviceProviderAddress: addressSchema.optional(), +export const accessControlSchema = z.object({ + serviceProviderAddress: z + .string() + .refine((val) => isAddress(val), { + message: "serviceProviderAddress must be a valid blockchain address", + }) + .optional(), }); const protocolProviderConfigSchema = z.object({ diff --git a/apps/scripts/utilities/approveAccountingModules.ts b/apps/scripts/utilities/approveAccountingModules.ts index e0e721e..d27fda2 100644 --- a/apps/scripts/utilities/approveAccountingModules.ts +++ b/apps/scripts/utilities/approveAccountingModules.ts @@ -105,9 +105,6 @@ const rpcConfig = { timeout: env.TIMEOUT, retryInterval: env.RETRY_INTERVAL, }, - accessControl: env.SERVICE_PROVIDER_ADDRESS - ? { serviceProviderAddress: env.SERVICE_PROVIDER_ADDRESS as Address } - : undefined, }; const contracts = env.CONTRACTS_ADDRESSES; diff --git a/packages/automated-dispute/src/config.ts b/packages/automated-dispute/src/config.ts index 1f59148..5150f94 100644 --- a/packages/automated-dispute/src/config.ts +++ b/packages/automated-dispute/src/config.ts @@ -1,22 +1,7 @@ -import { isAddress } from "viem"; import { z } from "zod"; const ConfigSchema = z.object({ DISCORD_WEBHOOK: z.string().url().optional(), - accessControl: z - .object({ - /** - * The service provider address used with access control modules. - * This is an optional field. If not provided, it will be derived from the PROTOCOL_PROVIDER_PRIVATE_KEY. - */ - serviceProviderAddress: z - .string() - .refine((val) => isAddress(val), { - message: "serviceProviderAddress must be a valid blockchain address", - }) - .optional(), - }) - .optional(), }); /** diff --git a/packages/automated-dispute/src/providers/protocolProvider.ts b/packages/automated-dispute/src/providers/protocolProvider.ts index 0e1adcd..ba1b6ba 100644 --- a/packages/automated-dispute/src/providers/protocolProvider.ts +++ b/packages/automated-dispute/src/providers/protocolProvider.ts @@ -71,9 +71,10 @@ type RpcConfig = { type ProtocolRpcConfig = { l1: RpcConfig; l2: RpcConfig; - accessControl?: { - serviceProviderAddress: Address; - }; +}; + +type ProtocolProviderConfig = ProtocolRpcConfig & { + serviceProviderAddress?: Address; }; // TODO: add default caching strategy for RPC client @@ -121,26 +122,28 @@ export class ProtocolProvider implements IProtocolProvider { /** * Creates a new ProtocolProvider instance - * @param rpcConfig The configuration for RPC connections including URLs, timeout, retry interval, and transaction receipt confirmations + * @param config The configuration for the serviceProviderAddress and RPC connections, including URLs, timeout, retry interval, and transaction receipt confirmations * @param contracts The addresses of the protocol contracts that will be instantiated * @param privateKey The private key of the account that will be used to interact with the contracts * @param logger The logger instance * @param blockNumberService The service that will be used to fetch block numbers */ constructor( - private readonly rpcConfig: ProtocolRpcConfig, + private readonly config: ProtocolProviderConfig, contracts: ProtocolContractsAddresses, privateKey: Hex, private readonly logger: ILogger, blockNumberService?: BlockNumberService, ) { - const l1Chain = this.getViemChain(rpcConfig.l1.chainId); - const l2Chain = this.getViemChain(rpcConfig.l2.chainId); + const l1Chain = this.getViemChain(config.l1.chainId); + const l2Chain = this.getViemChain(config.l2.chainId); - this.l1ReadClient = this.createReadClient(rpcConfig.l1, l1Chain); - this.l2ReadClient = this.createReadClient(rpcConfig.l2, l2Chain); - this.l2WriteClient = this.createWriteClient(rpcConfig.l2, l2Chain, privateKey); + this.l1ReadClient = this.createReadClient(config.l1, l1Chain); + this.l2ReadClient = this.createReadClient(config.l2, l2Chain); + this.l2WriteClient = this.createWriteClient(config.l2, l2Chain, privateKey); this.blockNumberService = blockNumberService; + this.serviceProviderAddress = + config.serviceProviderAddress || privateKeyToAccount(privateKey).address; // Instantiate all the protocol contracts this.oracleContract = getContract({ @@ -181,12 +184,6 @@ export class ProtocolProvider implements IProtocolProvider { wallet: this.l2WriteClient, }, }); - if (this.rpcConfig.accessControl?.serviceProviderAddress) { - this.serviceProviderAddress = this.rpcConfig.accessControl.serviceProviderAddress; - } else { - const account = privateKeyToAccount(privateKey); - this.serviceProviderAddress = account.address; - } } public write: IWriteProvider = { @@ -349,7 +346,7 @@ export class ProtocolProvider implements IProtocolProvider { const startTimestamp = epochFirstBlock.timestamp as UnixTimestamp; - const l2ChainId = this.rpcConfig.l2.chainId; + const l2ChainId = this.config.l2.chainId; const l2FirstBlockNumber = await this.blockNumberService.getEpochBlockNumber( startTimestamp, l2ChainId, @@ -825,7 +822,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -873,7 +870,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(request); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -907,7 +904,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -943,7 +940,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -978,7 +975,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1025,7 +1022,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1076,7 +1073,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1132,7 +1129,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1172,7 +1169,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.rpcConfig.l2; + const { transactionReceiptConfirmations } = this.config.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts index 832626e..d660f5b 100644 --- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts +++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts @@ -82,9 +82,7 @@ describe("ProtocolProvider", () => { const mockRpcConfigWithServiceProvider = { ...mockRpcConfigBase, - accessControl: { - serviceProviderAddress: mockServiceProviderAddress, - }, + serviceProviderAddress: mockServiceProviderAddress, }; const mockRpcConfigWithoutServiceProvider = { @@ -1274,7 +1272,7 @@ describe("ProtocolProvider", () => { }); describe("Service Provider Address", () => { - it("uses the provided serviceProviderAddress from env", () => { + it("uses the provided serviceProviderAddress from config", () => { const protocolProvider = new ProtocolProvider( mockRpcConfigWithServiceProvider, mockContractAddress, @@ -1286,9 +1284,7 @@ describe("ProtocolProvider", () => { expect(protocolProvider.getServiceProviderAddress()).toBe(mockServiceProviderAddress); }); - it("derives serviceProviderAddress from PROTOCOL_PROVIDER_PRIVATE_KEY when not provided", () => { - const derivedAddress = "0xDerivedAddressFromPrivateKey" as Address; - + it("derives serviceProviderAddress from PROTOCOL_PROVIDER_PRIVATE_KEY when not provided in config", () => { const protocolProvider = new ProtocolProvider( mockRpcConfigWithoutServiceProvider, mockContractAddress, @@ -1297,7 +1293,7 @@ describe("ProtocolProvider", () => { mockBlockNumberService, ); - expect(protocolProvider.getServiceProviderAddress()).toBe(derivedAddress); + expect(protocolProvider.getServiceProviderAddress()).toBe(mockDerivedAddress); }); }); }); From 54fbd3a8bdd903de1811733838b8d8b1e0490e94 Mon Sep 17 00:00:00 2001 From: jahabeebs <47253537+jahabeebs@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:56:46 -0500 Subject: [PATCH 6/6] fix: pr comments --- apps/agent/src/index.ts | 1 + .../utilities/approveAccountingModules.ts | 8 +++- .../src/providers/protocolProvider.ts | 38 +++++++++--------- .../tests/mocks/eboActor.mocks.ts | 31 ++++++++------- .../tests/mocks/eboProcessor.mocks.ts | 4 +- .../tests/services/eboActor/fixtures.ts | 2 + .../tests/services/protocolProvider.spec.ts | 39 ++++++++++++++++++- 7 files changed, 88 insertions(+), 35 deletions(-) diff --git a/apps/agent/src/index.ts b/apps/agent/src/index.ts index 9124bc6..1a63c24 100644 --- a/apps/agent/src/index.ts +++ b/apps/agent/src/index.ts @@ -42,6 +42,7 @@ const main = async (): Promise => { config.protocolProvider.rpcsConfig, config.protocolProvider.contracts, config.protocolProvider.privateKey, + config.protocolProvider.accessControl?.serviceProviderAddress, logger, blockNumberService, ); diff --git a/apps/scripts/utilities/approveAccountingModules.ts b/apps/scripts/utilities/approveAccountingModules.ts index d27fda2..1f306c1 100644 --- a/apps/scripts/utilities/approveAccountingModules.ts +++ b/apps/scripts/utilities/approveAccountingModules.ts @@ -109,7 +109,13 @@ const rpcConfig = { const contracts = env.CONTRACTS_ADDRESSES; -const provider = new ProtocolProvider(rpcConfig, contracts, env.PRIVATE_KEY as Hex, mockLogger()); +const provider = new ProtocolProvider( + rpcConfig, + contracts, + env.PRIVATE_KEY as Hex, + env.SERVICE_PROVIDER_ADDRESS, + mockLogger(), +); /** * Approves the necessary modules by calling approveModule on ProtocolProvider. diff --git a/packages/automated-dispute/src/providers/protocolProvider.ts b/packages/automated-dispute/src/providers/protocolProvider.ts index ba1b6ba..92a9d51 100644 --- a/packages/automated-dispute/src/providers/protocolProvider.ts +++ b/packages/automated-dispute/src/providers/protocolProvider.ts @@ -122,28 +122,30 @@ export class ProtocolProvider implements IProtocolProvider { /** * Creates a new ProtocolProvider instance - * @param config The configuration for the serviceProviderAddress and RPC connections, including URLs, timeout, retry interval, and transaction receipt confirmations + * @param rpcConfig The configuration for the serviceProviderAddress and RPC connections, including URLs, timeout, retry interval, and transaction receipt confirmations * @param contracts The addresses of the protocol contracts that will be instantiated * @param privateKey The private key of the account that will be used to interact with the contracts + * @param serviceProviderAddress The address of the service provider * @param logger The logger instance * @param blockNumberService The service that will be used to fetch block numbers */ constructor( - private readonly config: ProtocolProviderConfig, + private readonly rpcConfig: ProtocolProviderConfig, contracts: ProtocolContractsAddresses, privateKey: Hex, + serviceProviderAddress: Address | undefined, private readonly logger: ILogger, blockNumberService?: BlockNumberService, ) { - const l1Chain = this.getViemChain(config.l1.chainId); - const l2Chain = this.getViemChain(config.l2.chainId); + const l1Chain = this.getViemChain(rpcConfig.l1.chainId); + const l2Chain = this.getViemChain(rpcConfig.l2.chainId); - this.l1ReadClient = this.createReadClient(config.l1, l1Chain); - this.l2ReadClient = this.createReadClient(config.l2, l2Chain); - this.l2WriteClient = this.createWriteClient(config.l2, l2Chain, privateKey); + this.l1ReadClient = this.createReadClient(rpcConfig.l1, l1Chain); + this.l2ReadClient = this.createReadClient(rpcConfig.l2, l2Chain); + this.l2WriteClient = this.createWriteClient(rpcConfig.l2, l2Chain, privateKey); this.blockNumberService = blockNumberService; this.serviceProviderAddress = - config.serviceProviderAddress || privateKeyToAccount(privateKey).address; + serviceProviderAddress || privateKeyToAccount(privateKey).address; // Instantiate all the protocol contracts this.oracleContract = getContract({ @@ -346,7 +348,7 @@ export class ProtocolProvider implements IProtocolProvider { const startTimestamp = epochFirstBlock.timestamp as UnixTimestamp; - const l2ChainId = this.config.l2.chainId; + const l2ChainId = this.rpcConfig.l2.chainId; const l2FirstBlockNumber = await this.blockNumberService.getEpochBlockNumber( startTimestamp, l2ChainId, @@ -822,7 +824,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -870,7 +872,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(request); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -904,7 +906,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -940,7 +942,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -975,7 +977,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1022,7 +1024,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1073,7 +1075,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1129,7 +1131,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, @@ -1169,7 +1171,7 @@ export class ProtocolProvider implements IProtocolProvider { const hash = await this.l2WriteClient.writeContract(simulatedRequest); - const { transactionReceiptConfirmations } = this.config.l2; + const { transactionReceiptConfirmations } = this.rpcConfig.l2; const receipt = await this.l2ReadClient.waitForTransactionReceipt({ hash, confirmations: transactionReceiptConfirmations, diff --git a/packages/automated-dispute/tests/mocks/eboActor.mocks.ts b/packages/automated-dispute/tests/mocks/eboActor.mocks.ts index 262d946..5c64294 100644 --- a/packages/automated-dispute/tests/mocks/eboActor.mocks.ts +++ b/packages/automated-dispute/tests/mocks/eboActor.mocks.ts @@ -18,6 +18,7 @@ import { DEFAULT_MOCKED_PROTOCOL_CONTRACTS, DEFAULT_MOCKED_REQUEST_CREATED_DATA, mockedPrivateKey, + mockServiceProviderAddress, } from "../services/eboActor/fixtures.js"; /** @@ -50,6 +51,7 @@ export function buildEboActor(request: Request, logger: ILogger) { }, DEFAULT_MOCKED_PROTOCOL_CONTRACTS, mockedPrivateKey, + mockServiceProviderAddress, logger, ); @@ -76,6 +78,20 @@ export function buildEboActor(request: Request, logger: ILogger) { [chainId, ["http://localhost:8539"]], ]); + const notificationService: NotificationService = { + send: vi.fn().mockResolvedValue(undefined), + sendOrThrow: vi.fn().mockResolvedValue(undefined), + createErrorMessage: vi + .fn() + .mockImplementation((defaultMessage: string, context?: unknown, err?: unknown) => { + return { + title: defaultMessage, + description: err instanceof Error ? err.message : undefined, + }; + }), + sendError: vi.fn().mockResolvedValue(undefined), + }; + const blockNumberService = new BlockNumberService( blockNumberRpcUrls, { @@ -88,6 +104,7 @@ export function buildEboActor(request: Request, logger: ILogger) { }, }, logger, + notificationService, ); vi.spyOn(blockNumberService, "getEpochBlockNumber").mockResolvedValue(BigInt(12345)); @@ -96,20 +113,6 @@ export function buildEboActor(request: Request, logger: ILogger) { const eventProcessingMutex = new Mutex(); - const notificationService: NotificationService = { - send: vi.fn().mockResolvedValue(undefined), - sendOrThrow: vi.fn().mockResolvedValue(undefined), - createErrorMessage: vi - .fn() - .mockImplementation((defaultMessage: string, context?: unknown, err?: unknown) => { - return { - title: defaultMessage, - description: err instanceof Error ? err.message : undefined, - }; - }), - sendError: vi.fn().mockResolvedValue(undefined), - }; - const actor = new EboActor( { id, epoch, chainId }, protocolProvider, diff --git a/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts b/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts index eb2b183..47fba6c 100644 --- a/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts +++ b/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts @@ -8,6 +8,7 @@ import { AccountingModules } from "../../src/types/prophet.js"; import { DEFAULT_MOCKED_PROTOCOL_CONTRACTS, mockedPrivateKey, + mockServiceProviderAddress, } from "../services/eboActor/fixtures.js"; export function buildEboProcessor( @@ -16,7 +17,7 @@ export function buildEboProcessor( responseModule: "0x02", escalationModule: "0x03", }, - notifier?: NotificationService, + notifier: NotificationService, ) { const blockNumberRpcUrls = new Map([ ["eip155:1" as Caip2ChainId, ["http://localhost:8539"]], @@ -56,6 +57,7 @@ export function buildEboProcessor( }, DEFAULT_MOCKED_PROTOCOL_CONTRACTS, mockedPrivateKey, + mockServiceProviderAddress, logger, blockNumberService, ); diff --git a/packages/automated-dispute/tests/services/eboActor/fixtures.ts b/packages/automated-dispute/tests/services/eboActor/fixtures.ts index 1e203a9..be3ea45 100644 --- a/packages/automated-dispute/tests/services/eboActor/fixtures.ts +++ b/packages/automated-dispute/tests/services/eboActor/fixtures.ts @@ -15,6 +15,8 @@ import { export const mockedPrivateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +export const mockServiceProviderAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address; + export const DEFAULT_MOCKED_PROTOCOL_CONTRACTS: ProtocolContractsAddresses = { oracle: "0x1234560000000000000000000000000000000000" as Address, epochManager: "0x6543210000000000000000000000000000000000" as Address, diff --git a/packages/automated-dispute/tests/services/protocolProvider.spec.ts b/packages/automated-dispute/tests/services/protocolProvider.spec.ts index d660f5b..b3e4f0d 100644 --- a/packages/automated-dispute/tests/services/protocolProvider.spec.ts +++ b/packages/automated-dispute/tests/services/protocolProvider.spec.ts @@ -37,6 +37,7 @@ import { DEFAULT_MOCKED_REQUEST_CREATED_DATA, DEFAULT_MOCKED_RESPONSE_DATA, mockedPrivateKey, + mockServiceProviderAddress, } from "./eboActor/fixtures.js"; vi.mock("viem", async () => { @@ -77,7 +78,6 @@ describe("ProtocolProvider", () => { transactionReceiptConfirmations: 1, }, }; - const mockServiceProviderAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address; const mockDerivedAddress = "0xDerivedAddressFromPrivateKey" as Address; const mockRpcConfigWithServiceProvider = { @@ -267,6 +267,7 @@ describe("ProtocolProvider", () => { { ...mockRpcConfigBase, l1: { ...mockRpcConfigBase.l1, urls: [] } }, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ), @@ -280,6 +281,7 @@ describe("ProtocolProvider", () => { { ...mockRpcConfigBase, l2: { ...mockRpcConfigBase.l2, urls: [] } }, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ), @@ -307,6 +309,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -354,6 +357,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -375,6 +379,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -403,6 +408,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -420,6 +426,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -441,6 +448,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -462,6 +470,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -486,6 +495,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -509,6 +519,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -531,6 +542,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -559,6 +571,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -581,6 +594,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -619,6 +633,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -636,6 +651,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -659,6 +675,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -696,6 +713,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -709,6 +727,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -726,6 +745,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -749,6 +769,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -769,6 +790,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -795,6 +817,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -817,6 +840,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -845,6 +869,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -874,6 +899,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -896,6 +922,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -923,6 +950,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -948,6 +976,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -971,6 +1000,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1041,6 +1071,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1192,6 +1223,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1220,6 +1252,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1241,6 +1274,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1261,6 +1295,7 @@ describe("ProtocolProvider", () => { mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1277,6 +1312,7 @@ describe("ProtocolProvider", () => { mockRpcConfigWithServiceProvider, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1289,6 +1325,7 @@ describe("ProtocolProvider", () => { mockRpcConfigWithoutServiceProvider, mockContractAddress, mockedPrivateKey, + undefined, mockLogger(), mockBlockNumberService, );