diff --git a/config.example.yaml b/config.example.yaml index f3db1b3..068d17c 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -21,10 +21,12 @@ global: # Evaluation properties evaluationRetryInterval: 3600000 # Interval at which to reevaluate whether to relay a message. maxEvaluationDuration: 86400000 # Time after which to drop an undelivered message. - unrewardedDeliveryGas: '100000' # Gas amount that will be unrewarded on delivery submission. + verificationDeliveryGas: '55000' # Gas amount used for packet verification upon delivery. + unrewardedDeliveryGas: '25000' # Gas amount that will be unrewarded on delivery submission. minDeliveryReward: 0.001 # In the 'pricingDenomination' specified below relativeMinDeliveryReward: 0.001 - unrewardedAckGas: '50000' # Gas amount that will be unrewarded on ack submission. + verificationAckGas: '55000' # Gas amount used for packet verification upon ack. + unrewardedAckGas: '25000' # Gas amount that will be unrewarded on ack submission. minAckReward: 0.001 # In the 'pricingDenomination' specified below relativeMinAckReward: 0.001 profitabilityFactor: 1.0 # Profitiability evaluation adjustment factor. A larger diff --git a/src/config/config.schema.ts b/src/config/config.schema.ts index 50256d7..0ae31b4 100644 --- a/src/config/config.schema.ts +++ b/src/config/config.schema.ts @@ -150,9 +150,11 @@ const SUBMITTER_SCHEMA = { evaluationRetryInterval: { $ref: "positive-number-schema" }, maxEvaluationDuration: { $ref: "positive-number-schema" }, unrewardedDeliveryGas: { $ref: "gas-field-schema" }, + verificationDeliveryGas: { $ref: "gas-field-schema" }, minDeliveryReward: { $ref: "positive-number-schema" }, relativeMinDeliveryReward: { $ref: "positive-number-schema" }, unrewardedAckGas: { $ref: "gas-field-schema" }, + verificationAckGas: { $ref: "gas-field-schema" }, minAckReward: { $ref: "positive-number-schema" }, relativeMinAckReward: { $ref: "positive-number-schema" }, profitabilityFactor: { $ref: "positive-number-schema" }, diff --git a/src/config/config.service.ts b/src/config/config.service.ts index a59dc96..8a1064e 100644 --- a/src/config/config.service.ts +++ b/src/config/config.service.ts @@ -191,9 +191,15 @@ export class ConfigService { if (config.unrewardedDeliveryGas != undefined) { config.unrewardedDeliveryGas = BigInt(config.unrewardedDeliveryGas); } + if (config.verificationDeliveryGas != undefined) { + config.verificationDeliveryGas = BigInt(config.verificationDeliveryGas); + } if (config.unrewardedAckGas != undefined) { config.unrewardedAckGas = BigInt(config.unrewardedAckGas); } + if (config.verificationAckGas != undefined) { + config.verificationAckGas = BigInt(config.verificationAckGas); + } return config as SubmitterGlobalConfig; } diff --git a/src/config/config.types.ts b/src/config/config.types.ts index b7c838e..7cca08a 100644 --- a/src/config/config.types.ts +++ b/src/config/config.types.ts @@ -48,9 +48,11 @@ export interface SubmitterGlobalConfig { evaluationRetryInterval?: number; maxEvaluationDuration?: number; unrewardedDeliveryGas?: bigint; + verificationDeliveryGas?: bigint; minDeliveryReward?: number; relativeMinDeliveryReward?: number; unrewardedAckGas?: bigint; + verificationAckGas?: bigint; minAckReward?: number; relativeMinAckReward?: number; profitabilityFactor?: number; diff --git a/src/submitter/queues/eval-queue.ts b/src/submitter/queues/eval-queue.ts index 42860af..08b8eb9 100644 --- a/src/submitter/queues/eval-queue.ts +++ b/src/submitter/queues/eval-queue.ts @@ -230,12 +230,10 @@ export class EvalQueue extends ProcessingQueue { bounty.priceOfDeliveryGas ); - // Consider the worst 'ack' submission loss, as in that case no one will desire to submit - // the 'ack', and this relayer will have to submit it in order to get the payment for the - // delivery. const maxAckLoss = this.calcMaxGasLoss( // ! In source chain gas value sourceGasPrice, this.evaluationConfig.unrewardedAckGas, + this.evaluationConfig.verificationAckGas, BigInt(bounty.maxGasAck), bounty.priceOfAckGas, ); @@ -248,7 +246,7 @@ export class EvalQueue extends ProcessingQueue { this.chainId ); - const correctedDeliveryReward = deliveryReward - maxAckLoss; + const correctedDeliveryReward = deliveryReward + maxAckLoss; const deliveryFiatReward = await this.getGasCostFiatPrice( correctedDeliveryReward, bounty.fromChainId @@ -399,24 +397,42 @@ export class EvalQueue extends ProcessingQueue { private calcMaxGasLoss( gasPrice: bigint, unrewardedGas: bigint, + verificationGas: bigint, bountyMaxGas: bigint, bountyPriceOfGas: bigint, ): bigint { - // Evaluate the worst possible loss of a submission. There are 2 possible scenarios: - // - The provided `bountyPriceOfGas` covers the current gas price: the worst loss - // will occur if no gas is used for the submission logic (and hence there is no bounty - // reward). - // - The provided `bountyPriceOfGas' does *not* cover the current gas price: the - // worst loss will occur if the maximum allowed amount of gas is used for the - // submission logic. - - const fixedCost = unrewardedGas * gasPrice; - - const worstCaseVariableCost = gasPrice > bountyPriceOfGas - ? bountyMaxGas * (gasPrice - bountyPriceOfGas) - : 0n; - return fixedCost + worstCaseVariableCost; + // The gas used for the 'ack' submission is composed of 3 amounts: + // - Logic overhead: is never computed for the reward. + // - Verification logic: is only computed for the reward if the source application's + // 'ack' handler does not use all of the 'ack' gas allowance ('bountyMaxGas'). + // - Source application's 'ack' handler: it is always computed for the reward (up to a + // maximum of 'bountyMaxGas'). + + // Evaluate the minimum expected profit from the 'ack' delivery. There are 2 possible + // scenarios: + // - No gas is used by the source application's 'ack' handler. + // - The maximum allowed amount of gas is used by the source application's 'ack' handler. + + // NOTE: strictly speaking, 'verificationGas' should be upperbounded by 'bountyMaxGas' on + // the following line. However, this is not necessary, as in such a case + // 'maximumGasUsageProfit' will always return a smaller profit than 'minimumGasUsageProfit'. + const minimumGasUsageReward = verificationGas * bountyPriceOfGas; + const minimumGasUsageCost = (unrewardedGas + verificationGas) * gasPrice; + const minimumGasUsageProfit = minimumGasUsageReward - minimumGasUsageCost; + + const maximumGasUsageReward = bountyMaxGas * bountyPriceOfGas; + const maximumGasUsageCost = (unrewardedGas + verificationGas + bountyMaxGas) * gasPrice; + const maximumGasUsageProfit = maximumGasUsageReward - maximumGasUsageCost; + + const worstCaseProfit = minimumGasUsageProfit < maximumGasUsageProfit + ? minimumGasUsageProfit + : maximumGasUsageProfit; + + // Only return the 'worstCaseProfit' if it's negative. + return worstCaseProfit < 0n + ? worstCaseProfit + : 0n; } private async getGasPrice(chainId: string): Promise { diff --git a/src/submitter/submitter.service.ts b/src/submitter/submitter.service.ts index 8b496c2..b3e07cd 100644 --- a/src/submitter/submitter.service.ts +++ b/src/submitter/submitter.service.ts @@ -18,9 +18,11 @@ const NEW_ORDERS_DELAY_DEFAULT = 0; const EVALUATION_RETRY_INTERVAL_DEFAULT = 60 * 60 * 1000; const MAX_EVALUATION_DURATION_DEFAULT = 24 * 60 * 60 * 1000; const UNREWARDED_DELIVERY_GAS_DEFAULT = 0n; +const VERIFICATION_DELIVERY_GAS_DEFAULT = 0n; const MIN_DELIVERY_REWARD_DEFAULT = 0; const RELATIVE_MIN_DELIVERY_REWARD_DEFAULT = 0; const UNREWARDED_ACK_GAS_DEFAULT = 0n; +const VERIFICATION_ACK_GAS_DEFAULT = 0n; const MIN_ACK_REWARD_DEFAULT = 0; const RELATIVE_MIN_ACK_REWARD_DEFAULT = 0; const PROFITABILITY_FACTOR_DEFAULT = 1; @@ -35,9 +37,11 @@ interface GlobalSubmitterConfig { evaluationRetryInterval: number; maxEvaluationDuration: number; unrewardedDeliveryGas: bigint; + verificationDeliveryGas: bigint; minDeliveryReward: number; relativeMinDeliveryReward: number; unrewardedAckGas: bigint; + verificationAckGas: bigint; minAckReward: number; relativeMinAckReward: number; profitabilityFactor: number; @@ -57,9 +61,11 @@ export interface SubmitterWorkerData { evaluationRetryInterval: number; maxEvaluationDuration: number; unrewardedDeliveryGas: bigint; + verificationDeliveryGas: bigint; minDeliveryReward: number; relativeMinDeliveryReward: number; unrewardedAckGas: bigint; + verificationAckGas: bigint; minAckReward: number; relativeMinAckReward: number; profitabilityFactor: number; @@ -147,12 +153,16 @@ export class SubmitterService { submitterConfig.maxEvaluationDuration ?? MAX_EVALUATION_DURATION_DEFAULT; const unrewardedDeliveryGas = submitterConfig.unrewardedDeliveryGas ?? UNREWARDED_DELIVERY_GAS_DEFAULT; + const verificationDeliveryGas = + submitterConfig.verificationDeliveryGas ?? VERIFICATION_DELIVERY_GAS_DEFAULT; const minDeliveryReward = submitterConfig.minDeliveryReward ?? MIN_DELIVERY_REWARD_DEFAULT; const relativeMinDeliveryReward = submitterConfig.relativeMinDeliveryReward ?? RELATIVE_MIN_DELIVERY_REWARD_DEFAULT; const unrewardedAckGas = submitterConfig.unrewardedAckGas ?? UNREWARDED_ACK_GAS_DEFAULT; + const verificationAckGas = + submitterConfig.verificationAckGas ?? VERIFICATION_ACK_GAS_DEFAULT; const minAckReward = submitterConfig.minAckReward ?? MIN_ACK_REWARD_DEFAULT; const relativeMinAckReward = @@ -173,9 +183,11 @@ export class SubmitterService { evaluationRetryInterval, maxEvaluationDuration, unrewardedDeliveryGas, + verificationDeliveryGas, minDeliveryReward, relativeMinDeliveryReward, unrewardedAckGas, + verificationAckGas, minAckReward, relativeMinAckReward, profitabilityFactor, @@ -230,6 +242,10 @@ export class SubmitterService { unrewardedDeliveryGas: chainConfig.submitter.unrewardedDeliveryGas ?? globalConfig.unrewardedDeliveryGas, + + verificationDeliveryGas: + chainConfig.submitter.verificationDeliveryGas ?? + globalConfig.verificationDeliveryGas, maxEvaluationDuration: chainConfig.submitter.maxEvaluationDuration ?? @@ -246,6 +262,10 @@ export class SubmitterService { unrewardedAckGas: chainConfig.submitter.unrewardedAckGas ?? globalConfig.unrewardedAckGas, + + verificationAckGas: + chainConfig.submitter.verificationAckGas ?? + globalConfig.verificationAckGas, minAckReward: chainConfig.submitter.minAckReward ?? diff --git a/src/submitter/submitter.types.ts b/src/submitter/submitter.types.ts index 4359c2e..51e7188 100644 --- a/src/submitter/submitter.types.ts +++ b/src/submitter/submitter.types.ts @@ -36,9 +36,11 @@ export interface BountyEvaluationConfig { evaluationRetryInterval: number, maxEvaluationDuration: number, unrewardedDeliveryGas: bigint; + verificationDeliveryGas: bigint; minDeliveryReward: number; relativeMinDeliveryReward: number, unrewardedAckGas: bigint; + verificationAckGas: bigint; minAckReward: number; relativeMinAckReward: number; profitabilityFactor: number; diff --git a/src/submitter/submitter.worker.ts b/src/submitter/submitter.worker.ts index c4f0a7f..2f7057b 100644 --- a/src/submitter/submitter.worker.ts +++ b/src/submitter/submitter.worker.ts @@ -68,9 +68,11 @@ class SubmitterWorker { evaluationRetryInterval: this.config.evaluationRetryInterval, maxEvaluationDuration: this.config.maxEvaluationDuration, unrewardedDeliveryGas: this.config.unrewardedDeliveryGas, + verificationDeliveryGas: this.config.verificationDeliveryGas, minDeliveryReward: this.config.minDeliveryReward, relativeMinDeliveryReward: this.config.relativeMinDeliveryReward, unrewardedAckGas: this.config.unrewardedAckGas, + verificationAckGas: this.config.verificationAckGas, minAckReward: this.config.minAckReward, relativeMinAckReward: this.config.relativeMinAckReward, profitabilityFactor: this.config.profitabilityFactor,