olas-operate-middleware 0.8.2__tar.gz → 0.14.7__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 (104) hide show
  1. olas_operate_middleware-0.14.7/PKG-INFO +56 -0
  2. olas_operate_middleware-0.14.7/operate/__init__.py +71 -0
  3. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/bridge/bridge_manager.py +67 -60
  4. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/bridge/providers/lifi_provider.py +5 -4
  5. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/bridge/providers/native_bridge_provider.py +32 -18
  6. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/bridge/providers/provider.py +76 -132
  7. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/bridge/providers/relay_provider.py +31 -7
  8. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/cli.py +791 -173
  9. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/constants.py +47 -12
  10. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/dual_staking_token/contract.py +3 -3
  11. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/dual_staking_token/contract.yaml +2 -2
  12. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/foreign_omnibridge/contract.yaml +1 -1
  13. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/home_omnibridge/contract.py +2 -2
  14. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/home_omnibridge/contract.yaml +2 -2
  15. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l1_standard_bridge/contract.py +20 -0
  16. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l1_standard_bridge/contract.yaml +2 -2
  17. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l2_standard_bridge/contract.py +4 -4
  18. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l2_standard_bridge/contract.yaml +2 -2
  19. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/mech_activity/contract.yaml +1 -1
  20. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/optimism_mintable_erc20/contract.yaml +1 -1
  21. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/requester_activity_checker/contract.yaml +1 -1
  22. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/staking_token/contract.py +3 -3
  23. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/staking_token/contract.yaml +2 -2
  24. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/contract.yaml +3 -3
  25. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py +5 -5
  26. olas_operate_middleware-0.14.7/operate/keys.py +193 -0
  27. olas_operate_middleware-0.14.7/operate/ledger/__init__.py +196 -0
  28. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/ledger/profiles.py +183 -74
  29. olas_operate_middleware-0.14.7/operate/migration.py +555 -0
  30. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/operate_http/__init__.py +0 -2
  31. olas_operate_middleware-0.14.7/operate/operate_types.py +504 -0
  32. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/analyse_logs.py +3 -6
  33. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/claim_staking_rewards.py +12 -26
  34. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/reset_configs.py +1 -4
  35. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/reset_password.py +5 -12
  36. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/reset_staking.py +5 -6
  37. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/run_service.py +124 -32
  38. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/stop_service.py +11 -5
  39. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/terminate_on_chain_service.py +1 -4
  40. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/quickstart/utils.py +44 -19
  41. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/resource.py +32 -65
  42. olas_operate_middleware-0.14.7/operate/serialization.py +113 -0
  43. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/agent_runner.py +23 -31
  44. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/deployment_runner.py +348 -120
  45. olas_operate_middleware-0.14.7/operate/services/funding_manager.py +1013 -0
  46. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/health_checker.py +52 -17
  47. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/manage.py +558 -474
  48. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/protocol.py +684 -358
  49. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/service.py +391 -328
  50. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/utils/mech.py +3 -3
  51. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/utils/tendermint.py +5 -3
  52. olas_operate_middleware-0.14.7/operate/settings.py +73 -0
  53. olas_operate_middleware-0.14.7/operate/utils/__init__.py +264 -0
  54. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/utils/gnosis.py +144 -130
  55. olas_operate_middleware-0.14.7/operate/utils/single_instance.py +226 -0
  56. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/wallet/master.py +314 -252
  57. olas_operate_middleware-0.14.7/operate/wallet/wallet_recovery_manager.py +510 -0
  58. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/pyproject.toml +14 -28
  59. olas_operate_middleware-0.8.2/PKG-INFO +0 -72
  60. olas_operate_middleware-0.8.2/operate/__init__.py +0 -25
  61. olas_operate_middleware-0.8.2/operate/keys.py +0 -135
  62. olas_operate_middleware-0.8.2/operate/ledger/__init__.py +0 -98
  63. olas_operate_middleware-0.8.2/operate/migration.py +0 -63
  64. olas_operate_middleware-0.8.2/operate/operate_types.py +0 -341
  65. olas_operate_middleware-0.8.2/operate/utils/__init__.py +0 -94
  66. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/LICENSE +0 -0
  67. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/README.md +0 -0
  68. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/account/__init__.py +0 -0
  69. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/account/user.py +0 -0
  70. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/README.md +0 -0
  71. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/__init__.py +0 -0
  72. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/__init__.py +0 -0
  73. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/dual_staking_token/__init__.py +0 -0
  74. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/dual_staking_token/build/DualStakingToken.json +0 -0
  75. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/foreign_omnibridge/__init__.py +0 -0
  76. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/foreign_omnibridge/build/ForeignOmnibridge.json +0 -0
  77. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/foreign_omnibridge/contract.py +0 -0
  78. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/home_omnibridge/__init__.py +0 -0
  79. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/home_omnibridge/build/HomeOmnibridge.json +0 -0
  80. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l1_standard_bridge/__init__.py +0 -0
  81. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l1_standard_bridge/build/L1StandardBridge.json +0 -0
  82. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l2_standard_bridge/__init__.py +0 -0
  83. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/l2_standard_bridge/build/L2StandardBridge.json +0 -0
  84. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/mech_activity/__init__.py +0 -0
  85. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/mech_activity/build/MechActivity.json +0 -0
  86. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/mech_activity/contract.py +0 -0
  87. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/optimism_mintable_erc20/__init__.py +0 -0
  88. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/optimism_mintable_erc20/build/OptimismMintableERC20.json +0 -0
  89. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/optimism_mintable_erc20/contract.py +0 -0
  90. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/requester_activity_checker/__init__.py +0 -0
  91. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/requester_activity_checker/build/RequesterActivityChecker.json +0 -0
  92. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/requester_activity_checker/contract.py +0 -0
  93. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/staking_token/__init__.py +0 -0
  94. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/staking_token/build/StakingToken.json +0 -0
  95. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/__init__.py +0 -0
  96. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/build/IUniswapV2ERC20.json +0 -0
  97. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/contract.py +0 -0
  98. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py +0 -0
  99. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/operate_http/exceptions.py +0 -0
  100. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/pearl.py +0 -0
  101. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/__init__.py +0 -0
  102. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/services/utils/__init__.py +0 -0
  103. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/utils/ssl.py +0 -0
  104. {olas_operate_middleware-0.8.2 → olas_operate_middleware-0.14.7}/operate/wallet/__init__.py +0 -0
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: olas-operate-middleware
3
+ Version: 0.14.7
4
+ Summary:
5
+ License-File: LICENSE
6
+ Author: David Vilela
7
+ Author-email: dvilelaf@gmail.com
8
+ Requires-Python: >=3.10,<3.12
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: argon2-cffi (==23.1.0)
13
+ Requires-Dist: clea (==0.1.0rc4)
14
+ Requires-Dist: cryptography (>=46.0.3,<47.0.0)
15
+ Requires-Dist: cytoolz (==0.12.3)
16
+ Requires-Dist: deepdiff (>=8.6.1,<9.0.0)
17
+ Requires-Dist: fastapi (==0.110.3)
18
+ Requires-Dist: halo (==0.0.31)
19
+ Requires-Dist: multiaddr (==0.0.9)
20
+ Requires-Dist: open-aea-cli-ipfs (>=2.0.8,<3.0.0)
21
+ Requires-Dist: open-aea-ledger-cosmos (>=2.0.8,<3.0.0)
22
+ Requires-Dist: open-aea-ledger-ethereum (>=2.0.8,<3.0.0)
23
+ Requires-Dist: open-aea-ledger-ethereum-flashbots (>=2.0.8,<3.0.0)
24
+ Requires-Dist: open-autonomy (>=0.21.8,<0.22.0)
25
+ Requires-Dist: psutil (>=5.9.8,<6.0.0)
26
+ Requires-Dist: pyinstaller (>=6.8.0,<7.0.0)
27
+ Requires-Dist: requests-mock (>=1.12.1,<2.0.0)
28
+ Requires-Dist: uvicorn (==0.27.0)
29
+ Description-Content-Type: text/markdown
30
+
31
+ <h1 align="center">
32
+ <b>Olas Operate Middleware</b>
33
+ </h1>
34
+
35
+ A cross-platform python package used to run autonomous agents powered by the OLAS Network.
36
+
37
+ ## Getting Started
38
+
39
+ Install using
40
+ ```
41
+ pip install olas-operate-middleware
42
+ ```
43
+
44
+ Start the daemon service using
45
+ ```
46
+ python -m operate.cli daemon
47
+ ```
48
+
49
+ ## License
50
+
51
+ - [Apache 2.0](LICENSE)
52
+
53
+ ## Security
54
+
55
+ - [Security Policy](SECURITY.md)
56
+
@@ -0,0 +1,71 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ------------------------------------------------------------------------------
3
+ #
4
+ # Copyright 2023 Valory AG
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ # ------------------------------------------------------------------------------
19
+
20
+ """Operate app."""
21
+
22
+ import logging
23
+ import os
24
+ import platform
25
+ from importlib.metadata import PackageNotFoundError, version
26
+
27
+ import certifi
28
+
29
+
30
+ try:
31
+ # Prefer the distribution name if installed; fall back to the module name
32
+ __version__ = version("olas-operate-middleware")
33
+ except PackageNotFoundError:
34
+ try:
35
+ __version__ = version("operate")
36
+ except PackageNotFoundError:
37
+ logger = logging.getLogger("operate")
38
+ logger.warning("Could not determine version, using 0.0.0+local")
39
+ __version__ = "0.0.0+local"
40
+
41
+ logging.getLogger("aea").setLevel(logging.ERROR)
42
+
43
+
44
+ # Ensure CA bundle is available for requests
45
+ # This prevents errors when PyInstaller temp directory is cleaned during long-running apps
46
+ # Set REQUESTS_CA_BUNDLE, preferring system CA bundle, falling back to bundled.
47
+ logger = logging.getLogger("operate")
48
+ system = platform.system()
49
+ bundle_set = False
50
+ if system == "Darwin": # macOS
51
+ system_bundle = "/etc/ssl/cert.pem"
52
+ if os.path.exists(system_bundle):
53
+ os.environ.setdefault("REQUESTS_CA_BUNDLE", system_bundle)
54
+ bundle_set = True
55
+ elif system == "Linux":
56
+ system_bundle = "/etc/ssl/certs/ca-certificates.crt"
57
+ if os.path.exists(system_bundle):
58
+ os.environ.setdefault("REQUESTS_CA_BUNDLE", system_bundle)
59
+ bundle_set = True
60
+ elif system == "Windows":
61
+ # Windows uses the system certificate store by default; no file needed
62
+ logger.info("Using system certificate store on Windows.")
63
+ bundle_set = True # Considered set since system handles it
64
+ else:
65
+ logger.warning(f"Unknown OS {system}; CA bundle handling not configured.")
66
+
67
+ # Fallback to bundled if system not available
68
+ if not bundle_set and os.path.exists(certifi.where()):
69
+ os.environ.setdefault("REQUESTS_CA_BUNDLE", certifi.where())
70
+ elif not bundle_set:
71
+ logger.warning("No CA certificate bundle available.")
@@ -29,7 +29,6 @@ from dataclasses import dataclass
29
29
  from pathlib import Path
30
30
  from typing import cast
31
31
 
32
- from aea.helpers.logging import setup_logger
33
32
  from deepdiff import DeepDiff
34
33
  from web3 import Web3
35
34
 
@@ -43,10 +42,9 @@ from operate.bridge.providers.provider import Provider, ProviderRequest
43
42
  from operate.bridge.providers.relay_provider import RelayProvider
44
43
  from operate.constants import ZERO_ADDRESS
45
44
  from operate.ledger.profiles import USDC
46
- from operate.operate_types import Chain
45
+ from operate.operate_types import Chain, ChainAmounts
47
46
  from operate.resource import LocalResource
48
47
  from operate.services.manage import get_assets_balances
49
- from operate.utils import merge_sum_dicts, subtract_dicts
50
48
  from operate.wallet.master import MasterWalletManager
51
49
 
52
50
 
@@ -59,52 +57,60 @@ RELAY_PROVIDER_ID = "relay-provider"
59
57
 
60
58
  NATIVE_BRIDGE_PROVIDER_CONFIGS: t.Dict[str, t.Any] = {
61
59
  "native-ethereum-to-base": {
62
- "from_chain": "ethereum",
60
+ "from_chain": Chain.ETHEREUM.value,
63
61
  "from_bridge": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35",
64
- "to_chain": "base",
62
+ "to_chain": Chain.BASE.value,
65
63
  "to_bridge": "0x4200000000000000000000000000000000000010",
66
64
  "bridge_eta": 300,
67
65
  "bridge_contract_adaptor_class": OptimismContractAdaptor,
68
66
  },
67
+ "native-ethereum-to-celo": {
68
+ "from_chain": Chain.ETHEREUM.value,
69
+ "from_bridge": "0x9C4955b92F34148dbcfDCD82e9c9eCe5CF2badfe",
70
+ "to_chain": Chain.CELO.value,
71
+ "to_bridge": "0x4200000000000000000000000000000000000010",
72
+ "bridge_eta": 300,
73
+ "bridge_contract_adaptor_class": OptimismContractAdaptor,
74
+ },
75
+ "native-ethereum-to-gnosis": {
76
+ "from_chain": Chain.ETHEREUM.value,
77
+ "from_bridge": "0x88ad09518695c6c3712AC10a214bE5109a655671",
78
+ "to_chain": Chain.GNOSIS.value,
79
+ "to_bridge": "0xf6A78083ca3e2a662D6dd1703c939c8aCE2e268d",
80
+ "bridge_eta": 1800,
81
+ "bridge_contract_adaptor_class": OmnibridgeContractAdaptor,
82
+ },
69
83
  "native-ethereum-to-mode": {
70
- "from_chain": "ethereum",
84
+ "from_chain": Chain.ETHEREUM.value,
71
85
  "from_bridge": "0x735aDBbE72226BD52e818E7181953f42E3b0FF21",
72
- "to_chain": "mode",
86
+ "to_chain": Chain.MODE.value,
73
87
  "to_bridge": "0x4200000000000000000000000000000000000010",
74
88
  "bridge_eta": 300,
75
89
  "bridge_contract_adaptor_class": OptimismContractAdaptor,
76
90
  },
77
91
  "native-ethereum-to-optimism": {
78
- "from_chain": "ethereum",
92
+ "from_chain": Chain.ETHEREUM.value,
79
93
  "from_bridge": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1",
80
- "to_chain": "optimistic",
94
+ "to_chain": Chain.OPTIMISM.value,
81
95
  "to_bridge": "0x4200000000000000000000000000000000000010",
82
96
  "bridge_eta": 300,
83
97
  "bridge_contract_adaptor_class": OptimismContractAdaptor,
84
98
  },
85
- "native-ethereum-to-gnosis": {
86
- "from_chain": "ethereum",
87
- "from_bridge": "0x88ad09518695c6c3712AC10a214bE5109a655671",
88
- "to_chain": "gnosis",
89
- "to_bridge": "0xf6A78083ca3e2a662D6dd1703c939c8aCE2e268d",
90
- "bridge_eta": 1800,
91
- "bridge_contract_adaptor_class": OmnibridgeContractAdaptor,
92
- },
93
99
  }
94
100
 
95
-
96
- ROUTES = {
101
+ # Routes are defined as the tuples (from_chain, from_token, to_chain, to_token)
102
+ PREFERRED_ROUTES = {
97
103
  (
98
- Chain.ETHEREUM, # from_chain
99
- USDC[Chain.ETHEREUM], # from_token
100
- Chain.OPTIMISTIC, # to_chain
101
- USDC[Chain.OPTIMISTIC], # to_token
104
+ Chain.ETHEREUM,
105
+ USDC[Chain.ETHEREUM],
106
+ Chain.OPTIMISM,
107
+ USDC[Chain.OPTIMISM],
102
108
  ): LIFI_PROVIDER_ID,
103
109
  (
104
- Chain.ETHEREUM, # from_chain
105
- USDC[Chain.ETHEREUM], # from_token
106
- Chain.BASE, # to_chain
107
- USDC[Chain.BASE], # to_token
110
+ Chain.ETHEREUM,
111
+ USDC[Chain.ETHEREUM],
112
+ Chain.BASE,
113
+ USDC[Chain.BASE],
108
114
  ): LIFI_PROVIDER_ID,
109
115
  (Chain.ETHEREUM, ZERO_ADDRESS, Chain.GNOSIS, ZERO_ADDRESS): RELAY_PROVIDER_ID,
110
116
  }
@@ -187,14 +193,14 @@ class BridgeManager:
187
193
  self,
188
194
  path: Path,
189
195
  wallet_manager: MasterWalletManager,
190
- logger: t.Optional[logging.Logger] = None,
191
- quote_validity_period: int = DEFAULT_BUNDLE_VALIDITY_PERIOD,
196
+ logger: logging.Logger,
197
+ bundle_validity_period: int = DEFAULT_BUNDLE_VALIDITY_PERIOD,
192
198
  ) -> None:
193
199
  """Initialize bridge manager."""
194
200
  self.path = path
195
201
  self.wallet_manager = wallet_manager
196
- self.logger = logger or setup_logger(name="operate.bridge.BridgeManager")
197
- self.quote_validity_period = quote_validity_period
202
+ self.logger = logger
203
+ self.bundle_validity_period = bundle_validity_period
198
204
  self.path.mkdir(exist_ok=True)
199
205
  (self.path / EXECUTED_BUNDLES_PATH).mkdir(exist_ok=True)
200
206
  self.data: BridgeManagerData = cast(
@@ -252,7 +258,7 @@ class BridgeManager:
252
258
  self.logger.info("[BRIDGE MANAGER] Force bundle update.")
253
259
  self.quote_bundle(bundle)
254
260
  self._store_data()
255
- elif now > bundle.timestamp + self.quote_validity_period:
261
+ elif now > bundle.timestamp + self.bundle_validity_period:
256
262
  self.logger.info("[BRIDGE MANAGER] Bundle expired.")
257
263
  self.quote_bundle(bundle)
258
264
  self._store_data()
@@ -262,24 +268,26 @@ class BridgeManager:
262
268
 
263
269
  provider_requests = []
264
270
  for params in requests_params:
265
- for provider in self._native_bridge_providers.values():
266
- if provider.can_handle_request(params):
267
- provider_requests.append(provider.create_request(params=params))
268
- break
269
- else:
270
- provider_id = ROUTES.get(
271
- (
272
- Chain(params["from"]["chain"]),
273
- params["from"]["token"],
274
- Chain(params["to"]["chain"]),
275
- params["to"]["token"],
276
- ),
277
- RELAY_PROVIDER_ID,
278
- )
279
-
280
- provider_requests.append(
281
- self._providers[provider_id].create_request(params=params)
282
- )
271
+ route = (
272
+ Chain(params["from"]["chain"]),
273
+ params["from"]["token"],
274
+ Chain(params["to"]["chain"]),
275
+ params["to"]["token"],
276
+ )
277
+ provider_id = PREFERRED_ROUTES.get(route)
278
+
279
+ if not provider_id:
280
+ for provider in self._native_bridge_providers.values():
281
+ if provider.can_handle_request(params):
282
+ provider_id = provider.provider_id
283
+ break
284
+
285
+ if not provider_id:
286
+ provider_id = RELAY_PROVIDER_ID
287
+
288
+ provider_requests.append(
289
+ self._providers[provider_id].create_request(params=params)
290
+ )
283
291
 
284
292
  bundle = ProviderRequestBundle(
285
293
  id=f"{BRIDGE_REQUEST_BUNDLE_PREFIX}{uuid.uuid4()}",
@@ -336,7 +344,7 @@ class BridgeManager:
336
344
 
337
345
  bundle = self._get_updated_bundle(requests_params, force_update)
338
346
 
339
- balances = {}
347
+ balances = ChainAmounts()
340
348
  for chain in bundle.get_from_chains():
341
349
  ledger_api = self.wallet_manager.load(chain.ledger_type).ledger_api(chain)
342
350
  balances[chain.value] = get_assets_balances(
@@ -347,9 +355,8 @@ class BridgeManager:
347
355
 
348
356
  bridge_total_requirements = self.bridge_total_requirements(bundle)
349
357
 
350
- bridge_refill_requirements = cast(
351
- t.Dict[str, t.Dict[str, t.Dict[str, int]]],
352
- subtract_dicts(bridge_total_requirements, balances),
358
+ bridge_refill_requirements = ChainAmounts.shortfalls(
359
+ bridge_total_requirements, balances
353
360
  )
354
361
 
355
362
  is_refill_required = any(
@@ -362,10 +369,10 @@ class BridgeManager:
362
369
  status_json = self.get_status_json(bundle.id)
363
370
  status_json.update(
364
371
  {
365
- "balances": balances,
366
- "bridge_refill_requirements": bridge_refill_requirements,
367
- "bridge_total_requirements": bridge_total_requirements,
368
- "expiration_timestamp": bundle.timestamp + self.quote_validity_period,
372
+ "balances": balances.json,
373
+ "bridge_refill_requirements": bridge_refill_requirements.json,
374
+ "bridge_total_requirements": bridge_total_requirements.json,
375
+ "expiration_timestamp": bundle.timestamp + self.bundle_validity_period,
369
376
  "is_refill_required": is_refill_required,
370
377
  }
371
378
  )
@@ -442,14 +449,14 @@ class BridgeManager:
442
449
  "bridge_request_status": provider_request_status,
443
450
  }
444
451
 
445
- def bridge_total_requirements(self, bundle: ProviderRequestBundle) -> t.Dict:
452
+ def bridge_total_requirements(self, bundle: ProviderRequestBundle) -> ChainAmounts:
446
453
  """Sum bridge requirements."""
447
454
  requirements = []
448
455
  for provider_request in bundle.provider_requests:
449
456
  provider = self._providers[provider_request.provider_id]
450
457
  requirements.append(provider.requirements(provider_request))
451
458
 
452
- return merge_sum_dicts(*requirements)
459
+ return ChainAmounts.add(*requirements)
453
460
 
454
461
  def quote_bundle(self, bundle: ProviderRequestBundle) -> None:
455
462
  """Update the bundle with the quotes."""
@@ -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,11 @@ 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 (
57
+ get_default_ledger_api,
58
+ update_tx_with_gas_estimate,
59
+ update_tx_with_gas_pricing,
60
+ )
56
61
  from operate.ledger.profiles import ERC20_TOKENS, EXPLORER_URL
57
62
  from operate.operate_types import Chain
58
63
  from operate.wallet.master import MasterWalletManager
@@ -74,13 +79,15 @@ class BridgeContractAdaptor(ABC):
74
79
  ) -> None:
75
80
  """Initialize the bridge contract adaptor."""
76
81
  super().__init__()
82
+ if from_chain == to_chain:
83
+ raise ValueError("from_chain and to_chain cannot be the same.")
77
84
  self.from_chain = from_chain
78
85
  self.from_bridge = from_bridge
79
86
  self.to_chain = to_chain
80
87
  self.to_bridge = to_bridge
81
88
  self.bridge_eta = bridge_eta
82
89
 
83
- def can_handle_request(self, to_ledger_api: LedgerApi, params: t.Dict) -> bool:
90
+ def can_handle_request(self, params: t.Dict) -> bool:
84
91
  """Returns 'true' if the contract adaptor can handle a request for 'params'."""
85
92
  from_chain = params["from"]["chain"]
86
93
  from_token = Web3.to_checksum_address(params["from"]["token"])
@@ -96,7 +103,7 @@ class BridgeContractAdaptor(ABC):
96
103
  if from_token == ZERO_ADDRESS and to_token == ZERO_ADDRESS:
97
104
  return True
98
105
 
99
- for token_map in ERC20_TOKENS:
106
+ for token_map in ERC20_TOKENS.values():
100
107
  if (
101
108
  Chain(from_chain) in token_map
102
109
  and Chain(to_chain) in token_map
@@ -157,11 +164,24 @@ class OptimismContractAdaptor(BridgeContractAdaptor):
157
164
  ),
158
165
  )
159
166
 
160
- def can_handle_request(self, to_ledger_api: LedgerApi, params: t.Dict) -> bool:
167
+ def can_handle_request(self, params: t.Dict) -> bool:
161
168
  """Returns 'true' if the contract adaptor can handle a request for 'params'."""
162
169
 
170
+ if not super().can_handle_request(params):
171
+ return False
172
+
173
+ from_chain = params["from"]["chain"]
163
174
  from_token = Web3.to_checksum_address(params["from"]["token"])
175
+ from_ledger_api = get_default_ledger_api(Chain(from_chain))
176
+ to_chain = params["to"]["chain"]
164
177
  to_token = Web3.to_checksum_address(params["to"]["token"])
178
+ to_ledger_api = get_default_ledger_api(Chain(to_chain))
179
+
180
+ if from_token == ZERO_ADDRESS and to_token == ZERO_ADDRESS:
181
+ if not self._l1_standard_bridge_contract.supports_bridge_eth_to(
182
+ ledger_api=from_ledger_api, contract_address=self.from_bridge
183
+ ):
184
+ return False
165
185
 
166
186
  if to_token != ZERO_ADDRESS:
167
187
  try:
@@ -175,7 +195,7 @@ class OptimismContractAdaptor(BridgeContractAdaptor):
175
195
  except Exception: # pylint: disable=broad-except
176
196
  return False
177
197
 
178
- return super().can_handle_request(to_ledger_api, params)
198
+ return True
179
199
 
180
200
  def build_bridge_tx(
181
201
  self, from_ledger_api: LedgerApi, provider_request: ProviderRequest
@@ -287,13 +307,13 @@ class OmnibridgeContractAdaptor(BridgeContractAdaptor):
287
307
  ),
288
308
  )
289
309
 
290
- def can_handle_request(self, to_ledger_api: LedgerApi, params: t.Dict) -> bool:
310
+ def can_handle_request(self, params: t.Dict) -> bool:
291
311
  """Returns 'true' if the contract adaptor can handle a request for 'params'."""
292
312
  from_token = Web3.to_checksum_address(params["from"]["token"])
293
313
  if from_token == ZERO_ADDRESS:
294
314
  return False
295
315
 
296
- return super().can_handle_request(to_ledger_api, params)
316
+ return super().can_handle_request(params)
297
317
 
298
318
  def build_bridge_tx(
299
319
  self, from_ledger_api: LedgerApi, provider_request: ProviderRequest
@@ -417,7 +437,7 @@ class NativeBridgeProvider(Provider):
417
437
  bridge_contract_adaptor: BridgeContractAdaptor,
418
438
  provider_id: str,
419
439
  wallet_manager: MasterWalletManager,
420
- logger: t.Optional[logging.Logger] = None,
440
+ logger: logging.Logger,
421
441
  ) -> None:
422
442
  """Initialize the provider."""
423
443
  self.bridge_contract_adaptor = bridge_contract_adaptor
@@ -427,16 +447,10 @@ class NativeBridgeProvider(Provider):
427
447
 
428
448
  def can_handle_request(self, params: t.Dict) -> bool:
429
449
  """Returns 'true' if the provider can handle a request for 'params'."""
430
-
431
450
  if not super().can_handle_request(params):
432
451
  return False
433
452
 
434
- to_chain = params["to"]["chain"]
435
- chain = Chain(to_chain)
436
- wallet = self.wallet_manager.load(chain.ledger_type)
437
- to_ledger_api = wallet.ledger_api(chain)
438
-
439
- if not self.bridge_contract_adaptor.can_handle_request(to_ledger_api, params):
453
+ if not self.bridge_contract_adaptor.can_handle_request(params):
440
454
  return False
441
455
 
442
456
  return True
@@ -512,8 +526,8 @@ class NativeBridgeProvider(Provider):
512
526
  amount=to_amount,
513
527
  )
514
528
  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)
529
+ update_tx_with_gas_pricing(approve_tx, from_ledger_api)
530
+ update_tx_with_gas_estimate(approve_tx, from_ledger_api)
517
531
  return approve_tx
518
532
 
519
533
  def _get_bridge_tx(self, provider_request: ProviderRequest) -> t.Optional[t.Dict]:
@@ -534,8 +548,8 @@ class NativeBridgeProvider(Provider):
534
548
  from_ledger_api=from_ledger_api, provider_request=provider_request
535
549
  )
536
550
 
537
- Provider._update_with_gas_pricing(bridge_tx, from_ledger_api)
538
- Provider._update_with_gas_estimate(bridge_tx, from_ledger_api)
551
+ update_tx_with_gas_pricing(bridge_tx, from_ledger_api)
552
+ update_tx_with_gas_estimate(bridge_tx, from_ledger_api)
539
553
  return bridge_tx
540
554
 
541
555
  def _get_txs(