@@ -134,9 +134,13 @@ pub struct EthereumConfig {
134134 /// The gas limit to use for entropy callback transactions.
135135 pub gas_limit : u64 ,
136136
137- /// The percentage multiplier to apply to the gas limit for each backoff.
138- #[ serde( default = "default_backoff_gas_multiplier_pct" ) ]
139- pub backoff_gas_multiplier_pct : u64 ,
137+ /// The percentage multiplier to apply to priority fee estimates (100 = no change, e.g. 150 = 150% of base fee)
138+ #[ serde( default = "default_priority_fee_multiplier_pct" ) ]
139+ pub priority_fee_multiplier_pct : u64 ,
140+
141+ /// The escalation policy governs how the gas limit and fee are increased during backoff retries.
142+ #[ serde( default ) ]
143+ pub escalation_policy : EscalationPolicyConfig ,
140144
141145 /// The minimum percentage profit to earn as a function of the callback cost.
142146 /// For example, 20 means a profit of 20% over the cost of the callback.
@@ -170,16 +174,104 @@ pub struct EthereumConfig {
170174 /// Maximum number of hashes to record in a request.
171175 /// This should be set according to the maximum gas limit the provider supports for callbacks.
172176 pub max_num_hashes : Option < u32 > ,
173-
174- /// The percentage multiplier to apply to the priority fee (100 = no change, e.g. 150 = 150% of base fee)
175- #[ serde( default = "default_priority_fee_multiplier_pct" ) ]
176- pub priority_fee_multiplier_pct : u64 ,
177177}
178178
179- fn default_backoff_gas_multiplier_pct ( ) -> u64 {
179+ fn default_priority_fee_multiplier_pct ( ) -> u64 {
180180 100
181181}
182182
183+ #[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
184+ pub struct EscalationPolicyConfig {
185+ /// The initial gas multiplier to apply to the gas limit.
186+ #[ serde( default = "default_initial_gas_multiplier_pct" ) ]
187+ pub initial_gas_multiplier_pct : u64 ,
188+
189+ /// The gas multiplier to apply to the gas limit during backoff retries.
190+ /// The gas on each successive retry is multiplied by this value, with the maximum multiplier capped at `gas_multiplier_cap_pct`.
191+ #[ serde( default = "default_gas_multiplier_pct" ) ]
192+ pub gas_multiplier_pct : u64 ,
193+ /// The maximum gas multiplier to apply to the gas limit during backoff retries.
194+ #[ serde( default = "default_gas_multiplier_cap_pct" ) ]
195+ pub gas_multiplier_cap_pct : u64 ,
196+
197+ /// The fee multiplier to apply to the fee during backoff retries.
198+ /// The initial fee is 100% of the estimate (which itself may be padded based on our chain configuration)
199+ /// The fee on each successive retry is multiplied by this value, with the maximum multiplier capped at `fee_multiplier_cap_pct`.
200+ #[ serde( default = "default_fee_multiplier_pct" ) ]
201+ pub fee_multiplier_pct : u64 ,
202+ #[ serde( default = "default_fee_multiplier_cap_pct" ) ]
203+ pub fee_multiplier_cap_pct : u64 ,
204+ }
205+
206+ fn default_initial_gas_multiplier_pct ( ) -> u64 {
207+ 125
208+ }
209+
210+ fn default_gas_multiplier_pct ( ) -> u64 {
211+ 110
212+ }
213+
214+ fn default_gas_multiplier_cap_pct ( ) -> u64 {
215+ 600
216+ }
217+
218+ fn default_fee_multiplier_pct ( ) -> u64 {
219+ 110
220+ }
221+
222+ fn default_fee_multiplier_cap_pct ( ) -> u64 {
223+ 200
224+ }
225+
226+ impl Default for EscalationPolicyConfig {
227+ fn default ( ) -> Self {
228+ Self {
229+ initial_gas_multiplier_pct : default_initial_gas_multiplier_pct ( ) ,
230+ gas_multiplier_pct : default_gas_multiplier_pct ( ) ,
231+ gas_multiplier_cap_pct : default_gas_multiplier_cap_pct ( ) ,
232+ fee_multiplier_pct : default_fee_multiplier_pct ( ) ,
233+ fee_multiplier_cap_pct : default_fee_multiplier_cap_pct ( ) ,
234+ }
235+ }
236+ }
237+
238+ impl EscalationPolicyConfig {
239+ pub fn get_gas_multiplier_pct ( & self , num_retries : u64 ) -> u64 {
240+ self . apply_escalation_policy (
241+ num_retries,
242+ self . initial_gas_multiplier_pct ,
243+ self . gas_multiplier_pct ,
244+ self . gas_multiplier_cap_pct ,
245+ )
246+ }
247+
248+ pub fn get_fee_multiplier_pct ( & self , num_retries : u64 ) -> u64 {
249+ self . apply_escalation_policy (
250+ num_retries,
251+ 100 ,
252+ self . fee_multiplier_pct ,
253+ self . fee_multiplier_cap_pct ,
254+ )
255+ }
256+
257+ fn apply_escalation_policy (
258+ & self ,
259+ num_retries : u64 ,
260+ initial : u64 ,
261+ multiplier : u64 ,
262+ cap : u64 ,
263+ ) -> u64 {
264+ let mut current = initial;
265+ let mut i = 0 ;
266+ while i < num_retries && current < cap {
267+ current = current. saturating_mul ( multiplier) / 100 ;
268+ i += 1 ;
269+ }
270+
271+ current. min ( cap)
272+ }
273+ }
274+
183275/// A commitment that the provider used to generate random numbers at some point in the past.
184276/// These historical commitments need to be stored in the configuration to support transition points where
185277/// the commitment changes. In theory, this information is stored on the blockchain, but unfortunately it
@@ -227,10 +319,6 @@ fn default_chain_sample_interval() -> u64 {
227319 1
228320}
229321
230- fn default_priority_fee_multiplier_pct ( ) -> u64 {
231- 100
232- }
233-
234322/// Configuration values for the keeper service that are shared across chains.
235323#[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
236324pub struct KeeperConfig {
0 commit comments