diff --git a/src/clients/ProfitClient.ts b/src/clients/ProfitClient.ts index 3b9ff5418d..18e18fd653 100644 --- a/src/clients/ProfitClient.ts +++ b/src/clients/ProfitClient.ts @@ -113,6 +113,7 @@ export class ProfitClient { private relayerFeeQueries: { [chainId: number]: relayFeeCalculator.QueryInterface } = {}; private readonly isTestnet: boolean; + private readonly auxNativeTokenCostCaps: { [chainId: number]: BigNumber } = {}; // @todo: Consolidate this set of args before it grows legs and runs away from us. constructor( @@ -164,6 +165,8 @@ export class ProfitClient { } this.isTestnet = this.hubPoolClient.chainId !== CHAIN_IDs.MAINNET; + + this.configureAuxNativeLimits(); } resolveGasMultiplier(deposit: Deposit): BigNumber { @@ -570,12 +573,29 @@ export class ProfitClient { let tokenGasCost = uint256Max; let gasPrice = uint256Max; try { - ({ profitable, netRelayerFeePct, nativeGasCost, tokenGasCost, gasPrice } = await this.getFillProfitability( - deposit, - lpFeePct, - l1Token, - repaymentChainId - )); + let auxNativeTokenCostUsd = uint256Max; + ({ + profitable, + netRelayerFeePct, + nativeGasCost, + tokenGasCost, + gasPrice, + auxiliaryNativeTokenCostUsd: auxNativeTokenCostUsd, + } = await this.getFillProfitability(deposit, lpFeePct, l1Token, repaymentChainId)); + + // If a deposit wants us to forward more native token than a configured limit, mark it unprofitable + const cap = this.auxNativeTokenCostCaps[deposit.destinationChainId]; + if (auxNativeTokenCostUsd.gt(cap)) { + this.logger.debug({ + at: "ProfitClient#isFillProfitable", + message: "Marking fill unprofitable: aux native token cost too large.", + costUsd: `$${formatEther(auxNativeTokenCostUsd)}`, + capUsd: `$${formatEther(cap)}`, + deposit: convertRelayDataParamsToBytes32(deposit), + lpFeePct, + }); + profitable = false; + } } catch (err) { this.logger.debug({ at: "ProfitClient#isFillProfitable", @@ -831,4 +851,23 @@ export class ProfitClient { this.logger ); } + + private configureAuxNativeLimits() { + const maxAuxNativeUsdDefault = + this.resolveAuxNativeUsd(process.env.RELAYER_MAX_AUX_NATIVE_USD) ?? + toBNWei(constants.DEFAULT_RELAYER_MAX_AUX_NATIVE_USD); + this.enabledChainIds.forEach((chainId) => { + const override = this.resolveAuxNativeUsd(process.env[`RELAYER_MAX_AUX_NATIVE_USD_${chainId}`]); + this.auxNativeTokenCostCaps[chainId] = override ?? maxAuxNativeUsdDefault; + }); + } + + private resolveAuxNativeUsd(value?: string): BigNumber | undefined { + if (!isDefined(value)) { + return undefined; + } + const numeric = Number(value); + assert(!Number.isNaN(numeric) && numeric >= 0, "RELAYER_MAX_AUX_NATIVE_USD must be a non-negative number"); + return toBNWei(value); + } } diff --git a/src/common/Constants.ts b/src/common/Constants.ts index 0bd1493f9c..a8eb86dd49 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -236,6 +236,8 @@ export const BUNDLE_END_BLOCK_BUFFERS = { export const DEFAULT_RELAYER_GAS_PADDING = ".15"; // Padding on token- and message-based relayer fill gas estimates. export const DEFAULT_RELAYER_GAS_MULTIPLIER = "1.0"; // Multiplier on pre-profitability token-only gas estimates. export const DEFAULT_RELAYER_GAS_MESSAGE_MULTIPLIER = "1.0"; // Multiplier on pre-profitability message fill gas estimates. +// Maximum value of native token we're willing to forward to user beyond amountOut, in USD +export const DEFAULT_RELAYER_MAX_AUX_NATIVE_USD = "2.0"; export const DEFAULT_MULTICALL_CHUNK_SIZE = 50;