@@ -6,12 +6,13 @@ mod token;
66mod anvil;
77
88use super :: DriaOracleConfig ;
9+ use alloy:: contract:: CallBuilder ;
910use alloy:: hex:: FromHex ;
1011use alloy:: providers:: fillers:: {
1112 BlobGasFiller , ChainIdFiller , FillProvider , GasFiller , JoinFill , NonceFiller , WalletFiller ,
1213} ;
1314use alloy:: providers:: { PendingTransactionBuilder , WalletProvider } ;
14- use alloy:: rpc :: types :: TransactionReceipt ;
15+ use alloy:: transports :: RpcError ;
1516use alloy:: {
1617 network:: { Ethereum , EthereumWallet } ,
1718 primitives:: Address ,
@@ -21,8 +22,8 @@ use alloy::{
2122use alloy_chains:: Chain ;
2223use dkn_workflows:: { DriaWorkflowsConfig , Model , ModelProvider } ;
2324use dria_oracle_contracts:: {
24- get_coordinator_address, ContractAddresses , OracleCoordinator , OracleKind , OracleRegistry ,
25- TokenBalance ,
25+ contract_error_report , get_coordinator_address, ContractAddresses , OracleCoordinator ,
26+ OracleKind , OracleRegistry , TokenBalance ,
2627} ;
2728use eyre:: { eyre, Context , Result } ;
2829use std:: env;
@@ -259,17 +260,87 @@ impl DriaOracle {
259260 }
260261
261262 /// Waits for a transaction to be mined, returning the receipt.
262- async fn wait_for_tx (
263+ #[ inline]
264+ async fn wait_for_tx < T , N > (
263265 & self ,
264- tx : PendingTransactionBuilder < Http < Client > , Ethereum > ,
265- ) -> Result < TransactionReceipt > {
266+ tx : PendingTransactionBuilder < T , N > ,
267+ ) -> Result < N :: ReceiptResponse >
268+ where
269+ T : alloy:: transports:: Transport + Clone ,
270+ N : alloy:: network:: Network ,
271+ {
266272 log:: info!( "Waiting for tx: {:?}" , tx. tx_hash( ) ) ;
267273 let receipt = tx
268274 . with_timeout ( self . config . tx_timeout )
269275 . get_receipt ( )
270276 . await ?;
271277 Ok ( receipt)
272278 }
279+
280+ /// Given a request, retries sending it with increasing gas prices to avoid
281+ /// the "tx underpriced" errors.
282+ #[ inline]
283+ async fn send_with_gas_hikes < T , P , D , N > (
284+ & self ,
285+ req : CallBuilder < T , P , D , N > ,
286+ ) -> Result < PendingTransactionBuilder < T , N > >
287+ where
288+ T : alloy:: transports:: Transport + Clone ,
289+ P : alloy:: providers:: Provider < T , N > + Clone ,
290+ D : alloy:: contract:: CallDecoder + Clone ,
291+ N : alloy:: network:: Network ,
292+ {
293+ // gas price hikes to try in increasing order, first is 0 to simply use the
294+ // initial gas fee for the first attempt
295+ const GAS_PRICE_HIKES : [ u128 ; 4 ] = [ 0 , 12 , 24 , 36 ] ;
296+
297+ // try and send tx, with increasing gas prices for few attempts
298+ let initial_gas_price = self . provider . get_gas_price ( ) . await ?;
299+ for ( attempt_no, increase_percentage) in GAS_PRICE_HIKES . iter ( ) . enumerate ( ) {
300+ // set gas price
301+ let gas_price = initial_gas_price + ( initial_gas_price / 100 ) * increase_percentage;
302+
303+ // try to send tx with gas price
304+ match req
305+ . clone ( )
306+ . gas_price ( gas_price) // TODO: very low gas price to get an error deliberately
307+ . send ( )
308+ . await
309+ {
310+ // if all is well, we can return the tx
311+ Ok ( tx) => {
312+ return Ok ( tx) ;
313+ }
314+ // if we get an RPC error; specifically, if the tx is underpriced, we try again with higher gas
315+ Err ( alloy:: contract:: Error :: TransportError ( RpcError :: ErrorResp ( err) ) ) => {
316+ // TODO: kind of a code-smell, can we do better check here?
317+ if err. message . contains ( "underpriced" ) {
318+ log:: warn!(
319+ "{} with gas {} in attempt {}" ,
320+ err. message,
321+ gas_price,
322+ attempt_no + 1 ,
323+ ) ;
324+
325+ // wait just a little bit
326+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 300 ) ) . await ;
327+
328+ continue ;
329+ } else {
330+ // otherwise let it be handled by the error report
331+ return Err ( contract_error_report (
332+ alloy:: contract:: Error :: TransportError ( RpcError :: ErrorResp ( err) ) ,
333+ ) ) ;
334+ }
335+ }
336+ // if we get any other error, we report it
337+ Err ( err) => return Err ( contract_error_report ( err) ) ,
338+ } ;
339+ }
340+
341+ // all attempts failed
342+ Err ( eyre ! ( "Failed to send transaction." ) )
343+ }
273344}
274345
275346impl core:: fmt:: Display for DriaOracle {
0 commit comments