diff --git a/src/relayer/RelayerClientHelper.ts b/src/relayer/RelayerClientHelper.ts index d12f4845f..6061cc6f1 100644 --- a/src/relayer/RelayerClientHelper.ts +++ b/src/relayer/RelayerClientHelper.ts @@ -1,4 +1,4 @@ -import { utils as sdkUtils } from "@across-protocol/sdk-v2"; +import { typeguards, utils as sdkUtils } from "@across-protocol/sdk-v2"; import winston from "winston"; import { AcrossApiClient, BundleDataClient, InventoryClient, ProfitClient, TokenClient } from "../clients"; import { AdapterManager, CrossChainTransferClient } from "../clients/bridges"; @@ -11,7 +11,7 @@ import { updateSpokePoolClients, } from "../common"; import { SpokePoolClientsByChain } from "../interfaces"; -import { Signer } from "../utils"; +import { isDefined, readFile, Signer } from "../utils"; import { RelayerConfig } from "./RelayerConfig"; export interface RelayerClients extends Clients { @@ -107,12 +107,31 @@ export async function constructRelayerClients( configStoreClient.getChainIdIndicesForBlock(), config.blockRangeEndBlockBuffer ); + const crossChainAdapterSupportedChains = adapterManager.supportedChains(); const crossChainTransferClient = new CrossChainTransferClient( logger, enabledChainIds.filter((chainId) => crossChainAdapterSupportedChains.includes(chainId)), adapterManager ); + + // If an external inventory configuration was defined, read it in now before instantiating the InventoryClient. + if (isDefined(config.externalInventoryConfig)) { + const _inventoryConfig = await readFile(config.externalInventoryConfig); + try { + config.inventoryConfig = JSON.parse(_inventoryConfig); + } catch (err) { + const msg = typeguards.isError(err) ? err.message : (err as Record)?.code; + throw new Error(`Inventory config error in ${config.externalInventoryConfig} (${msg ?? "unknown error"})`); + } + logger.debug({ + at: "Relayer#constructRelayerClients", + message: "Updated Inventory config.", + source: config.externalInventoryConfig, + inventoryConfig: config.inventoryConfig, + }); + } + const inventoryClient = new InventoryClient( signerAddr, logger, diff --git a/src/relayer/RelayerConfig.ts b/src/relayer/RelayerConfig.ts index 4432de29b..7f4eccb20 100644 --- a/src/relayer/RelayerConfig.ts +++ b/src/relayer/RelayerConfig.ts @@ -1,10 +1,12 @@ -import { BigNumber, toBNWei, assert, toBN, replaceAddressCase, ethers } from "../utils"; +import { BigNumber, toBNWei, assert, isDefined, toBN, replaceAddressCase, ethers } from "../utils"; import { CommonConfig, ProcessEnv } from "../common"; import * as Constants from "../common/Constants"; import { InventoryConfig } from "../interfaces"; export class RelayerConfig extends CommonConfig { - readonly inventoryConfig: InventoryConfig; + readonly externalInventoryConfig?: string; + inventoryConfig: InventoryConfig; + readonly debugProfitability: boolean; // Whether token price fetch failures will be ignored when computing relay profitability. // If this is false, the relayer will throw an error when fetching prices fails. @@ -41,6 +43,7 @@ export class RelayerConfig extends CommonConfig { RELAYER_GAS_MESSAGE_MULTIPLIER, RELAYER_GAS_MULTIPLIER, RELAYER_GAS_PADDING, + RELAYER_EXTERNAL_INVENTORY_CONFIG, RELAYER_INVENTORY_CONFIG, RELAYER_TOKENS, SEND_RELAYS, @@ -67,7 +70,14 @@ export class RelayerConfig extends CommonConfig { this.slowDepositors = SLOW_DEPOSITORS ? JSON.parse(SLOW_DEPOSITORS).map((depositor) => ethers.utils.getAddress(depositor)) : []; - this.inventoryConfig = RELAYER_INVENTORY_CONFIG ? JSON.parse(RELAYER_INVENTORY_CONFIG) : {}; + + assert( + !isDefined(RELAYER_EXTERNAL_INVENTORY_CONFIG) || !isDefined(RELAYER_INVENTORY_CONFIG), + "Concurrent inventory management configurations detected." + ); + this.externalInventoryConfig = RELAYER_EXTERNAL_INVENTORY_CONFIG; + this.inventoryConfig = JSON.parse(RELAYER_INVENTORY_CONFIG ?? "{}"); + this.minRelayerFeePct = toBNWei(MIN_RELAYER_FEE_PCT || Constants.RELAYER_MIN_FEE_PCT); if (Object.keys(this.inventoryConfig).length > 0) { diff --git a/src/utils/fsUtils.ts b/src/utils/fsUtils.ts new file mode 100644 index 000000000..64cf99c16 --- /dev/null +++ b/src/utils/fsUtils.ts @@ -0,0 +1,12 @@ +import * as fs from "fs/promises"; +import { typeguards } from "@across-protocol/sdk-v2"; + +export async function readFile(fileName: string): Promise { + try { + return await fs.readFile(fileName, { encoding: "utf8" }); + } catch (err) { + // @dev fs methods can return errors that are not Error objects (i.e. errno). + const msg = typeguards.isError(err) ? err.message : (err as Record)?.code; + throw new Error(`Unable to read ${fileName} (${msg ?? "unknown error"})`); + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 5f9e5c1ca..93c815f2d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -49,6 +49,7 @@ export { // Utils specifically for this bot. export * from "./SDKUtils"; export * from "./chains"; +export * from "./fsUtils"; export * from "./ProviderUtils"; export * from "./SignerUtils"; export * from "./DepositUtils";