From 09c4dcda990f359e33b6267e5109db141ed49b7d Mon Sep 17 00:00:00 2001 From: Beebs <47253537+jahabeebs@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:01:53 -0500 Subject: [PATCH] feat: add service provider address to config (#93) --- apps/agent/.env.example | 2 +- apps/agent/config.example.yml | 2 + apps/agent/src/config/schemas.ts | 11 ++ apps/agent/src/index.ts | 1 + .../utilities/approveAccountingModules.ts | 16 +- packages/automated-dispute/src/config.ts | 4 + .../src/providers/protocolProvider.ts | 28 ++- .../tests/mocks/eboActor.mocks.ts | 2 + .../tests/mocks/eboProcessor.mocks.ts | 4 +- .../tests/services/eboActor/fixtures.ts | 2 + .../tests/services/protocolProvider.spec.ts | 185 +++++++++++++----- .../src/services/blockNumberService.ts | 8 +- 12 files changed, 210 insertions(+), 55 deletions(-) diff --git a/apps/agent/.env.example b/apps/agent/.env.example index ec54d70..d825fc7 100644 --- a/apps/agent/.env.example +++ b/apps/agent/.env.example @@ -17,4 +17,4 @@ BLOCK_NUMBER_BLOCKMETA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNlIjoidH EBO_AGENT_CONFIG_FILE_PATH="./config.example.yml" # Discord webhook notifications -DISCORD_WEBHOOK=YOUR_DISCORD_WEBHOOK +DISCORD_WEBHOOK=YOUR_DISCORD_WEBHOOK \ No newline at end of file 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/schemas.ts b/apps/agent/src/config/schemas.ts index 3712ebb..dc83d15 100644 --- a/apps/agent/src/config/schemas.ts +++ b/apps/agent/src/config/schemas.ts @@ -34,6 +34,7 @@ export const envSchema = z.object({ }); const addressSchema = z.string().refine((address) => isAddress(address)); + const rpcConfigSchema = z.object({ chainId: z .string() @@ -43,6 +44,15 @@ const rpcConfigSchema = z.object({ retryInterval: z.number().int().positive(), }); +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({ rpcsConfig: z.object({ l1: rpcConfigSchema, @@ -55,6 +65,7 @@ const protocolProviderConfigSchema = z.object({ bondEscalationModule: addressSchema, horizonAccountingExtension: addressSchema, }), + accessControl: accessControlSchema.optional(), }); const blockNumberServiceSchema = z.object({ 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 c0f42f6..1f306c1 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); @@ -103,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/config.ts b/packages/automated-dispute/src/config.ts index 14d9f5c..5150f94 100644 --- a/packages/automated-dispute/src/config.ts +++ b/packages/automated-dispute/src/config.ts @@ -4,4 +4,8 @@ const ConfigSchema = z.object({ DISCORD_WEBHOOK: z.string().url().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..92a9d51 100644 --- a/packages/automated-dispute/src/providers/protocolProvider.ts +++ b/packages/automated-dispute/src/providers/protocolProvider.ts @@ -73,13 +73,22 @@ type ProtocolRpcConfig = { l2: RpcConfig; }; +type ProtocolProviderConfig = ProtocolRpcConfig & { + 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, @@ -113,16 +122,18 @@ 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 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 rpcConfig: ProtocolRpcConfig, + private readonly rpcConfig: ProtocolProviderConfig, contracts: ProtocolContractsAddresses, privateKey: Hex, + serviceProviderAddress: Address | undefined, private readonly logger: ILogger, blockNumberService?: BlockNumberService, ) { @@ -133,6 +144,8 @@ export class ProtocolProvider implements IProtocolProvider { this.l2ReadClient = this.createReadClient(rpcConfig.l2, l2Chain); this.l2WriteClient = this.createWriteClient(rpcConfig.l2, l2Chain, privateKey); this.blockNumberService = blockNumberService; + this.serviceProviderAddress = + serviceProviderAddress || privateKeyToAccount(privateKey).address; // Instantiate all the protocol contracts this.oracleContract = getContract({ @@ -197,6 +210,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/mocks/eboActor.mocks.ts b/packages/automated-dispute/tests/mocks/eboActor.mocks.ts index 06036cd..d9b6e55 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, ); 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 eb2023a..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 () => { @@ -51,8 +52,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 +78,17 @@ describe("ProtocolProvider", () => { transactionReceiptConfirmations: 1, }, }; + const mockDerivedAddress = "0xDerivedAddressFromPrivateKey" as Address; + + const mockRpcConfigWithServiceProvider = { + ...mockRpcConfigBase, + serviceProviderAddress: mockServiceProviderAddress, + }; + + const mockRpcConfigWithoutServiceProvider = { + ...mockRpcConfigBase, + // accessControl is omitted to simulate derivation from PROTOCOL_PROVIDER_PRIVATE_KEY + }; const mockContractAddress: ProtocolContractsAddresses = { oracle: "0x1234567890123456789012345678901234567890", @@ -82,6 +103,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 +177,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 +207,7 @@ describe("ProtocolProvider", () => { describe("constructor", () => { it("creates a new ProtocolProvider instance successfully", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigWithoutServiceProvider, mockContractAddress, mockedPrivateKey, mockLogger(), @@ -181,7 +217,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 +229,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,9 +264,10 @@ describe("ProtocolProvider", () => { expect( () => new ProtocolProvider( - { ...mockRpcConfig, l1: { ...mockRpcConfig.l1, urls: [] } }, + { ...mockRpcConfigBase, l1: { ...mockRpcConfigBase.l1, urls: [] } }, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ), @@ -241,9 +278,10 @@ describe("ProtocolProvider", () => { expect( () => new ProtocolProvider( - { ...mockRpcConfig, l2: { ...mockRpcConfig.l2, urls: [] } }, + { ...mockRpcConfigBase, l2: { ...mockRpcConfigBase.l2, urls: [] } }, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ), @@ -268,9 +306,10 @@ describe("ProtocolProvider", () => { } as unknown as BlockNumberService; const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -295,13 +334,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,9 +354,10 @@ describe("ProtocolProvider", () => { it("throws when current epoch request fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -336,9 +376,10 @@ describe("ProtocolProvider", () => { it("throws when current epoch block request fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -364,9 +405,10 @@ describe("ProtocolProvider", () => { describe("proposeResponse", () => { it("successfully proposes a response", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -381,9 +423,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -402,9 +445,10 @@ describe("ProtocolProvider", () => { it("throws when transaction couldn't be confirmed", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -423,9 +467,10 @@ describe("ProtocolProvider", () => { it("throws ContractFunctionRevertedError when viem throws it", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -447,9 +492,10 @@ describe("ProtocolProvider", () => { it("throws WaitForTransactionReceiptTimeoutError when waitForTransactionReceipt times out", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -470,9 +516,10 @@ describe("ProtocolProvider", () => { describe("disputeResponse", () => { it("successfully disputes a response", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -492,9 +539,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -520,9 +568,10 @@ describe("ProtocolProvider", () => { describe("escalateDispute", () => { it("successfully escalates a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -542,9 +591,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -580,9 +630,10 @@ describe("ProtocolProvider", () => { describe("finalize", () => { it("successfully finalizes a request", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -597,9 +648,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -620,9 +672,10 @@ describe("ProtocolProvider", () => { describe("createRequest", () => { it("creates a request successfully", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -657,24 +710,24 @@ describe("ProtocolProvider", () => { describe("getAccountAddress", () => { it("returns the correct account address", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, 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, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -689,9 +742,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -712,9 +766,10 @@ describe("ProtocolProvider", () => { describe("pledgeAgainstDispute", () => { it("successfully pledges against a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -732,9 +787,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -758,9 +814,10 @@ describe("ProtocolProvider", () => { describe("settleDispute", () => { it("successfully settles a dispute", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -780,9 +837,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -808,9 +866,10 @@ describe("ProtocolProvider", () => { describe("approveModule", () => { it("successfully approves a module", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -837,9 +896,10 @@ describe("ProtocolProvider", () => { it("throws TransactionExecutionError when transaction fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -859,9 +919,10 @@ describe("ProtocolProvider", () => { describe("approvedModules", () => { it("successfully retrieves approved modules for a user", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -886,9 +947,10 @@ describe("ProtocolProvider", () => { it("uses private key account as default", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -911,9 +973,10 @@ describe("ProtocolProvider", () => { it("throws error when RPC client fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -934,9 +997,10 @@ describe("ProtocolProvider", () => { describe("getOracleEvents", () => { it("successfully fetches and parses Oracle events", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1004,9 +1068,10 @@ describe("ProtocolProvider", () => { const request = DEFAULT_MOCKED_REQUEST_CREATED_DATA; const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1155,9 +1220,10 @@ describe("ProtocolProvider", () => { describe("getAvailableChains", () => { it("successfully retrieves available chains", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1183,9 +1249,10 @@ describe("ProtocolProvider", () => { it("returns an empty array if no chains are allowed", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1204,9 +1271,10 @@ describe("ProtocolProvider", () => { it("throws FetchAvailableChainsError when RPC call fails", async () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1224,9 +1292,10 @@ describe("ProtocolProvider", () => { describe("getAccountingModuleAddress", () => { it("returns the correct accounting module address", () => { const protocolProvider = new ProtocolProvider( - mockRpcConfig, + mockRpcConfigBase, mockContractAddress, mockedPrivateKey, + mockServiceProviderAddress, mockLogger(), mockBlockNumberService, ); @@ -1236,4 +1305,32 @@ describe("ProtocolProvider", () => { ); }); }); + + describe("Service Provider Address", () => { + it("uses the provided serviceProviderAddress from config", () => { + const protocolProvider = new ProtocolProvider( + mockRpcConfigWithServiceProvider, + mockContractAddress, + mockedPrivateKey, + mockServiceProviderAddress, + mockLogger(), + mockBlockNumberService, + ); + + expect(protocolProvider.getServiceProviderAddress()).toBe(mockServiceProviderAddress); + }); + + it("derives serviceProviderAddress from PROTOCOL_PROVIDER_PRIVATE_KEY when not provided in config", () => { + const protocolProvider = new ProtocolProvider( + mockRpcConfigWithoutServiceProvider, + mockContractAddress, + mockedPrivateKey, + undefined, + mockLogger(), + mockBlockNumberService, + ); + + expect(protocolProvider.getServiceProviderAddress()).toBe(mockDerivedAddress); + }); + }); }); 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]>;