From 3ac079173a1e0b0261bd01d4aa9e23050f27fcdc Mon Sep 17 00:00:00 2001 From: mfw78 Date: Tue, 23 Jan 2024 12:40:42 +0000 Subject: [PATCH] refactor: modular architecture --- src/commands/dumpDb.ts | 3 ++- src/commands/run.ts | 4 ++-- src/domain/{addContract.ts => events/index.ts} | 6 +++--- src/domain/index.ts | 3 ++- .../polling/filtering/badOrder.ts} | 11 ++++++++--- src/domain/polling/filtering/index.ts | 2 ++ .../polling/filtering/policy.ts} | 2 +- .../index.ts} | 17 ++++++++--------- src/{utils => domain/polling}/poll.ts | 2 +- src/{utils => services}/api.ts | 5 ++--- .../chainContext.ts => services/chain.ts} | 12 ++++++------ src/services/index.ts | 7 +++++++ src/{utils/db.ts => services/storage.ts} | 2 +- src/types/model.ts | 3 ++- src/utils/context.ts | 2 +- src/utils/index.ts | 3 --- 16 files changed, 48 insertions(+), 36 deletions(-) rename src/domain/{addContract.ts => events/index.ts} (98%) rename src/{utils/filterOrder.ts => domain/polling/filtering/badOrder.ts} (79%) create mode 100644 src/domain/polling/filtering/index.ts rename src/{utils/filterPolicy.ts => domain/polling/filtering/policy.ts} (95%) rename src/domain/{checkForAndPlaceOrder.ts => polling/index.ts} (98%) rename src/{utils => domain/polling}/poll.ts (95%) rename src/{utils => services}/api.ts (96%) rename src/{domain/chainContext.ts => services/chain.ts} (98%) create mode 100644 src/services/index.ts rename src/{utils/db.ts => services/storage.ts} (95%) diff --git a/src/commands/dumpDb.ts b/src/commands/dumpDb.ts index e6b4afd..5f67f7c 100644 --- a/src/commands/dumpDb.ts +++ b/src/commands/dumpDb.ts @@ -1,5 +1,6 @@ import { DumpDbOptions, Registry } from "../types"; -import { DBService, getLogger } from "../utils"; +import { DBService } from "../services"; +import { getLogger } from "../utils"; /** * Dump the database as JSON to STDOUT for a given chain ID diff --git a/src/commands/run.ts b/src/commands/run.ts index b3fad34..0ad7745 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -1,6 +1,6 @@ import { RunOptions } from "../types"; -import { getLogger, DBService, ApiService } from "../utils"; -import { ChainContext } from "../domain"; +import { getLogger } from "../utils"; +import { DBService, ApiService, ChainContext } from "../services"; /** * Run the watch-tower 👀🐮 diff --git a/src/domain/addContract.ts b/src/domain/events/index.ts similarity index 98% rename from src/domain/addContract.ts rename to src/domain/events/index.ts index a2d8773..c6c8c33 100644 --- a/src/domain/addContract.ts +++ b/src/domain/events/index.ts @@ -4,7 +4,7 @@ import { handleExecutionError, isComposableCowCompatible, metrics, -} from "../utils"; +} from "../../utils"; import { BytesLike, ethers } from "ethers"; import { @@ -17,9 +17,9 @@ import { Owner, Proof, Registry, -} from "../types"; +} from "../../types"; -import { ChainContext } from "./chainContext"; +import { ChainContext } from "../../services/chain"; import { ConditionalOrderParams } from "@cowprotocol/cow-sdk"; /** diff --git a/src/domain/index.ts b/src/domain/index.ts index 340b139..21b0ef9 100644 --- a/src/domain/index.ts +++ b/src/domain/index.ts @@ -1 +1,2 @@ -export * from "./chainContext"; +export * as events from "./events"; +export * as polling from "./polling"; diff --git a/src/utils/filterOrder.ts b/src/domain/polling/filtering/badOrder.ts similarity index 79% rename from src/utils/filterOrder.ts rename to src/domain/polling/filtering/badOrder.ts index 1053b0e..6ccbb0c 100644 --- a/src/utils/filterOrder.ts +++ b/src/domain/polling/filtering/badOrder.ts @@ -1,12 +1,14 @@ import { Order } from "@cowprotocol/contracts"; import { BigNumber, ethers } from "ethers"; +const MINIMUM_VALIDITY_SECONDS = 60; + /** * Process an order to determine if it is valid * @param order The GPv2.Order data struct to validate * @throws Error if the order is invalid */ -export function validateOrder(order: Order) { +export function check(order: Order) { // amounts must be non-zero if (BigNumber.from(order.sellAmount).isZero()) { throw new Error("Order has zero sell amount"); @@ -30,8 +32,11 @@ export function validateOrder(order: Order) { throw new Error("Order has identical sell and buy token addresses"); } - // Check to make sure that the order has at least 120s of validity - if (Math.floor(Date.now() / 1000) + 60 > Number(order.validTo)) { + // Check to make sure that the order has at least a specified validity + if ( + Math.floor(Date.now() / 1000) + MINIMUM_VALIDITY_SECONDS > + Number(order.validTo) + ) { throw new Error("Order expires too soon"); } } diff --git a/src/domain/polling/filtering/index.ts b/src/domain/polling/filtering/index.ts new file mode 100644 index 0000000..6ed09dc --- /dev/null +++ b/src/domain/polling/filtering/index.ts @@ -0,0 +1,2 @@ +export * as badOrder from "./badOrder"; +export * as policy from "./policy"; diff --git a/src/utils/filterPolicy.ts b/src/domain/polling/filtering/policy.ts similarity index 95% rename from src/utils/filterPolicy.ts rename to src/domain/polling/filtering/policy.ts index b4be38a..d0fe2b7 100644 --- a/src/utils/filterPolicy.ts +++ b/src/domain/polling/filtering/policy.ts @@ -1,5 +1,5 @@ import { ConditionalOrderParams } from "@cowprotocol/cow-sdk"; -import { Config, FilterAction as FilterActionSchema } from "../types"; +import { Config, FilterAction as FilterActionSchema } from "../../../types"; export enum FilterAction { DROP = "DROP", diff --git a/src/domain/checkForAndPlaceOrder.ts b/src/domain/polling/index.ts similarity index 98% rename from src/domain/checkForAndPlaceOrder.ts rename to src/domain/polling/index.ts index fcdb32b..7eccd30 100644 --- a/src/domain/checkForAndPlaceOrder.ts +++ b/src/domain/polling/index.ts @@ -8,14 +8,13 @@ import { import { ethers } from "ethers"; import { BytesLike } from "ethers/lib/utils"; -import { ConditionalOrder, OrderStatus } from "../types"; +import { ConditionalOrder, OrderStatus } from "../../types"; import { formatStatus, getLogger, - pollConditionalOrder, handleOnChainCustomError, metrics, -} from "../utils"; +} from "../../utils"; import { ConditionalOrder as ConditionalOrderSDK, OrderBookApi, @@ -30,9 +29,9 @@ import { SupportedChainId, formatEpoch, } from "@cowprotocol/cow-sdk"; -import { ChainContext, SDK_BACKOFF_NUM_OF_ATTEMPTS } from "./chainContext"; -import { FilterAction } from "../utils/filterPolicy"; -import { validateOrder } from "../utils/filterOrder"; +import { ChainContext, SDK_BACKOFF_NUM_OF_ATTEMPTS } from "../../services"; +import { badOrder, policy } from "./filtering"; +import { pollConditionalOrder } from "./poll"; const GPV2SETTLEMENT = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41"; @@ -125,12 +124,12 @@ export async function checkForAndPlaceOrder( }); switch (filterResult) { - case FilterAction.DROP: + case policy.FilterAction.DROP: log.debug("Dropping conditional order. Reason: AcceptPolicy: DROP"); ordersPendingDelete.push(conditionalOrder); continue; - case FilterAction.SKIP: + case policy.FilterAction.SKIP: log.debug("Skipping conditional order. Reason: AcceptPolicy: SKIP"); continue; } @@ -337,7 +336,7 @@ async function _processConditionalOrder( // We now have the order, so we can validate it. This will throw if the order is invalid // and we will catch it below. - validateOrder(orderToSubmit); + badOrder.check(orderToSubmit); // calculate the orderUid const orderUid = _getOrderUid(chainId, orderToSubmit, owner); diff --git a/src/utils/poll.ts b/src/domain/polling/poll.ts similarity index 95% rename from src/utils/poll.ts rename to src/domain/polling/poll.ts index b3be63e..36b0384 100644 --- a/src/utils/poll.ts +++ b/src/domain/polling/poll.ts @@ -5,7 +5,7 @@ import { PollParams, PollResult, } from "@cowprotocol/cow-sdk"; -import { getLogger } from "./logging"; +import { getLogger } from "../../utils/logging"; // Watch-tower will index every block, so we will by default the processing block and not the latest. const POLL_FROM_LATEST_BLOCK = false; diff --git a/src/utils/api.ts b/src/services/api.ts similarity index 96% rename from src/utils/api.ts rename to src/services/api.ts index e6fd1b8..1d5b47e 100644 --- a/src/utils/api.ts +++ b/src/services/api.ts @@ -2,11 +2,10 @@ import { Server } from "http"; import express, { Request, Response, Router } from "express"; import { Express } from "express-serve-static-core"; import * as client from "prom-client"; -import { getLogger } from "./logging"; -import { DBService } from "./db"; +import { getLogger } from "../utils/logging"; +import { DBService, ChainContext } from "../services"; import { Registry } from "../types"; import { version, name, description } from "../../package.json"; -import { ChainContext } from "../domain"; export class ApiService { protected port: number; diff --git a/src/domain/chainContext.ts b/src/services/chain.ts similarity index 98% rename from src/domain/chainContext.ts rename to src/services/chain.ts index c4cdcf7..0aa504f 100644 --- a/src/domain/chainContext.ts +++ b/src/services/chain.ts @@ -14,18 +14,18 @@ import { OrderBookApi, ApiBaseUrls, } from "@cowprotocol/cow-sdk"; -import { addContract } from "./addContract"; -import { checkForAndPlaceOrder } from "./checkForAndPlaceOrder"; +import { addContract } from "../domain/events"; +import { checkForAndPlaceOrder } from "../domain/polling"; import { EventFilter, providers } from "ethers"; import { composableCowContract, - DBService, getLogger, isRunningInKubernetesPod, metrics, } from "../utils"; +import { DBService } from "."; import { hexZeroPad } from "ethers/lib/utils"; -import { FilterPolicy } from "../utils/filterPolicy"; +import { policy } from "../domain/polling/filtering"; const WATCHDOG_FREQUENCY_SECS = 5; // 5 seconds const WATCHDOG_TIMEOUT_DEFAULT_SECS = 30; @@ -86,7 +86,7 @@ export class ChainContext { chainId: SupportedChainId; registry: Registry; orderBook: OrderBookApi; - filterPolicy: FilterPolicy | undefined; + filterPolicy: policy.FilterPolicy | undefined; contract: ComposableCoW; multicall: Multicall3; @@ -129,7 +129,7 @@ export class ChainContext { }, }); - this.filterPolicy = new FilterPolicy(filterPolicy); + this.filterPolicy = new policy.FilterPolicy(filterPolicy); this.contract = composableCowContract(this.provider, this.chainId); this.multicall = Multicall3__factory.connect(MULTICALL3, this.provider); } diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..413687c --- /dev/null +++ b/src/services/index.ts @@ -0,0 +1,7 @@ +import { DBService } from "./storage"; +import { ApiService } from "./api"; +import { ChainContext, SDK_BACKOFF_NUM_OF_ATTEMPTS } from "./chain"; + +// Exporting the `SDK_BACKOFF_NUM_OF_ATTEMPTS` is a smell that can be eliminated +// when upstream (`cow-sdk`) allows passing instantiated `OrderBookApi` for `.poll`. +export { DBService, ApiService, ChainContext, SDK_BACKOFF_NUM_OF_ATTEMPTS }; diff --git a/src/utils/db.ts b/src/services/storage.ts similarity index 95% rename from src/utils/db.ts rename to src/services/storage.ts index f5d0288..b0744fa 100644 --- a/src/utils/db.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { DatabaseOptions, Level } from "level"; -import { getLogger } from "./logging"; +import { getLogger } from "../utils/logging"; const DEFAULT_DB_LOCATION = "./database"; diff --git a/src/types/model.ts b/src/types/model.ts index cc7b94b..c31228e 100644 --- a/src/types/model.ts +++ b/src/types/model.ts @@ -4,7 +4,8 @@ import { BytesLike, ethers } from "ethers"; import type { ConditionalOrderCreatedEvent } from "./generated/ComposableCoW"; import { ConditionalOrderParams, PollResult } from "@cowprotocol/cow-sdk"; -import { DBService, metrics } from "../utils"; +import { DBService } from "../services"; +import { metrics } from "../utils"; // Standardise the storage key const LAST_NOTIFIED_ERROR_STORAGE_KEY = "LAST_NOTIFIED_ERROR"; diff --git a/src/utils/context.ts b/src/utils/context.ts index b48efe6..a094229 100644 --- a/src/utils/context.ts +++ b/src/utils/context.ts @@ -1,5 +1,5 @@ import Slack = require("node-slack"); -import { DBService } from "./db"; +import { DBService } from "../services"; import { ContextOptions, ExecutionContext, Registry } from "../types"; import { SupportedChainId } from "@cowprotocol/cow-sdk"; diff --git a/src/utils/index.ts b/src/utils/index.ts index c5fbd7c..b263022 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,8 +1,5 @@ export * from "./context"; export * from "./contracts"; -export * from "./poll"; export * from "./misc"; -export * from "./db"; export * from "./logging"; -export * from "./api"; export * as metrics from "./metrics";