olas-operate-middleware 0.10.18__tar.gz → 0.10.20__tar.gz

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.
Files changed (97) hide show
  1. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/PKG-INFO +1 -1
  2. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/bridge/providers/lifi_provider.py +5 -4
  3. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/bridge/providers/native_bridge_provider.py +5 -4
  4. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/bridge/providers/provider.py +2 -54
  5. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/bridge/providers/relay_provider.py +5 -4
  6. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/cli.py +8 -60
  7. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/constants.py +2 -2
  8. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/keys.py +13 -0
  9. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/ledger/__init__.py +55 -0
  10. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/run_service.py +5 -9
  11. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/agent_runner.py +2 -2
  12. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/health_checker.py +4 -4
  13. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/manage.py +18 -4
  14. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/utils/__init__.py +0 -29
  15. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/wallet/master.py +8 -5
  16. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/pyproject.toml +1 -1
  17. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/LICENSE +0 -0
  18. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/README.md +0 -0
  19. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/__init__.py +0 -0
  20. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/account/__init__.py +0 -0
  21. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/account/user.py +0 -0
  22. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/bridge/bridge_manager.py +0 -0
  23. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/README.md +0 -0
  24. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/__init__.py +0 -0
  25. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/__init__.py +0 -0
  26. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/dual_staking_token/__init__.py +0 -0
  27. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/dual_staking_token/build/DualStakingToken.json +0 -0
  28. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/dual_staking_token/contract.py +0 -0
  29. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/dual_staking_token/contract.yaml +0 -0
  30. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/foreign_omnibridge/__init__.py +0 -0
  31. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/foreign_omnibridge/build/ForeignOmnibridge.json +0 -0
  32. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/foreign_omnibridge/contract.py +0 -0
  33. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/foreign_omnibridge/contract.yaml +0 -0
  34. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/home_omnibridge/__init__.py +0 -0
  35. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/home_omnibridge/build/HomeOmnibridge.json +0 -0
  36. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/home_omnibridge/contract.py +0 -0
  37. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/home_omnibridge/contract.yaml +0 -0
  38. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l1_standard_bridge/__init__.py +0 -0
  39. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l1_standard_bridge/build/L1StandardBridge.json +0 -0
  40. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l1_standard_bridge/contract.py +0 -0
  41. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l1_standard_bridge/contract.yaml +0 -0
  42. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l2_standard_bridge/__init__.py +0 -0
  43. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l2_standard_bridge/build/L2StandardBridge.json +0 -0
  44. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l2_standard_bridge/contract.py +0 -0
  45. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/l2_standard_bridge/contract.yaml +0 -0
  46. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/mech_activity/__init__.py +0 -0
  47. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/mech_activity/build/MechActivity.json +0 -0
  48. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/mech_activity/contract.py +0 -0
  49. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/mech_activity/contract.yaml +0 -0
  50. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/optimism_mintable_erc20/__init__.py +0 -0
  51. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/optimism_mintable_erc20/build/OptimismMintableERC20.json +0 -0
  52. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/optimism_mintable_erc20/contract.py +0 -0
  53. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/optimism_mintable_erc20/contract.yaml +0 -0
  54. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/recovery_module/__init__.py +0 -0
  55. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/recovery_module/build/RecoveryModule.json +0 -0
  56. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/recovery_module/contract.py +0 -0
  57. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/recovery_module/contract.yaml +0 -0
  58. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/requester_activity_checker/__init__.py +0 -0
  59. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/requester_activity_checker/build/RequesterActivityChecker.json +0 -0
  60. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/requester_activity_checker/contract.py +0 -0
  61. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/requester_activity_checker/contract.yaml +0 -0
  62. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/staking_token/__init__.py +0 -0
  63. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/staking_token/build/StakingToken.json +0 -0
  64. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/staking_token/contract.py +0 -0
  65. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/staking_token/contract.yaml +0 -0
  66. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/__init__.py +0 -0
  67. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/build/IUniswapV2ERC20.json +0 -0
  68. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/contract.py +0 -0
  69. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/contract.yaml +0 -0
  70. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py +0 -0
  71. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py +0 -0
  72. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/ledger/profiles.py +0 -0
  73. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/migration.py +0 -0
  74. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/operate_http/__init__.py +0 -0
  75. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/operate_http/exceptions.py +0 -0
  76. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/operate_types.py +0 -0
  77. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/pearl.py +0 -0
  78. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/analyse_logs.py +0 -0
  79. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/claim_staking_rewards.py +0 -0
  80. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/reset_configs.py +0 -0
  81. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/reset_password.py +0 -0
  82. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/reset_staking.py +0 -0
  83. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/stop_service.py +0 -0
  84. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/terminate_on_chain_service.py +0 -0
  85. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/quickstart/utils.py +0 -0
  86. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/resource.py +0 -0
  87. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/__init__.py +0 -0
  88. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/deployment_runner.py +0 -0
  89. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/protocol.py +0 -0
  90. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/service.py +0 -0
  91. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/utils/__init__.py +0 -0
  92. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/utils/mech.py +0 -0
  93. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/services/utils/tendermint.py +0 -0
  94. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/utils/gnosis.py +0 -0
  95. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/utils/ssl.py +0 -0
  96. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/wallet/__init__.py +0 -0
  97. {olas_operate_middleware-0.10.18 → olas_operate_middleware-0.10.20}/operate/wallet/wallet_recovery_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: olas-operate-middleware
3
- Version: 0.10.18
3
+ Version: 0.10.20
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: David Vilela
@@ -38,6 +38,7 @@ from operate.bridge.providers.provider import (
38
38
  QuoteData,
39
39
  )
40
40
  from operate.constants import ZERO_ADDRESS
41
+ from operate.ledger import update_tx_with_gas_estimate, update_tx_with_gas_pricing
41
42
  from operate.operate_types import Chain
42
43
 
43
44
 
@@ -240,8 +241,8 @@ class LiFiProvider(Provider):
240
241
  amount=from_amount,
241
242
  )
242
243
  approve_tx["gas"] = 200_000 # TODO backport to ERC20 contract as default
243
- Provider._update_with_gas_pricing(approve_tx, from_ledger_api)
244
- Provider._update_with_gas_estimate(approve_tx, from_ledger_api)
244
+ update_tx_with_gas_pricing(approve_tx, from_ledger_api)
245
+ update_tx_with_gas_estimate(approve_tx, from_ledger_api)
245
246
  return approve_tx
246
247
 
247
248
  def _get_bridge_tx(self, provider_request: ProviderRequest) -> t.Optional[t.Dict]:
@@ -285,8 +286,8 @@ class LiFiProvider(Provider):
285
286
  transaction_request["from"]
286
287
  ),
287
288
  }
288
- Provider._update_with_gas_pricing(bridge_tx, from_ledger_api)
289
- Provider._update_with_gas_estimate(bridge_tx, from_ledger_api)
289
+ update_tx_with_gas_pricing(bridge_tx, from_ledger_api)
290
+ update_tx_with_gas_estimate(bridge_tx, from_ledger_api)
290
291
  return bridge_tx
291
292
 
292
293
  def _get_txs(
@@ -53,6 +53,7 @@ from operate.data.contracts.l2_standard_bridge.contract import L2StandardBridge
53
53
  from operate.data.contracts.optimism_mintable_erc20.contract import (
54
54
  OptimismMintableERC20,
55
55
  )
56
+ from operate.ledger import update_tx_with_gas_estimate, update_tx_with_gas_pricing
56
57
  from operate.ledger.profiles import ERC20_TOKENS, EXPLORER_URL
57
58
  from operate.operate_types import Chain
58
59
  from operate.wallet.master import MasterWalletManager
@@ -512,8 +513,8 @@ class NativeBridgeProvider(Provider):
512
513
  amount=to_amount,
513
514
  )
514
515
  approve_tx["gas"] = 200_000 # TODO backport to ERC20 contract as default
515
- Provider._update_with_gas_pricing(approve_tx, from_ledger_api)
516
- Provider._update_with_gas_estimate(approve_tx, from_ledger_api)
516
+ update_tx_with_gas_pricing(approve_tx, from_ledger_api)
517
+ update_tx_with_gas_estimate(approve_tx, from_ledger_api)
517
518
  return approve_tx
518
519
 
519
520
  def _get_bridge_tx(self, provider_request: ProviderRequest) -> t.Optional[t.Dict]:
@@ -534,8 +535,8 @@ class NativeBridgeProvider(Provider):
534
535
  from_ledger_api=from_ledger_api, provider_request=provider_request
535
536
  )
536
537
 
537
- Provider._update_with_gas_pricing(bridge_tx, from_ledger_api)
538
- Provider._update_with_gas_estimate(bridge_tx, from_ledger_api)
538
+ update_tx_with_gas_pricing(bridge_tx, from_ledger_api)
539
+ update_tx_with_gas_estimate(bridge_tx, from_ledger_api)
539
540
  return bridge_tx
540
541
 
541
542
  def _get_txs(
@@ -28,7 +28,6 @@ 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
32
31
 
33
32
  from aea.crypto.base import LedgerApi
34
33
  from autonomy.chain.tx import TxSettler
@@ -41,16 +40,12 @@ from operate.constants import (
41
40
  ON_CHAIN_INTERACT_TIMEOUT,
42
41
  ZERO_ADDRESS,
43
42
  )
43
+ from operate.ledger import update_tx_with_gas_pricing
44
44
  from operate.operate_types import Chain
45
45
  from operate.resource import LocalResource
46
46
  from operate.wallet.master import MasterWalletManager
47
47
 
48
48
 
49
- GAS_ESTIMATE_FALLBACK_ADDRESSES = [
50
- "0x000000000000000000000000000000000000dEaD",
51
- "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", # nosec
52
- ]
53
-
54
49
  DEFAULT_MAX_QUOTE_RETRIES = 3
55
50
  PROVIDER_REQUEST_PREFIX = "r-"
56
51
  MESSAGE_QUOTE_ZERO = "Zero-amount quote requested."
@@ -66,8 +61,6 @@ MESSAGE_REQUIREMENTS_QUOTE_FAILED = "Cannot compute requirements for failed quot
66
61
 
67
62
  ERC20_APPROVE_SELECTOR = "0x095ea7b3" # First 4 bytes of Web3.keccak(text='approve(address,uint256)').hex()[:10]
68
63
 
69
- GAS_ESTIMATE_BUFFER = 1.10
70
-
71
64
 
72
65
  @dataclass
73
66
  class QuoteData(LocalResource):
@@ -291,7 +284,7 @@ class Provider(ABC):
291
284
  self.logger.debug(
292
285
  f"[PROVIDER] Processing transaction {tx_label} for request {provider_request.id}."
293
286
  )
294
- self._update_with_gas_pricing(tx, from_ledger_api)
287
+ update_tx_with_gas_pricing(tx, from_ledger_api)
295
288
  gas_key = "gasPrice" if "gasPrice" in tx else "maxFeePerGas"
296
289
  gas_fees = tx.get(gas_key, 0) * tx["gas"]
297
290
  tx_value = int(tx.get("value", 0))
@@ -487,48 +480,3 @@ class Provider(ABC):
487
480
  receipt = ledger_api.api.eth.get_transaction_receipt(tx_hash)
488
481
  block = ledger_api.api.eth.get_block(receipt.blockNumber)
489
482
  return block.timestamp
490
-
491
- # TODO backport to open aea/autonomy
492
- # TODO This gas pricing management should possibly be done at a lower level in the library
493
- @staticmethod
494
- def _update_with_gas_pricing(tx: t.Dict, ledger_api: LedgerApi) -> None:
495
- tx.pop("maxFeePerGas", None)
496
- tx.pop("gasPrice", None)
497
- tx.pop("maxPriorityFeePerGas", None)
498
-
499
- gas_pricing = ledger_api.try_get_gas_pricing()
500
- if gas_pricing is None:
501
- raise RuntimeError("Unable to retrieve gas pricing.")
502
-
503
- if "maxFeePerGas" in gas_pricing and "maxPriorityFeePerGas" in gas_pricing:
504
- tx["maxFeePerGas"] = gas_pricing["maxFeePerGas"]
505
- tx["maxPriorityFeePerGas"] = gas_pricing["maxPriorityFeePerGas"]
506
- elif "gasPrice" in gas_pricing:
507
- tx["gasPrice"] = gas_pricing["gasPrice"]
508
- else:
509
- raise RuntimeError("Retrieved invalid gas pricing.")
510
-
511
- # TODO backport to open aea/autonomy
512
- @staticmethod
513
- def _update_with_gas_estimate(tx: t.Dict, ledger_api: LedgerApi) -> None:
514
- print(
515
- f"[PROVIDER] Trying to update transaction gas {tx['from']=} {tx['gas']=}."
516
- )
517
- original_from = tx["from"]
518
- original_gas = tx.get("gas", 1)
519
-
520
- for address in [original_from] + GAS_ESTIMATE_FALLBACK_ADDRESSES:
521
- tx["from"] = address
522
- tx["gas"] = 1
523
- ledger_api.update_with_gas_estimate(tx)
524
- if tx["gas"] > 1:
525
- print(
526
- f"[PROVIDER] Gas estimated successfully {tx['from']=} {tx['gas']=}."
527
- )
528
- break
529
-
530
- tx["from"] = original_from
531
- if tx["gas"] == 1:
532
- tx["gas"] = original_gas
533
- print(f"[PROVIDER] Unable to estimate gas. Restored {tx['gas']=}.")
534
- tx["gas"] = ceil(tx["gas"] * GAS_ESTIMATE_BUFFER)
@@ -39,6 +39,7 @@ from operate.bridge.providers.provider import (
39
39
  ProviderRequestStatus,
40
40
  QuoteData,
41
41
  )
42
+ from operate.ledger import update_tx_with_gas_estimate, update_tx_with_gas_pricing
42
43
  from operate.operate_types import Chain
43
44
 
44
45
 
@@ -258,10 +259,10 @@ class RelayProvider(Provider):
258
259
  timestamp=int(time.time()),
259
260
  )
260
261
  except requests.RequestException as e:
262
+ response_json = response.json()
261
263
  self.logger.warning(
262
- f"[RELAY PROVIDER] Request failed on attempt {attempt}/{DEFAULT_MAX_QUOTE_RETRIES}: {e}."
264
+ f"[RELAY PROVIDER] Request failed on attempt {attempt}/{DEFAULT_MAX_QUOTE_RETRIES}: {response_json}."
263
265
  )
264
- response_json = response.json()
265
266
  quote_data = QuoteData(
266
267
  eta=None,
267
268
  elapsed_time=time.time() - start,
@@ -338,8 +339,8 @@ class RelayProvider(Provider):
338
339
  tx["maxFeePerGas"] = int(tx.get("maxFeePerGas", 0))
339
340
  tx["maxPriorityFeePerGas"] = int(tx.get("maxPriorityFeePerGas", 0))
340
341
  tx["nonce"] = from_ledger_api.api.eth.get_transaction_count(tx["from"])
341
- Provider._update_with_gas_pricing(tx, from_ledger_api)
342
- Provider._update_with_gas_estimate(tx, from_ledger_api)
342
+ update_tx_with_gas_pricing(tx, from_ledger_api)
343
+ update_tx_with_gas_estimate(tx, from_ledger_api)
343
344
  txs.append((f"{step['id']}-{i}", tx))
344
345
 
345
346
  return txs
@@ -36,8 +36,6 @@ import psutil
36
36
  import requests
37
37
  from aea.helpers.logging import setup_logger
38
38
  from clea import group, params, run
39
- from compose.project import ProjectError
40
- from docker.errors import APIError
41
39
  from fastapi import FastAPI, Request
42
40
  from fastapi.middleware.cors import CORSMiddleware
43
41
  from fastapi.responses import JSONResponse
@@ -415,37 +413,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
415
413
  allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
416
414
  )
417
415
 
418
- def with_retries(f: t.Callable) -> t.Callable:
419
- """Retries decorator."""
420
-
421
- async def _call(request: Request) -> JSONResponse:
422
- """Call the endpoint."""
423
- logger.info(f"Calling `{f.__name__}` with retries enabled")
424
- retries = 0
425
- while retries < DEFAULT_MAX_RETRIES:
426
- try:
427
- return await f(request)
428
- except (APIError, ProjectError) as e:
429
- logger.error(f"Error {e}\n{traceback.format_exc()}")
430
- if "has active endpoints" in str(e):
431
- error_msg = "Service is already running."
432
- else:
433
- error_msg = "Service deployment failed. Please check the logs."
434
- return JSONResponse(
435
- content={"error": error_msg},
436
- status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
437
- )
438
- except Exception as e: # pylint: disable=broad-except
439
- logger.error(f"Error {str(e)}\n{traceback.format_exc()}")
440
- retries += 1
416
+ @app.middleware("http")
417
+ async def handle_internal_server_error(request: Request, call_next):
418
+ try:
419
+ response = await call_next(request)
420
+ except Exception as e: # pylint: disable=broad-except
421
+ logger.error(f"Error {str(e)}\n{traceback.format_exc()}")
441
422
  return JSONResponse(
442
- content={
443
- "error": "Operation failed after multiple attempts. Please try again later."
444
- },
423
+ content={"error": str(e)},
445
424
  status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
446
425
  )
447
-
448
- return _call
426
+ return response
449
427
 
450
428
  @app.get(f"/{shutdown_endpoint}")
451
429
  async def _kill_server(request: Request) -> JSONResponse:
@@ -464,19 +442,16 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
464
442
  return JSONResponse(content={"stopped": True})
465
443
 
466
444
  @app.get("/api")
467
- @with_retries
468
445
  async def _get_api(request: Request) -> JSONResponse:
469
446
  """Get API info."""
470
447
  return JSONResponse(content=operate.json)
471
448
 
472
449
  @app.get("/api/account")
473
- @with_retries
474
450
  async def _get_account(request: Request) -> t.Dict:
475
451
  """Get account information."""
476
452
  return {"is_setup": operate.user_account is not None}
477
453
 
478
454
  @app.post("/api/account")
479
- @with_retries
480
455
  async def _setup_account(request: Request) -> t.Dict:
481
456
  """Setup account."""
482
457
  if operate.user_account is not None:
@@ -498,7 +473,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
498
473
  return JSONResponse(content={"error": None})
499
474
 
500
475
  @app.put("/api/account")
501
- @with_retries
502
476
  async def _update_password( # pylint: disable=too-many-return-statements
503
477
  request: Request,
504
478
  ) -> t.Dict:
@@ -568,7 +542,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
568
542
  )
569
543
 
570
544
  @app.post("/api/account/login")
571
- @with_retries
572
545
  async def _validate_password(request: Request) -> t.Dict:
573
546
  """Validate password."""
574
547
  if operate.user_account is None:
@@ -588,7 +561,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
588
561
  )
589
562
 
590
563
  @app.get("/api/wallet")
591
- @with_retries
592
564
  async def _get_wallets(request: Request) -> t.List[t.Dict]:
593
565
  """Get wallets."""
594
566
  wallets = []
@@ -597,7 +569,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
597
569
  return JSONResponse(content=wallets)
598
570
 
599
571
  @app.post("/api/wallet")
600
- @with_retries
601
572
  async def _create_wallet(request: Request) -> t.List[t.Dict]:
602
573
  """Create wallet"""
603
574
  if operate.user_account is None:
@@ -620,7 +591,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
620
591
  return JSONResponse(content={"wallet": wallet.json, "mnemonic": mnemonic})
621
592
 
622
593
  @app.post("/api/wallet/private_key")
623
- @with_retries
624
594
  async def _get_private_key(request: Request) -> t.List[t.Dict]:
625
595
  """Get Master EOA private key."""
626
596
  if operate.user_account is None:
@@ -641,7 +611,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
641
611
  return JSONResponse(content={"private_key": wallet.crypto.private_key})
642
612
 
643
613
  @app.get("/api/extended/wallet")
644
- @with_retries
645
614
  async def _get_wallet_safe(request: Request) -> t.List[t.Dict]:
646
615
  """Get wallets."""
647
616
  wallets = []
@@ -650,7 +619,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
650
619
  return JSONResponse(content=wallets)
651
620
 
652
621
  @app.get("/api/wallet/safe")
653
- @with_retries
654
622
  async def _get_safes(request: Request) -> t.List[t.Dict]:
655
623
  """Create wallet safe"""
656
624
  all_safes = []
@@ -662,7 +630,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
662
630
  return JSONResponse(content=all_safes)
663
631
 
664
632
  @app.get("/api/wallet/safe/{chain}")
665
- @with_retries
666
633
  async def _get_safe(request: Request) -> t.List[t.Dict]:
667
634
  """Get safe address"""
668
635
  chain = Chain.from_string(request.path_params["chain"])
@@ -792,7 +759,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
792
759
  )
793
760
 
794
761
  @app.put("/api/wallet/safe")
795
- @with_retries
796
762
  async def _update_safe(request: Request) -> t.List[t.Dict]:
797
763
  """Update wallet safe"""
798
764
  # TODO: Extract login check as decorator
@@ -845,13 +811,11 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
845
811
  )
846
812
 
847
813
  @app.get("/api/v2/services")
848
- @with_retries
849
814
  async def _get_services(request: Request) -> JSONResponse:
850
815
  """Get all services."""
851
816
  return JSONResponse(content=operate.service_manager().json)
852
817
 
853
818
  @app.get("/api/v2/services/validate")
854
- @with_retries
855
819
  async def _validate_services(request: Request) -> JSONResponse:
856
820
  """Validate all services."""
857
821
  service_manager = operate.service_manager()
@@ -866,7 +830,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
866
830
  )
867
831
 
868
832
  @app.get("/api/v2/services/deployment")
869
- @with_retries
870
833
  async def _get_services_deployment(request: Request) -> JSONResponse:
871
834
  """Get a service deployment."""
872
835
  service_manager = operate.service_manager()
@@ -879,7 +842,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
879
842
  return JSONResponse(content=output)
880
843
 
881
844
  @app.get("/api/v2/service/{service_config_id}")
882
- @with_retries
883
845
  async def _get_service(request: Request) -> JSONResponse:
884
846
  """Get a service."""
885
847
  service_config_id = request.path_params["service_config_id"]
@@ -897,7 +859,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
897
859
  )
898
860
 
899
861
  @app.get("/api/v2/service/{service_config_id}/deployment")
900
- @with_retries
901
862
  async def _get_service_deployment(request: Request) -> JSONResponse:
902
863
  """Get a service deployment."""
903
864
  service_config_id = request.path_params["service_config_id"]
@@ -911,7 +872,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
911
872
  return JSONResponse(content=deployment_json)
912
873
 
913
874
  @app.get("/api/v2/service/{service_config_id}/agent_performance")
914
- @with_retries
915
875
  async def _get_agent_performance(request: Request) -> JSONResponse:
916
876
  """Get the service refill requirements."""
917
877
  service_config_id = request.path_params["service_config_id"]
@@ -926,7 +886,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
926
886
  )
927
887
 
928
888
  @app.get("/api/v2/service/{service_config_id}/refill_requirements")
929
- @with_retries
930
889
  async def _get_refill_requirements(request: Request) -> JSONResponse:
931
890
  """Get the service refill requirements."""
932
891
  service_config_id = request.path_params["service_config_id"]
@@ -941,7 +900,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
941
900
  )
942
901
 
943
902
  @app.post("/api/v2/service")
944
- @with_retries
945
903
  async def _create_services_v2(request: Request) -> JSONResponse:
946
904
  """Create a service."""
947
905
  if operate.password is None:
@@ -953,7 +911,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
953
911
  return JSONResponse(content=output.json)
954
912
 
955
913
  @app.post("/api/v2/service/{service_config_id}")
956
- @with_retries
957
914
  async def _deploy_and_run_service(request: Request) -> JSONResponse:
958
915
  """Deploy a service."""
959
916
  if operate.password is None:
@@ -986,7 +943,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
986
943
 
987
944
  @app.put("/api/v2/service/{service_config_id}")
988
945
  @app.patch("/api/v2/service/{service_config_id}")
989
- @with_retries
990
946
  async def _update_service(request: Request) -> JSONResponse:
991
947
  """Update a service."""
992
948
  if operate.password is None:
@@ -1022,7 +978,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1022
978
  return JSONResponse(content=output.json)
1023
979
 
1024
980
  @app.post("/api/v2/service/{service_config_id}/deployment/stop")
1025
- @with_retries
1026
981
  async def _stop_service_locally(request: Request) -> JSONResponse:
1027
982
  """Stop a service deployment."""
1028
983
 
@@ -1045,7 +1000,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1045
1000
  return JSONResponse(content=deployment.json)
1046
1001
 
1047
1002
  @app.post("/api/v2/service/{service_config_id}/onchain/withdraw")
1048
- @with_retries
1049
1003
  async def _withdraw_onchain(request: Request) -> JSONResponse:
1050
1004
  """Withdraw all the funds from a service."""
1051
1005
 
@@ -1114,7 +1068,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1114
1068
  return JSONResponse(content={"error": None, "message": "Withdrawal successful"})
1115
1069
 
1116
1070
  @app.post("/api/bridge/bridge_refill_requirements")
1117
- @with_retries
1118
1071
  async def _bridge_refill_requirements(request: Request) -> JSONResponse:
1119
1072
  """Get the bridge refill requirements."""
1120
1073
  if operate.password is None:
@@ -1149,7 +1102,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1149
1102
  )
1150
1103
 
1151
1104
  @app.post("/api/bridge/execute")
1152
- @with_retries
1153
1105
  async def _bridge_execute(request: Request) -> JSONResponse:
1154
1106
  """Execute bridge transaction."""
1155
1107
  if operate.password is None:
@@ -1179,14 +1131,12 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1179
1131
  )
1180
1132
 
1181
1133
  @app.get("/api/bridge/last_executed_bundle_id")
1182
- @with_retries
1183
1134
  async def _bridge_last_executed_bundle_id(request: Request) -> t.List[t.Dict]:
1184
1135
  """Get last executed bundle id."""
1185
1136
  content = {"id": operate.bridge_manager.last_executed_bundle_id()}
1186
1137
  return JSONResponse(content=content, status_code=HTTPStatus.OK)
1187
1138
 
1188
1139
  @app.get("/api/bridge/status/{id}")
1189
- @with_retries
1190
1140
  async def _bridge_status(request: Request) -> JSONResponse:
1191
1141
  """Get bridge transaction status."""
1192
1142
 
@@ -1215,7 +1165,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1215
1165
  )
1216
1166
 
1217
1167
  @app.post("/api/wallet/recovery/initiate")
1218
- @with_retries
1219
1168
  async def _wallet_recovery_initiate(request: Request) -> JSONResponse:
1220
1169
  """Initiate wallet recovery."""
1221
1170
  if operate.user_account is None:
@@ -1259,7 +1208,6 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
1259
1208
  )
1260
1209
 
1261
1210
  @app.post("/api/wallet/recovery/complete")
1262
- @with_retries
1263
1211
  async def _wallet_recovery_complete(request: Request) -> JSONResponse:
1264
1212
  """Complete wallet recovery."""
1265
1213
  if operate.user_account is None:
@@ -42,8 +42,8 @@ AGENT_LOG_ENV_VAR = "LOG_DIR"
42
42
  ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
43
43
 
44
44
  ON_CHAIN_INTERACT_TIMEOUT = 120.0
45
- ON_CHAIN_INTERACT_RETRIES = 10
46
- ON_CHAIN_INTERACT_SLEEP = 3.0
45
+ ON_CHAIN_INTERACT_RETRIES = 12
46
+ ON_CHAIN_INTERACT_SLEEP = 5.0
47
47
  MIN_PASSWORD_LENGTH = 8
48
48
 
49
49
  HEALTH_CHECK_URL = "http://127.0.0.1:8716/healthcheck" # possible DNS issues on windows so use IP address
@@ -76,6 +76,19 @@ class KeysManager(metaclass=SingletonMeta):
76
76
  )
77
77
  )
78
78
 
79
+ def get_private_key_file(self, address: str) -> Path:
80
+ """Get the path to the private key file for the given address."""
81
+ path = self.path / f"{address}_private_key"
82
+
83
+ if path.is_file():
84
+ return path
85
+
86
+ key = self.get(address)
87
+ private_key = key.private_key
88
+ path.write_text(private_key, encoding="utf-8")
89
+ os.chmod(path, 0o600)
90
+ return path
91
+
79
92
  def get_crypto_instance(self, address: str) -> EthereumCrypto:
80
93
  """Get EthereumCrypto instance for the given address."""
81
94
  key: Key = Key.from_json( # type: ignore
@@ -20,6 +20,10 @@
20
20
  """Ledger helpers."""
21
21
 
22
22
  import os
23
+ import typing as t
24
+ from math import ceil
25
+
26
+ from aea.crypto.base import LedgerApi
23
27
 
24
28
  from operate.operate_types import Chain
25
29
 
@@ -99,3 +103,54 @@ def get_currency_denom(chain: Chain) -> str:
99
103
  def get_currency_smallest_unit(chain: Chain) -> str:
100
104
  """Get currency denom by chain type."""
101
105
  return CURRENCY_SMALLEST_UNITS.get(chain, "Wei")
106
+
107
+
108
+ GAS_ESTIMATE_FALLBACK_ADDRESSES = [
109
+ "0x000000000000000000000000000000000000dEaD",
110
+ "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", # nosec
111
+ ]
112
+ GAS_ESTIMATE_BUFFER = 1.10
113
+
114
+
115
+ # TODO backport to open aea/autonomy
116
+ # TODO This gas pricing management should be done at a lower level in the library
117
+ def update_tx_with_gas_pricing(tx: t.Dict, ledger_api: LedgerApi) -> None:
118
+ """Update transaction with gas pricing."""
119
+ tx.pop("maxFeePerGas", None)
120
+ tx.pop("gasPrice", None)
121
+ tx.pop("maxPriorityFeePerGas", None)
122
+
123
+ gas_pricing = ledger_api.try_get_gas_pricing()
124
+ if gas_pricing is None:
125
+ raise RuntimeError("Unable to retrieve gas pricing.")
126
+
127
+ if "maxFeePerGas" in gas_pricing and "maxPriorityFeePerGas" in gas_pricing:
128
+ tx["maxFeePerGas"] = gas_pricing["maxFeePerGas"]
129
+ tx["maxPriorityFeePerGas"] = gas_pricing["maxPriorityFeePerGas"]
130
+ elif "gasPrice" in gas_pricing:
131
+ tx["gasPrice"] = gas_pricing["gasPrice"]
132
+ else:
133
+ raise RuntimeError("Retrieved invalid gas pricing.")
134
+
135
+
136
+ # TODO backport to open aea/autonomy
137
+ # TODO This gas management should be done at a lower level in the library
138
+ def update_tx_with_gas_estimate(tx: t.Dict, ledger_api: LedgerApi) -> None:
139
+ """Update transaction with gas estimate."""
140
+ print(f"[PROVIDER] Trying to update transaction gas {tx['from']=} {tx['gas']=}.")
141
+ original_from = tx["from"]
142
+ original_gas = tx.get("gas", 1)
143
+
144
+ for address in [original_from] + GAS_ESTIMATE_FALLBACK_ADDRESSES:
145
+ tx["from"] = address
146
+ tx["gas"] = 1
147
+ ledger_api.update_with_gas_estimate(tx)
148
+ if tx["gas"] > 1:
149
+ print(f"[PROVIDER] Gas estimated successfully {tx['from']=} {tx['gas']=}.")
150
+ break
151
+
152
+ tx["from"] = original_from
153
+ if tx["gas"] == 1:
154
+ tx["gas"] = original_gas
155
+ print(f"[PROVIDER] Unable to estimate gas. Restored {tx['gas']=}.")
156
+ tx["gas"] = ceil(tx["gas"] * GAS_ESTIMATE_BUFFER)
@@ -34,12 +34,7 @@ from halo import Halo # type: ignore[import]
34
34
  from web3.exceptions import Web3Exception
35
35
 
36
36
  from operate.account.user import UserAccount
37
- from operate.constants import (
38
- IPFS_ADDRESS,
39
- NO_STAKING_PROGRAM_ID,
40
- OPERATE_HOME,
41
- USER_JSON,
42
- )
37
+ from operate.constants import IPFS_ADDRESS, NO_STAKING_PROGRAM_ID, USER_JSON
43
38
  from operate.data import DATA_DIR
44
39
  from operate.data.contracts.staking_token.contract import StakingTokenContract
45
40
  from operate.ledger.profiles import STAKING, get_staking_contract
@@ -145,7 +140,8 @@ def ask_confirm_password() -> str:
145
140
 
146
141
  def load_local_config(operate: "OperateApp", service_name: str) -> QuickstartConfig:
147
142
  """Load the local quickstart configuration."""
148
- old_path = OPERATE_HOME / "local_config.json"
143
+ operate_home = operate._path
144
+ old_path = operate_home / "local_config.json"
149
145
  if old_path.exists(): # Migrate to new naming scheme
150
146
  config = t.cast(QuickstartConfig, QuickstartConfig.load(old_path))
151
147
  service_manager = operate.service_manager()
@@ -178,13 +174,13 @@ def load_local_config(operate: "OperateApp", service_name: str) -> QuickstartCon
178
174
  shutil.move(old_path, config.path)
179
175
  break
180
176
 
181
- for qs_config in OPERATE_HOME.glob("*-quickstart-config.json"):
177
+ for qs_config in operate_home.glob("*-quickstart-config.json"):
182
178
  if f"{service_name}-quickstart-config.json" == qs_config.name:
183
179
  config = t.cast(QuickstartConfig, QuickstartConfig.load(qs_config))
184
180
  break
185
181
  else:
186
182
  config = QuickstartConfig(
187
- OPERATE_HOME / f"{service_name}-quickstart-config.json"
183
+ operate_home / f"{service_name}-quickstart-config.json"
188
184
  )
189
185
 
190
186
  return config
@@ -65,10 +65,10 @@ class AgentRelease:
65
65
  # list of agents releases supported
66
66
  AGENTS_SUPPORTED = {
67
67
  "valory/trader": AgentRelease(
68
- owner="valory-xyz", repo="trader", release="v0.0.101"
68
+ owner="valory-xyz", repo="trader", release="v0.27.2-rc.1"
69
69
  ),
70
70
  "valory/optimus": AgentRelease(
71
- owner="valory-xyz", repo="optimus", release="v0.0.103"
71
+ owner="valory-xyz", repo="optimus", release="v0.0.1051"
72
72
  ),
73
73
  "dvilela/memeooorr": AgentRelease(
74
74
  owner="valory-xyz", repo="meme-ooorr", release="v0.0.101"
@@ -36,10 +36,10 @@ from operate.services.manage import ServiceManager # type: ignore
36
36
  class HealthChecker:
37
37
  """Health checker manager."""
38
38
 
39
- SLEEP_PERIOD_DEFAULT = 30
39
+ SLEEP_PERIOD_DEFAULT = 5 # seconds
40
40
  PORT_UP_TIMEOUT_DEFAULT = 300 # seconds
41
- REQUEST_TIMEOUT_DEFAULT = 90
42
- NUMBER_OF_FAILS_DEFAULT = 10
41
+ REQUEST_TIMEOUT_DEFAULT = 90 # seconds
42
+ NUMBER_OF_FAILS_DEFAULT = 60
43
43
 
44
44
  def __init__(
45
45
  self,
@@ -180,7 +180,7 @@ class HealthChecker:
180
180
  f"[HEALTH_CHECKER] {service_config_id} not healthy for {fails} time in a row"
181
181
  )
182
182
  else:
183
- self.logger.info(
183
+ self.logger.debug(
184
184
  f"[HEALTH_CHECKER] {service_config_id} is HEALTHY"
185
185
  )
186
186
  # reset fails if comes healty
@@ -415,18 +415,26 @@ class ServiceManager:
415
415
  and (
416
416
  on_chain_hash != service.hash
417
417
  or current_agent_id != staking_params["agent_ids"][0]
418
- or current_agent_bond != staking_params["min_staking_deposit"]
418
+ or (
419
+ user_params.use_staking
420
+ and current_agent_bond != staking_params["min_staking_deposit"]
421
+ )
422
+ # TODO Missing complete this check for non-staked services it should compare the current_agent_bond from the protocol, now it's only read for the staking contract.
419
423
  or on_chain_description != service.description
420
424
  )
421
425
  )
422
426
  current_staking_program = self._get_current_staking_program(service, chain)
423
427
 
428
+ self.logger.info(f"{chain_data.token=}")
429
+ self.logger.info(f"{user_params.use_staking=}")
424
430
  self.logger.info(f"{current_staking_program=}")
425
431
  self.logger.info(f"{user_params.staking_program_id=}")
426
432
  self.logger.info(f"{on_chain_hash=}")
427
433
  self.logger.info(f"{service.hash=}")
428
434
  self.logger.info(f"{current_agent_id=}")
429
- self.logger.info(f"{staking_params['agent_ids'][0]=}")
435
+ self.logger.info(f"{staking_params['agent_ids']=}")
436
+ self.logger.info(f"{current_agent_bond=}")
437
+ self.logger.info(f"{staking_params['min_staking_deposit']=}")
430
438
  self.logger.info(f"{is_first_mint=}")
431
439
  self.logger.info(f"{is_update=}")
432
440
 
@@ -815,7 +823,12 @@ class ServiceManager:
815
823
  # on_chain_hash != service.hash or # noqa
816
824
  current_agent_id != target_staking_params["agent_ids"][0]
817
825
  # TODO This has to be removed for Optimus (needs to be properly implemented). Needs to be put back for Trader!
818
- or current_agent_bond != target_staking_params["min_staking_deposit"]
826
+ or (
827
+ user_params.use_staking
828
+ and current_agent_bond
829
+ != target_staking_params["min_staking_deposit"]
830
+ )
831
+ # TODO Missing complete this check for non-staked services it should compare the current_agent_bond from the protocol, now it's only read for the staking contract.
819
832
  or current_staking_params["staking_token"]
820
833
  != target_staking_params["staking_token"]
821
834
  or on_chain_description != service.description
@@ -823,12 +836,13 @@ class ServiceManager:
823
836
  )
824
837
 
825
838
  self.logger.info(f"{chain_data.token=}")
839
+ self.logger.info(f"{user_params.use_staking=}")
826
840
  self.logger.info(f"{current_staking_program=}")
827
841
  self.logger.info(f"{user_params.staking_program_id=}")
828
842
  self.logger.info(f"{on_chain_hash=}")
829
843
  self.logger.info(f"{service.hash=}")
830
844
  self.logger.info(f"{current_agent_id=}")
831
- self.logger.info(f"{target_staking_params['agent_ids'][0]=}")
845
+ self.logger.info(f"{target_staking_params['agent_ids']=}")
832
846
  self.logger.info(f"{current_agent_bond=}")
833
847
  self.logger.info(f"{target_staking_params['min_staking_deposit']=}")
834
848
  self.logger.info(f"{is_first_mint=}")
@@ -19,7 +19,6 @@
19
19
 
20
20
  """Helper utilities."""
21
21
 
22
- import functools
23
22
  import shutil
24
23
  import time
25
24
  import typing as t
@@ -32,34 +31,6 @@ class SingletonMeta(type):
32
31
 
33
32
  _instances: t.Dict[t.Type, t.Any] = {}
34
33
  _lock: Lock = Lock()
35
- _class_locks: t.Dict[t.Type, Lock] = {}
36
-
37
- def __new__(
38
- cls, name: str, bases: t.Tuple[type, ...], dct: t.Dict[str, t.Any]
39
- ) -> t.Type:
40
- """Create a new class with thread-safe methods."""
41
- # Wrap all callable methods (except special methods) with thread safety
42
- for key, value in list(dct.items()):
43
- if callable(value) and not key.startswith("__"):
44
- dct[key] = cls._make_thread_safe(value)
45
-
46
- new_class = super().__new__(cls, name, bases, dct)
47
- cls._class_locks[new_class] = Lock()
48
- return new_class
49
-
50
- @staticmethod
51
- def _make_thread_safe(func: t.Callable) -> t.Callable:
52
- """Wrap a function to make it thread-safe."""
53
-
54
- @functools.wraps(func)
55
- def wrapper(self: t.Any, *args: t.Any, **kwargs: t.Any) -> t.Any:
56
- class_lock = SingletonMeta._class_locks.get(type(self))
57
- if class_lock:
58
- with class_lock:
59
- return func(self, *args, **kwargs)
60
- return func(self, *args, **kwargs)
61
-
62
- return wrapper
63
34
 
64
35
  def __call__(cls, *args: t.Any, **kwargs: t.Any) -> t.Any:
65
36
  """Override the __call__ method to control instance creation."""
@@ -42,7 +42,11 @@ from operate.constants import (
42
42
  ON_CHAIN_INTERACT_TIMEOUT,
43
43
  ZERO_ADDRESS,
44
44
  )
45
- from operate.ledger import get_default_rpc
45
+ from operate.ledger import (
46
+ get_default_rpc,
47
+ update_tx_with_gas_estimate,
48
+ update_tx_with_gas_pricing,
49
+ )
46
50
  from operate.ledger.profiles import ERC20_TOKENS, OLAS, USDC
47
51
  from operate.operate_types import Chain, LedgerType
48
52
  from operate.resource import LocalResource
@@ -357,10 +361,9 @@ class EthereumMasterWallet(MasterWallet):
357
361
  "nonce": ledger_api.api.eth.get_transaction_count(wallet_address),
358
362
  }
359
363
  )
360
- return ledger_api.update_with_gas_estimate(
361
- transaction=tx,
362
- raise_on_try=False,
363
- )
364
+ update_tx_with_gas_pricing(tx, ledger_api)
365
+ update_tx_with_gas_estimate(tx, ledger_api)
366
+ return tx
364
367
 
365
368
  setattr(tx_settler, "build", _build_transfer_tx) # noqa: B010
366
369
  tx_receipt = tx_settler.transact(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "olas-operate-middleware"
3
- version = "0.10.18"
3
+ version = "0.10.20"
4
4
  description = ""
5
5
  authors = ["David Vilela <dvilelaf@gmail.com>", "Viraj Patel <vptl185@gmail.com>"]
6
6
  readme = "README.md"