olas-operate-middleware 0.6.3__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  # ------------------------------------------------------------------------------
20
- """Bridge provider."""
20
+ """Provider."""
21
21
 
22
22
 
23
23
  import copy
@@ -28,6 +28,7 @@ import typing as t
28
28
  import uuid
29
29
  from abc import ABC, abstractmethod
30
30
  from dataclasses import dataclass
31
+ from math import ceil
31
32
 
32
33
  from aea.crypto.base import LedgerApi
33
34
  from aea.helpers.logging import setup_logger
@@ -46,21 +47,23 @@ from operate.resource import LocalResource
46
47
  from operate.wallet.master import MasterWalletManager
47
48
 
48
49
 
49
- PLACEHOLDER_NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" # nosec
50
+ GAS_ESTIMATE_FALLBACK_ADDRESSES = [
51
+ "0x000000000000000000000000000000000000dEaD",
52
+ "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", # nosec
53
+ ]
50
54
 
51
55
  DEFAULT_MAX_QUOTE_RETRIES = 3
52
- BRIDGE_REQUEST_PREFIX = "r-"
56
+ PROVIDER_REQUEST_PREFIX = "r-"
53
57
  MESSAGE_QUOTE_ZERO = "Zero-amount quote requested."
54
58
  MESSAGE_EXECUTION_SKIPPED = "Execution skipped."
55
59
  MESSAGE_EXECUTION_FAILED = "Execution failed:"
56
- MESSAGE_EXECUTION_FAILED_ETA = f"{MESSAGE_EXECUTION_FAILED} bridge ETA exceeded."
60
+ MESSAGE_EXECUTION_FAILED_ETA = f"{MESSAGE_EXECUTION_FAILED} ETA exceeded."
57
61
  MESSAGE_EXECUTION_FAILED_QUOTE_FAILED = f"{MESSAGE_EXECUTION_FAILED} quote failed."
58
- MESSAGE_EXECUTION_FAILED_REVERTED = (
59
- f"{MESSAGE_EXECUTION_FAILED} bridge transaction reverted."
60
- )
62
+ MESSAGE_EXECUTION_FAILED_REVERTED = f"{MESSAGE_EXECUTION_FAILED} transaction reverted."
61
63
  MESSAGE_EXECUTION_FAILED_SETTLEMENT = (
62
64
  f"{MESSAGE_EXECUTION_FAILED} transaction settlement failed."
63
65
  )
66
+ MESSAGE_REQUIREMENTS_QUOTE_FAILED = "Cannot compute requirements for failed quote."
64
67
 
65
68
  ERC20_APPROVE_SELECTOR = "0x095ea7b3" # First 4 bytes of Web3.keccak(text='approve(address,uint256)').hex()[:10]
66
69
 
@@ -71,7 +74,7 @@ GAS_ESTIMATE_BUFFER = 1.10
71
74
  class QuoteData(LocalResource):
72
75
  """QuoteData"""
73
76
 
74
- bridge_eta: t.Optional[int]
77
+ eta: t.Optional[int]
75
78
  elapsed_time: float
76
79
  message: t.Optional[str]
77
80
  timestamp: int
@@ -90,8 +93,8 @@ class ExecutionData(LocalResource):
90
93
  provider_data: t.Optional[t.Dict] # Provider-specific data
91
94
 
92
95
 
93
- class BridgeRequestStatus(str, enum.Enum):
94
- """BridgeRequestStatus"""
96
+ class ProviderRequestStatus(str, enum.Enum):
97
+ """ProviderRequestStatus"""
95
98
 
96
99
  CREATED = "CREATED"
97
100
  QUOTE_DONE = "QUOTE_DONE"
@@ -107,35 +110,34 @@ class BridgeRequestStatus(str, enum.Enum):
107
110
 
108
111
 
109
112
  @dataclass
110
- class BridgeRequest(LocalResource):
111
- """BridgeRequest"""
113
+ class ProviderRequest(LocalResource):
114
+ """ProviderRequest"""
112
115
 
113
116
  params: t.Dict
114
- bridge_provider_id: str
117
+ provider_id: str
115
118
  id: str
116
- status: BridgeRequestStatus
119
+ status: ProviderRequestStatus
117
120
  quote_data: t.Optional[QuoteData]
118
121
  execution_data: t.Optional[ExecutionData]
119
122
 
120
123
 
121
- class BridgeProvider(ABC):
122
- """(Abstract) BridgeProvider.
124
+ class Provider(ABC):
125
+ """(Abstract) Provider.
123
126
 
124
127
  Expected usage:
125
128
  params = {...}
126
129
 
127
- 1. request = bridge.create_request(params)
128
- 2. bridge.quote(request)
129
- 3. bridge.requirements(request)
130
- 4. bridge.execute(request)
131
- 5. bridge.status_json(request)
130
+ 1. request = provider.create_request(params)
131
+ 2. provider.quote(request)
132
+ 3. provider.requirements(request)
133
+ 4. provider.execute(request)
134
+ 5. provider.status_json(request)
132
135
 
133
136
  Derived classes must implement the following methods:
134
137
  - description
135
138
  - quote
136
139
  - _update_execution_status
137
- - _get_approve_tx
138
- - _get_bridge_tx
140
+ - _get_txs
139
141
  - _get_explorer_link
140
142
  """
141
143
 
@@ -145,28 +147,28 @@ class BridgeProvider(ABC):
145
147
  provider_id: str,
146
148
  logger: t.Optional[logging.Logger] = None,
147
149
  ) -> None:
148
- """Initialize the bridge provider."""
150
+ """Initialize the provider."""
149
151
  self.wallet_manager = wallet_manager
150
152
  self.provider_id = provider_id
151
- self.logger = logger or setup_logger(name="operate.bridge.BridgeProvider")
153
+ self.logger = logger or setup_logger(name="operate.bridge.providers.Provider")
152
154
 
153
155
  def description(self) -> str:
154
- """Get a human-readable description of the bridge provider."""
156
+ """Get a human-readable description of the provider."""
155
157
  return self.__class__.__name__
156
158
 
157
- def _validate(self, bridge_request: BridgeRequest) -> None:
158
- """Validate theat the bridge request was created by this bridge."""
159
- if bridge_request.bridge_provider_id != self.provider_id:
159
+ def _validate(self, provider_request: ProviderRequest) -> None:
160
+ """Validate that the request was created by this provider."""
161
+ if provider_request.provider_id != self.provider_id:
160
162
  raise ValueError(
161
- f"Bridge request provider id {bridge_request.bridge_provider_id} does not match the bridge provider id {self.provider_id}"
163
+ f"Request provider id {provider_request.provider_id} does not match the provider id {self.provider_id}"
162
164
  )
163
165
 
164
166
  def can_handle_request(self, params: t.Dict) -> bool:
165
- """Returns 'true' if the bridge can handle a request for 'params'."""
167
+ """Returns 'true' if the provider can handle a request for 'params'."""
166
168
 
167
169
  if "from" not in params or "to" not in params:
168
170
  self.logger.error(
169
- "[BRIDGE PROVIDER] Invalid input: All requests must contain exactly one 'from' and one 'to' sender."
171
+ "[PROVIDER] Invalid input: All requests must contain exactly one 'from' and one 'to' sender."
170
172
  )
171
173
  return False
172
174
 
@@ -180,7 +182,7 @@ class BridgeProvider(ABC):
180
182
  or "token" not in from_
181
183
  ):
182
184
  self.logger.error(
183
- "[BRIDGE PROVIDER] Invalid input: 'from' must contain 'chain', 'address', and 'token'."
185
+ "[PROVIDER] Invalid input: 'from' must contain 'chain', 'address', and 'token'."
184
186
  )
185
187
  return False
186
188
 
@@ -192,17 +194,17 @@ class BridgeProvider(ABC):
192
194
  or "amount" not in to
193
195
  ):
194
196
  self.logger.error(
195
- "[BRIDGE PROVIDER] Invalid input: 'to' must contain 'chain', 'address', 'token', and 'amount'."
197
+ "[PROVIDER] Invalid input: 'to' must contain 'chain', 'address', 'token', and 'amount'."
196
198
  )
197
199
  return False
198
200
 
199
201
  return True
200
202
 
201
- def create_request(self, params: t.Dict) -> BridgeRequest:
202
- """Create a bridge request."""
203
+ def create_request(self, params: t.Dict) -> ProviderRequest:
204
+ """Create a request."""
203
205
 
204
206
  if not self.can_handle_request(params):
205
- raise ValueError("Invalid input: Cannot process bridge request.")
207
+ raise ValueError("Invalid input: Cannot process request.")
206
208
 
207
209
  w3 = Web3()
208
210
  params = copy.deepcopy(params)
@@ -212,18 +214,18 @@ class BridgeProvider(ABC):
212
214
  params["to"]["token"] = w3.to_checksum_address(params["to"]["token"])
213
215
  params["to"]["amount"] = int(params["to"]["amount"])
214
216
 
215
- return BridgeRequest(
217
+ return ProviderRequest(
216
218
  params=params,
217
- bridge_provider_id=self.provider_id,
218
- id=f"{BRIDGE_REQUEST_PREFIX}{uuid.uuid4()}",
219
+ provider_id=self.provider_id,
220
+ id=f"{PROVIDER_REQUEST_PREFIX}{uuid.uuid4()}",
219
221
  quote_data=None,
220
222
  execution_data=None,
221
- status=BridgeRequestStatus.CREATED,
223
+ status=ProviderRequestStatus.CREATED,
222
224
  )
223
225
 
224
- def _from_ledger_api(self, bridge_request: BridgeRequest) -> LedgerApi:
226
+ def _from_ledger_api(self, provider_request: ProviderRequest) -> LedgerApi:
225
227
  """Get the from ledger api."""
226
- from_chain = bridge_request.params["from"]["chain"]
228
+ from_chain = provider_request.params["from"]["chain"]
227
229
  chain = Chain(from_chain)
228
230
  wallet = self.wallet_manager.load(chain.ledger_type)
229
231
  ledger_api = wallet.ledger_api(chain)
@@ -234,9 +236,9 @@ class BridgeProvider(ABC):
234
236
 
235
237
  return ledger_api
236
238
 
237
- def _to_ledger_api(self, bridge_request: BridgeRequest) -> LedgerApi:
239
+ def _to_ledger_api(self, provider_request: ProviderRequest) -> LedgerApi:
238
240
  """Get the from ledger api."""
239
- from_chain = bridge_request.params["to"]["chain"]
241
+ from_chain = provider_request.params["to"]["chain"]
240
242
  chain = Chain(from_chain)
241
243
  wallet = self.wallet_manager.load(chain.ledger_type)
242
244
  ledger_api = wallet.ledger_api(chain)
@@ -248,41 +250,29 @@ class BridgeProvider(ABC):
248
250
  return ledger_api
249
251
 
250
252
  @abstractmethod
251
- def quote(self, bridge_request: BridgeRequest) -> None:
253
+ def quote(self, provider_request: ProviderRequest) -> None:
252
254
  """Update the request with the quote."""
253
255
  raise NotImplementedError()
254
256
 
255
257
  @abstractmethod
256
- def _get_approve_tx(self, bridge_request: BridgeRequest) -> t.Optional[t.Dict]:
257
- """Get the approve transaction."""
258
- raise NotImplementedError()
259
-
260
- @abstractmethod
261
- def _get_bridge_tx(self, bridge_request: BridgeRequest) -> t.Optional[t.Dict]:
262
- """Get the bridge transaction."""
258
+ def _get_txs(
259
+ self, provider_request: ProviderRequest, *args: t.Any, **kwargs: t.Any
260
+ ) -> t.List[t.Tuple[str, t.Dict]]:
261
+ """Get the sorted list of transactions to execute the quote."""
263
262
  raise NotImplementedError()
264
263
 
265
- def bridge_requirements(self, bridge_request: BridgeRequest) -> t.Dict:
266
- """Gets the bridge requirements to execute the quote, with updated gas estimation."""
267
- self.logger.info(
268
- f"[BRIDGE PROVIDER] Bridge requirements for request {bridge_request.id}."
269
- )
264
+ def requirements(self, provider_request: ProviderRequest) -> t.Dict:
265
+ """Gets the requirements to execute the quote, with updated gas estimation."""
266
+ self.logger.info(f"[PROVIDER] Requirements for request {provider_request.id}.")
270
267
 
271
- self._validate(bridge_request)
268
+ self._validate(provider_request)
272
269
 
273
- from_chain = bridge_request.params["from"]["chain"]
274
- from_address = bridge_request.params["from"]["address"]
275
- from_token = bridge_request.params["from"]["token"]
276
- from_ledger_api = self._from_ledger_api(bridge_request)
270
+ from_chain = provider_request.params["from"]["chain"]
271
+ from_address = provider_request.params["from"]["address"]
272
+ from_token = provider_request.params["from"]["token"]
273
+ from_ledger_api = self._from_ledger_api(provider_request)
277
274
 
278
- txs = []
279
-
280
- approve_tx = self._get_approve_tx(bridge_request)
281
- if approve_tx:
282
- txs.append(("approve_tx", approve_tx))
283
- bridge_tx = self._get_bridge_tx(bridge_request)
284
- if bridge_tx:
285
- txs.append(("bridge_tx", bridge_tx))
275
+ txs = self._get_txs(provider_request)
286
276
 
287
277
  if not txs:
288
278
  return {
@@ -300,7 +290,7 @@ class BridgeProvider(ABC):
300
290
 
301
291
  for tx_label, tx in txs:
302
292
  self.logger.debug(
303
- f"[BRIDGE PROVIDER] Processing transaction {tx_label} for bridge request {bridge_request.id}."
293
+ f"[PROVIDER] Processing transaction {tx_label} for request {provider_request.id}."
304
294
  )
305
295
  self._update_with_gas_pricing(tx, from_ledger_api)
306
296
  gas_key = "gasPrice" if "gasPrice" in tx else "maxFeePerGas"
@@ -310,11 +300,11 @@ class BridgeProvider(ABC):
310
300
  total_native += tx_value + gas_fees
311
301
 
312
302
  self.logger.debug(
313
- f"[BRIDGE PROVIDER] Transaction {gas_key}={tx.get(gas_key, 0)} maxPriorityFeePerGas={tx.get('maxPriorityFeePerGas', -1)} gas={tx['gas']} {gas_fees=} {tx_value=}"
303
+ f"[PROVIDER] Transaction {gas_key}={tx.get(gas_key, 0)} maxPriorityFeePerGas={tx.get('maxPriorityFeePerGas', -1)} gas={tx['gas']} {gas_fees=} {tx_value=}"
314
304
  )
315
- self.logger.debug(f"[BRIDGE PROVIDER] {from_ledger_api.api.eth.gas_price=}")
305
+ self.logger.debug(f"[PROVIDER] {from_ledger_api.api.eth.gas_price=}")
316
306
  self.logger.debug(
317
- f"[BRIDGE PROVIDER] {from_ledger_api.api.eth.get_block('latest').baseFeePerGas=}"
307
+ f"[PROVIDER] {from_ledger_api.api.eth.get_block('latest').baseFeePerGas=}"
318
308
  )
319
309
 
320
310
  if tx.get("to", "").lower() == from_token.lower() and tx.get(
@@ -327,7 +317,7 @@ class BridgeProvider(ABC):
327
317
  raise RuntimeError("Malformed ERC20 approve transaction.") from e
328
318
 
329
319
  self.logger.info(
330
- f"[BRIDGE PROVIDER] Total gas fees for bridge request {bridge_request.id}: {total_gas_fees} native units."
320
+ f"[PROVIDER] Total gas fees for request {provider_request.id}: {total_gas_fees} native units."
331
321
  )
332
322
 
333
323
  result = {
@@ -343,18 +333,14 @@ class BridgeProvider(ABC):
343
333
 
344
334
  return result
345
335
 
346
- def execute(self, bridge_request: BridgeRequest) -> None:
336
+ def execute(self, provider_request: ProviderRequest) -> None:
347
337
  """Execute the request."""
348
- self.logger.info(
349
- f"[BRIDGE PROVIDER] Executing bridge request {bridge_request.id}."
350
- )
338
+ self.logger.info(f"[PROVIDER] Executing request {provider_request.id}.")
351
339
 
352
- self._validate(bridge_request)
340
+ self._validate(provider_request)
353
341
 
354
- if bridge_request.status in (BridgeRequestStatus.QUOTE_FAILED):
355
- self.logger.info(
356
- f"[BRIDGE PROVIDER] {MESSAGE_EXECUTION_FAILED_QUOTE_FAILED}."
357
- )
342
+ if provider_request.status in (ProviderRequestStatus.QUOTE_FAILED):
343
+ self.logger.info(f"[PROVIDER] {MESSAGE_EXECUTION_FAILED_QUOTE_FAILED}.")
358
344
  execution_data = ExecutionData(
359
345
  elapsed_time=0,
360
346
  message=f"{MESSAGE_EXECUTION_FAILED_QUOTE_FAILED}",
@@ -363,61 +349,52 @@ class BridgeProvider(ABC):
363
349
  to_tx_hash=None,
364
350
  provider_data=None,
365
351
  )
366
- bridge_request.execution_data = execution_data
367
- bridge_request.status = BridgeRequestStatus.EXECUTION_FAILED
352
+ provider_request.execution_data = execution_data
353
+ provider_request.status = ProviderRequestStatus.EXECUTION_FAILED
368
354
  return
369
355
 
370
- if bridge_request.status not in (BridgeRequestStatus.QUOTE_DONE,):
356
+ if provider_request.status not in (ProviderRequestStatus.QUOTE_DONE,):
371
357
  raise RuntimeError(
372
- f"Cannot execute bridge request {bridge_request.id} with status {bridge_request.status}."
358
+ f"Cannot execute request {provider_request.id} with status {provider_request.status}."
373
359
  )
374
- if not bridge_request.quote_data:
360
+ if not provider_request.quote_data:
375
361
  raise RuntimeError(
376
- f"Cannot execute bridge request {bridge_request.id}: quote data not present."
362
+ f"Cannot execute request {provider_request.id}: quote data not present."
377
363
  )
378
- if bridge_request.execution_data:
364
+ if provider_request.execution_data:
379
365
  raise RuntimeError(
380
- f"Cannot execute bridge request {bridge_request.id}: execution data already present."
366
+ f"Cannot execute request {provider_request.id}: execution data already present."
381
367
  )
382
368
 
383
- txs = []
384
-
385
- approve_tx = self._get_approve_tx(bridge_request)
386
- if approve_tx:
387
- txs.append(("approve_tx", approve_tx))
388
- bridge_tx = self._get_bridge_tx(bridge_request)
389
- if bridge_tx:
390
- txs.append(("bridge_tx", bridge_tx))
369
+ txs = self._get_txs(provider_request)
391
370
 
392
371
  if not txs:
393
372
  self.logger.info(
394
- f"[BRIDGE PROVIDER] {MESSAGE_EXECUTION_SKIPPED} ({bridge_request.status=})"
373
+ f"[PROVIDER] {MESSAGE_EXECUTION_SKIPPED} ({provider_request.status=})"
395
374
  )
396
375
  execution_data = ExecutionData(
397
376
  elapsed_time=0,
398
- message=f"{MESSAGE_EXECUTION_SKIPPED} ({bridge_request.status=})",
377
+ message=f"{MESSAGE_EXECUTION_SKIPPED} ({provider_request.status=})",
399
378
  timestamp=int(time.time()),
400
379
  from_tx_hash=None,
401
380
  to_tx_hash=None,
402
381
  provider_data=None,
403
382
  )
404
- bridge_request.execution_data = execution_data
405
- bridge_request.status = BridgeRequestStatus.EXECUTION_DONE
383
+ provider_request.execution_data = execution_data
384
+ provider_request.status = ProviderRequestStatus.EXECUTION_DONE
406
385
  return
407
386
 
408
387
  try:
409
- self.logger.info(
410
- f"[BRIDGE PROVIDER] Executing bridge request {bridge_request.id}."
411
- )
388
+ self.logger.info(f"[PROVIDER] Executing request {provider_request.id}.")
412
389
  timestamp = time.time()
413
- chain = Chain(bridge_request.params["from"]["chain"])
414
- from_address = bridge_request.params["from"]["address"]
390
+ chain = Chain(provider_request.params["from"]["chain"])
391
+ from_address = provider_request.params["from"]["address"]
415
392
  wallet = self.wallet_manager.load(chain.ledger_type)
416
- from_ledger_api = self._from_ledger_api(bridge_request)
393
+ from_ledger_api = self._from_ledger_api(provider_request)
417
394
  tx_settler = TxSettler(
418
395
  ledger_api=from_ledger_api,
419
396
  crypto=wallet.crypto,
420
- chain_type=Chain(bridge_request.params["from"]["chain"]),
397
+ chain_type=Chain(provider_request.params["from"]["chain"]),
421
398
  timeout=ON_CHAIN_INTERACT_TIMEOUT,
422
399
  retries=ON_CHAIN_INTERACT_RETRIES,
423
400
  sleep=ON_CHAIN_INTERACT_SLEEP,
@@ -425,7 +402,7 @@ class BridgeProvider(ABC):
425
402
  tx_hashes = []
426
403
 
427
404
  for tx_label, tx in txs:
428
- self.logger.info(f"[BRIDGE] Executing transaction {tx_label}.")
405
+ self.logger.info(f"[PROVIDER] Executing transaction {tx_label}.")
429
406
  nonce = from_ledger_api.api.eth.get_transaction_count(from_address)
430
407
  tx["nonce"] = nonce # TODO: backport to TxSettler
431
408
  setattr( # noqa: B010
@@ -437,7 +414,7 @@ class BridgeProvider(ABC):
437
414
  kwargs={},
438
415
  dry_run=False,
439
416
  )
440
- self.logger.info(f"[BRIDGE] Transaction {tx_label} settled.")
417
+ self.logger.info(f"[PROVIDER] Transaction {tx_label} settled.")
441
418
  tx_hashes.append(tx_receipt.get("transactionHash", "").hex())
442
419
 
443
420
  execution_data = ExecutionData(
@@ -448,17 +425,17 @@ class BridgeProvider(ABC):
448
425
  to_tx_hash=None,
449
426
  provider_data=None,
450
427
  )
451
- bridge_request.execution_data = execution_data
428
+ provider_request.execution_data = execution_data
452
429
  if len(tx_hashes) == len(txs):
453
- bridge_request.status = BridgeRequestStatus.EXECUTION_PENDING
430
+ provider_request.status = ProviderRequestStatus.EXECUTION_PENDING
454
431
  else:
455
- bridge_request.execution_data.message = (
432
+ provider_request.execution_data.message = (
456
433
  MESSAGE_EXECUTION_FAILED_SETTLEMENT
457
434
  )
458
- bridge_request.status = BridgeRequestStatus.EXECUTION_FAILED
435
+ provider_request.status = ProviderRequestStatus.EXECUTION_FAILED
459
436
 
460
437
  except Exception as e: # pylint: disable=broad-except
461
- self.logger.error(f"[BRIDGE PROVIDER] Error executing bridge request: {e}")
438
+ self.logger.error(f"[PROVIDER] Error executing request: {e}")
462
439
  execution_data = ExecutionData(
463
440
  elapsed_time=time.time() - timestamp,
464
441
  message=f"{MESSAGE_EXECUTION_FAILED} {str(e)}",
@@ -467,44 +444,44 @@ class BridgeProvider(ABC):
467
444
  to_tx_hash=None,
468
445
  provider_data=None,
469
446
  )
470
- bridge_request.execution_data = execution_data
471
- bridge_request.status = BridgeRequestStatus.EXECUTION_FAILED
447
+ provider_request.execution_data = execution_data
448
+ provider_request.status = ProviderRequestStatus.EXECUTION_FAILED
472
449
 
473
450
  @abstractmethod
474
- def _update_execution_status(self, bridge_request: BridgeRequest) -> None:
451
+ def _update_execution_status(self, provider_request: ProviderRequest) -> None:
475
452
  """Update the execution status."""
476
453
  raise NotImplementedError()
477
454
 
478
455
  @abstractmethod
479
- def _get_explorer_link(self, bridge_request: BridgeRequest) -> t.Optional[str]:
456
+ def _get_explorer_link(self, provider_request: ProviderRequest) -> t.Optional[str]:
480
457
  """Get the explorer link for a transaction."""
481
458
  raise NotImplementedError()
482
459
 
483
- def status_json(self, bridge_request: BridgeRequest) -> t.Dict:
460
+ def status_json(self, provider_request: ProviderRequest) -> t.Dict:
484
461
  """JSON representation of the status."""
485
- self._validate(bridge_request)
462
+ self._validate(provider_request)
486
463
 
487
- if bridge_request.execution_data and bridge_request.quote_data:
488
- self._update_execution_status(bridge_request)
464
+ if provider_request.execution_data and provider_request.quote_data:
465
+ self._update_execution_status(provider_request)
489
466
  tx_hash = None
490
- if bridge_request.execution_data.from_tx_hash:
491
- tx_hash = bridge_request.execution_data.from_tx_hash
467
+ if provider_request.execution_data.from_tx_hash:
468
+ tx_hash = provider_request.execution_data.from_tx_hash
492
469
 
493
470
  return {
494
- "eta": bridge_request.quote_data.bridge_eta,
495
- "explorer_link": self._get_explorer_link(bridge_request),
496
- "message": bridge_request.execution_data.message,
497
- "status": bridge_request.status.value,
471
+ "eta": provider_request.quote_data.eta,
472
+ "explorer_link": self._get_explorer_link(provider_request),
473
+ "message": provider_request.execution_data.message,
474
+ "status": provider_request.status.value,
498
475
  "tx_hash": tx_hash,
499
476
  }
500
- if bridge_request.quote_data:
477
+ if provider_request.quote_data:
501
478
  return {
502
- "eta": bridge_request.quote_data.bridge_eta,
503
- "message": bridge_request.quote_data.message,
504
- "status": bridge_request.status.value,
479
+ "eta": provider_request.quote_data.eta,
480
+ "message": provider_request.quote_data.message,
481
+ "status": provider_request.status.value,
505
482
  }
506
483
 
507
- return {"message": None, "status": bridge_request.status.value}
484
+ return {"message": None, "status": provider_request.status.value}
508
485
 
509
486
  @staticmethod
510
487
  def _tx_timestamp(tx_hash: str, ledger_api: LedgerApi) -> int:
@@ -535,19 +512,24 @@ class BridgeProvider(ABC):
535
512
  # TODO backport to open aea/autonomy
536
513
  @staticmethod
537
514
  def _update_with_gas_estimate(tx: t.Dict, ledger_api: LedgerApi) -> None:
515
+ print(
516
+ f"[PROVIDER] Trying to update transaction gas {tx['from']=} {tx['gas']=}."
517
+ )
518
+ original_from = tx["from"]
538
519
  original_gas = tx.get("gas", 1)
539
- tx["gas"] = 1
540
- ledger_api.update_with_gas_estimate(tx)
541
520
 
542
- if tx["gas"] > 1:
543
- return
521
+ for address in [original_from] + GAS_ESTIMATE_FALLBACK_ADDRESSES:
522
+ tx["from"] = address
523
+ tx["gas"] = 1
524
+ ledger_api.update_with_gas_estimate(tx)
525
+ if tx["gas"] > 1:
526
+ print(
527
+ f"[PROVIDER] Gas estimated successfully {tx['from']=} {tx['gas']=}."
528
+ )
529
+ break
544
530
 
545
- original_from = tx["from"]
546
- tx["from"] = PLACEHOLDER_NATIVE_TOKEN_ADDRESS
547
- ledger_api.update_with_gas_estimate(tx)
548
531
  tx["from"] = original_from
549
-
550
- if tx["gas"] > 1:
551
- return
552
-
553
- tx["gas"] = original_gas
532
+ if tx["gas"] == 1:
533
+ tx["gas"] = original_gas
534
+ print(f"[PROVIDER] Unable to estimate gas. Restored {tx['gas']=}.")
535
+ tx["gas"] = ceil(tx["gas"] * GAS_ESTIMATE_BUFFER)