olas-operate-middleware 0.13.11__py3-none-any.whl → 0.14.1__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.

Potentially problematic release.


This version of olas-operate-middleware might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: olas-operate-middleware
3
- Version: 0.13.11
3
+ Version: 0.14.1
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: David Vilela
@@ -1,13 +1,13 @@
1
1
  operate/__init__.py,sha256=_pgD-4F4Gc9xSPxbJxiQkw0m5rSHhLjxN7mDRNm0iCE,2652
2
2
  operate/account/__init__.py,sha256=suJ_vBMO7hLCvLYe3MVDtLXTNDd6P03og7bvUN7fZsE,804
3
3
  operate/account/user.py,sha256=y7DqqDpqgHjbVmnfL_cN0Me_JWl3Dh6GSVt2-9FdRVw,3044
4
- operate/bridge/bridge_manager.py,sha256=K5DMYGqgX0xw3pxzZXrwnCQ8ZKpy-HVsfNRM185xb5g,17445
4
+ operate/bridge/bridge_manager.py,sha256=X3TQDevI5WRsn9PRbGUbaNaZujJWKutYpPZeH2QG9qM,17460
5
5
  operate/bridge/providers/lifi_provider.py,sha256=UzAeEnX9FGpnCYYml5lcICeEZeHHqNRCHkGZ-npgteo,14208
6
6
  operate/bridge/providers/native_bridge_provider.py,sha256=vAx0MtVPIAxIdQ5OKSUDhnGurYVkC8tKVJRFK9NkIdk,25088
7
- operate/bridge/providers/provider.py,sha256=Ra-HBzcq2fSBSZWu9Qv1WsuBiMtU6IXYL5lc6D6cvZM,16881
8
- operate/bridge/providers/relay_provider.py,sha256=4D2U8jrugh2DJZeSoxLCTVSZe8xMEwdCimqFDtfwWwc,17422
7
+ operate/bridge/providers/provider.py,sha256=E5d3yFe7WYZd_IbQIgDVf6F5MMJ8vMOm1o-qeqJJSCk,16981
8
+ operate/bridge/providers/relay_provider.py,sha256=QU9H9mCAUgQx-qMKXkCGfFNimi1WGoxmKO30F2K9erw,17628
9
9
  operate/cli.py,sha256=2Rg4pIRZMMK7U2xgMuX3CEueOXi280cUzk-avZ3E1aw,69786
10
- operate/constants.py,sha256=3awbelHUI9y3ZvTmpJjEu39qRq2ZSSqhPaWTeJ9CwXU,3875
10
+ operate/constants.py,sha256=oBxZEnhETCd96GWz2QDUZd-0-ofV-1deKNvFPl4-mmM,3933
11
11
  operate/data/README.md,sha256=jGPyZTvg2LCGdllvmYxmFMkkkiXb6YWatbqIkcX3kv4,879
12
12
  operate/data/__init__.py,sha256=ttC51Yqk9c4ehpIgs1Qbe7aJvzkrbbdZ1ClaCxJYByE,864
13
13
  operate/data/contracts/__init__.py,sha256=_th54_WvL0ibGy-b6St0Ne9DX-fyjsh-tNOKDn-cWrg,809
@@ -59,43 +59,44 @@ operate/data/contracts/uniswap_v2_erc20/tests/__init__.py,sha256=3Arw8dsCsJz6hVO
59
59
  operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py,sha256=z4GfybA_oZUA6-sl61qaJ78rXdbcW_rk4APzgMzQD38,13456
60
60
  operate/keys.py,sha256=qfT3-ZS1R2jG_t7BdqUdgrAYqHnj6dNrtK5c0-_AODU,6179
61
61
  operate/ledger/__init__.py,sha256=c41SqGLSpLBvG_q1cPyDh1aunByopsIIC5Mfk1vdmQE,6207
62
- operate/ledger/profiles.py,sha256=D-2K99UJjqTwPW8fWICRRCIIXdSZC0uocbtb-e40YPU,14984
62
+ operate/ledger/profiles.py,sha256=ElxkFcZ9gt9Cetn6nWC0v63Ca0Eo8YTt9_amnI1v6RQ,15153
63
63
  operate/migration.py,sha256=hdZlhhdkoPPzkOD0CFyNYAp-eqUrVu_PJnw8_PoxpWk,21015
64
64
  operate/operate_http/__init__.py,sha256=MTS1tMZ5qnA_WzaoeLxlK9IJToMGIpkNr7_vyBeAqZ8,4680
65
65
  operate/operate_http/exceptions.py,sha256=4UFzrn-GyDD71RhkaOyFPBynL6TrrtP3eywaaU3o4fc,1339
66
- operate/operate_types.py,sha256=TCmbLfJIbo-OyvpMN9PBcfYj94e00zttVPcQ0GnwyWs,13038
66
+ operate/operate_types.py,sha256=tsGL1vC0dSZidseG1A_2oAPEpxEHXM7YhtGVcuifBDw,13855
67
67
  operate/pearl.py,sha256=yrTpSXLu_ML3qT-uNxq3kScOyo31JyxBujiSMfMUbcg,1690
68
68
  operate/quickstart/analyse_logs.py,sha256=cAeAL2iUy0Po8Eor70tq54-Ibg-Dn8rkuaS167yjE_I,4198
69
69
  operate/quickstart/claim_staking_rewards.py,sha256=K7X1Yq0mxe3qWmFLb1Xu9-Jghhml95lS_LpM_BXii0o,3533
70
70
  operate/quickstart/reset_configs.py,sha256=DVPM4mh6Djunwq16hf8lD9-nGkkm7wVtwr2JUXr1if8,3380
71
71
  operate/quickstart/reset_password.py,sha256=jEBk2ROR1q8PkTIHlqum7E8PRQtXHwrauiy0_bik3RQ,2394
72
72
  operate/quickstart/reset_staking.py,sha256=SB5LZq9EctG4SYn2M6oPZ7R7ARHSFLRGzAqfKkpRcy0,5111
73
- operate/quickstart/run_service.py,sha256=myncdvwHD9DDgjj6fBVC2Ju4SplfBUZnPyXu0Z2gNYg,30279
73
+ operate/quickstart/run_service.py,sha256=tt4PYeZJ2MtYeG59vohOdMbOiCYGGUmGnjeZwYl0shQ,30383
74
74
  operate/quickstart/stop_service.py,sha256=a3-1vVyZma2UtFUPKMvVrOso1Iwpz5Rzpus9VAI4qOc,2169
75
75
  operate/quickstart/terminate_on_chain_service.py,sha256=5ENU8_mkj06i80lKUX-v1QbLU0YzKeOZDUL1e_jzySE,2914
76
76
  operate/quickstart/utils.py,sha256=i1juhJCPkzB7ZKgSk5tNiRmYxGcx8MG-dTjVyC5sKys,9287
77
- operate/resource.py,sha256=LlHJWw66RLIA9TV3HIQ6p7zZSIqoUvn3ntaVs4eRs-g,5803
77
+ operate/resource.py,sha256=0KeQkWojN737er4USSJMVC9tQEmWtXWdXj8xPEfaHqI,3954
78
+ operate/serialization.py,sha256=mf2uJCj1WULaTIJSYQ-XuaW3bdwc0vn-cxk2q0IJQf4,3885
78
79
  operate/services/__init__.py,sha256=isrThS-Ccu5Sc15JZgkN4uTAVaSg-NwUUSDeTyJEqLk,855
79
80
  operate/services/agent_runner.py,sha256=JGjyrzA5hX4Nuh79h81-dl2hdt74ZkC63t7UsGXY6Rw,7500
80
81
  operate/services/deployment_runner.py,sha256=7A94QpZu100BwIk1Q9Cr0SVK5Sj7nTWx2GRCwr0gvaM,30772
81
- operate/services/funding_manager.py,sha256=4jcu3KHQOKaaX5AYJsKb-F6GnsSy5fiqC_mWpe7wKVk,41431
82
+ operate/services/funding_manager.py,sha256=q-mO6kQWthCLI5uW8qbrMQw_6i--zd1rJ3SG4tbw6FM,41672
82
83
  operate/services/health_checker.py,sha256=dARikrgzU1jEuK4NUqlZ7N0DQq4Ah1ZiRKHmrlh8v-A,11472
83
84
  operate/services/manage.py,sha256=9dTjXhBq6tgcFWfhU61JQL67L2h3_b_7p8OICimWWB4,113292
84
85
  operate/services/protocol.py,sha256=4wAMHoELkqJJlETsMJa-XT8xVA0jfueiaKMn7X4SUKo,71898
85
- operate/services/service.py,sha256=WK1RSe83OceETmzpzR22vpWdx1qMkF2J6RSf4P9GTyk,45363
86
+ operate/services/service.py,sha256=YOU0rlPe5PjDnFRlAcThYLvr5MrPOftBDKZHMRNzZ78,46647
86
87
  operate/services/utils/__init__.py,sha256=TvioaZ1mfTRUSCtrQoLNAp4WMVXyqEJqFJM4PxSQCRU,24
87
88
  operate/services/utils/mech.py,sha256=98gNw8pMNvv_O34V1blr7JUwenqxFeeyFuXLuSYv10w,3864
88
89
  operate/services/utils/tendermint.py,sha256=M4zjF97SOJomhmj97bWKIphnia30lbDie65fs_vy_q8,25686
89
- operate/settings.py,sha256=0J2E69-Oplo-Ijy-7rzYHc2Q9Xvct-EUMiEdmKKaYOQ,2353
90
- operate/utils/__init__.py,sha256=LD5xScW5ZW9pJeBg1h_9ydj0epPcRXbP0v7OVV85Cl8,8560
91
- operate/utils/gnosis.py,sha256=mw-K-_xmRnY7QYl6Bzrh-jP7_JwHyiXhvwX6pCMSgt8,18056
90
+ operate/settings.py,sha256=is8NE-ls0PyJDsPOevwFtFHAIVtkuX-PIDTl-bMK6Qo,2455
91
+ operate/utils/__init__.py,sha256=bp_3fka3K0iSJEEe4cNlHTCb6Q5AAAu4RI4fhiVw6cM,8609
92
+ operate/utils/gnosis.py,sha256=1PrEnwkVF9lEFsFJlQXk5yXFsARGnIMPhJCrN-pRrxs,18128
92
93
  operate/utils/single_instance.py,sha256=1qVibsLoK2m45ip38kRC6IMghaza_kD14D0wAbevcYk,9090
93
94
  operate/utils/ssl.py,sha256=O5DrDoZD4T4qQuHP8GLwWUVxQ-1qXeefGp6uDJiF2lM,4308
94
95
  operate/wallet/__init__.py,sha256=NGiozD3XhvkBi7_FaOWQ8x1thZPK4uGpokJaeDY_o2w,813
95
- operate/wallet/master.py,sha256=5UvfEDFjgHNOHC25ZhZeewte1kXr69YPs5ue1NYSe5Q,33751
96
- operate/wallet/wallet_recovery_manager.py,sha256=Dn0QmOYmmNj4p1X1TVQOrua3fysR3XJ99m6Z3H7tJQI,19792
97
- olas_operate_middleware-0.13.11.dist-info/METADATA,sha256=KdXRjShg1XPVGB8ZTQFOadXprdZjviExImHafXLxl4U,1493
98
- olas_operate_middleware-0.13.11.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
99
- olas_operate_middleware-0.13.11.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
100
- olas_operate_middleware-0.13.11.dist-info/licenses/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
101
- olas_operate_middleware-0.13.11.dist-info/RECORD,,
96
+ operate/wallet/master.py,sha256=019VvWsMfzAV3fUienhcYVLB12BcSVvub3weAeMOlSA,33808
97
+ operate/wallet/wallet_recovery_manager.py,sha256=kZIKBCIVb-ufntUoCE0IqAJ-Q2YUIl7955UYY6sp8Os,19856
98
+ olas_operate_middleware-0.14.1.dist-info/METADATA,sha256=f-5TTJaF2_pDz2a0j7nRdvqdokleT2m2-gJ94jf2YI4,1492
99
+ olas_operate_middleware-0.14.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
100
+ olas_operate_middleware-0.14.1.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
101
+ olas_operate_middleware-0.14.1.dist-info/licenses/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
102
+ olas_operate_middleware-0.14.1.dist-info/RECORD,,
@@ -369,9 +369,9 @@ class BridgeManager:
369
369
  status_json = self.get_status_json(bundle.id)
370
370
  status_json.update(
371
371
  {
372
- "balances": balances,
373
- "bridge_refill_requirements": bridge_refill_requirements,
374
- "bridge_total_requirements": bridge_total_requirements,
372
+ "balances": balances.json,
373
+ "bridge_refill_requirements": bridge_refill_requirements.json,
374
+ "bridge_total_requirements": bridge_total_requirements.json,
375
375
  "expiration_timestamp": bundle.timestamp + self.bundle_validity_period,
376
376
  "is_refill_required": is_refill_required,
377
377
  }
@@ -44,6 +44,7 @@ from operate.constants import (
44
44
  from operate.ledger import get_default_ledger_api, update_tx_with_gas_pricing
45
45
  from operate.operate_types import Chain, ChainAmounts
46
46
  from operate.resource import LocalResource
47
+ from operate.serialization import BigInt
47
48
  from operate.wallet.master import MasterWalletManager
48
49
 
49
50
 
@@ -256,16 +257,16 @@ class Provider(ABC):
256
257
  {
257
258
  from_chain: {
258
259
  from_address: {
259
- ZERO_ADDRESS: 0,
260
- from_token: 0,
260
+ ZERO_ADDRESS: BigInt(0),
261
+ from_token: BigInt(0),
261
262
  }
262
263
  }
263
264
  }
264
265
  )
265
266
 
266
- total_native = 0
267
- total_gas_fees = 0
268
- total_token = 0
267
+ total_native = BigInt(0)
268
+ total_gas_fees = BigInt(0)
269
+ total_token = BigInt(0)
269
270
 
270
271
  for tx_label, tx in txs:
271
272
  self.logger.debug(
@@ -273,8 +274,8 @@ class Provider(ABC):
273
274
  )
274
275
  update_tx_with_gas_pricing(tx, from_ledger_api)
275
276
  gas_key = "gasPrice" if "gasPrice" in tx else "maxFeePerGas"
276
- gas_fees = tx.get(gas_key, 0) * tx["gas"]
277
- tx_value = int(tx.get("value", 0))
277
+ gas_fees = BigInt(tx.get(gas_key, 0) * tx["gas"])
278
+ tx_value = BigInt(int(tx.get("value", 0)))
278
279
  total_gas_fees += gas_fees
279
280
  total_native += tx_value + gas_fees
280
281
 
@@ -290,7 +291,7 @@ class Provider(ABC):
290
291
  "data", ""
291
292
  ).startswith(ERC20_APPROVE_SELECTOR):
292
293
  try:
293
- amount = int(tx["data"][-64:], 16)
294
+ amount = BigInt(tx["data"][-64:], 16)
294
295
  total_token += amount
295
296
  except Exception as e:
296
297
  raise RuntimeError("Malformed ERC20 approve transaction.") from e
@@ -101,6 +101,15 @@ RELAY_DEFAULT_GAS = {
101
101
  "swap": 400_000,
102
102
  "send": 1,
103
103
  },
104
+ Chain.ARBITRUM_ONE: {
105
+ "deposit": 50_000,
106
+ "approve": 200_000,
107
+ "authorize": 1,
108
+ "authorize1": 1,
109
+ "authorize2": 1,
110
+ "swap": 400_000,
111
+ "send": 1,
112
+ },
104
113
  }
105
114
 
106
115
 
operate/constants.py CHANGED
@@ -21,6 +21,8 @@
21
21
 
22
22
  from pathlib import Path
23
23
 
24
+ from operate.serialization import BigInt
25
+
24
26
 
25
27
  OPERATE = ".operate"
26
28
  OPERATE_HOME = Path.cwd() / OPERATE
@@ -54,8 +56,8 @@ AGENT_RUNNER_PREFIX = "agent_runner"
54
56
  ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
55
57
 
56
58
  DEFAULT_TIMEOUT = 30
57
- MIN_AGENT_BOND = 1
58
- MIN_SECURITY_DEPOSIT = 1
59
+ MIN_AGENT_BOND = BigInt(1)
60
+ MIN_SECURITY_DEPOSIT = BigInt(1)
59
61
 
60
62
  ON_CHAIN_INTERACT_TIMEOUT = 120.0
61
63
  ON_CHAIN_INTERACT_RETRIES = 12
@@ -33,6 +33,7 @@ from operate.ledger import (
33
33
  get_default_ledger_api,
34
34
  )
35
35
  from operate.operate_types import Chain, ContractAddresses
36
+ from operate.serialization import BigInt
36
37
 
37
38
 
38
39
  # TODO: Refactor, remove the usage of CONTRACTS and use CHAIN_PROFILES from Open Autonomy instead.
@@ -234,14 +235,14 @@ DEFAULT_NEW_SAFE_FUNDS: t.Dict[Chain, t.Dict[str, int]] = {
234
235
  }
235
236
 
236
237
  DEFAULT_EOA_TOPUPS = {
237
- Chain.ARBITRUM_ONE: {ZERO_ADDRESS: 2_500_000_000_000_000},
238
- Chain.BASE: {ZERO_ADDRESS: 2_500_000_000_000_000},
239
- Chain.CELO: {ZERO_ADDRESS: 750_000_000_000_000_000},
240
- Chain.ETHEREUM: {ZERO_ADDRESS: 10_000_000_000_000_000},
241
- Chain.GNOSIS: {ZERO_ADDRESS: 750_000_000_000_000_000},
242
- Chain.MODE: {ZERO_ADDRESS: 250_000_000_000_000},
243
- Chain.OPTIMISM: {ZERO_ADDRESS: 2_500_000_000_000_000},
244
- Chain.POLYGON: {ZERO_ADDRESS: 750_000_000_000_000_000},
238
+ Chain.ARBITRUM_ONE: {ZERO_ADDRESS: BigInt(2_500_000_000_000_000)},
239
+ Chain.BASE: {ZERO_ADDRESS: BigInt(2_500_000_000_000_000)},
240
+ Chain.CELO: {ZERO_ADDRESS: BigInt(750_000_000_000_000_000)},
241
+ Chain.ETHEREUM: {ZERO_ADDRESS: BigInt(10_000_000_000_000_000)},
242
+ Chain.GNOSIS: {ZERO_ADDRESS: BigInt(750_000_000_000_000_000)},
243
+ Chain.MODE: {ZERO_ADDRESS: BigInt(250_000_000_000_000)},
244
+ Chain.OPTIMISM: {ZERO_ADDRESS: BigInt(2_500_000_000_000_000)},
245
+ Chain.POLYGON: {ZERO_ADDRESS: BigInt(750_000_000_000_000_000)},
245
246
  }
246
247
 
247
248
  DEFAULT_EOA_TOPUPS_WITHOUT_SAFE = {
@@ -250,14 +251,14 @@ DEFAULT_EOA_TOPUPS_WITHOUT_SAFE = {
250
251
  }
251
252
 
252
253
  DEFAULT_RECOVERY_TOPUPS = {
253
- Chain.ARBITRUM_ONE: {ZERO_ADDRESS: 625_000_000_000_000},
254
- Chain.BASE: {ZERO_ADDRESS: 625_000_000_000_000},
255
- Chain.CELO: {ZERO_ADDRESS: 187_500_000_000_000_000},
256
- Chain.ETHEREUM: {ZERO_ADDRESS: 2_500_000_000_000_000},
257
- Chain.GNOSIS: {ZERO_ADDRESS: 187_500_000_000_000_000},
258
- Chain.MODE: {ZERO_ADDRESS: 62_500_000_000_000},
259
- Chain.OPTIMISM: {ZERO_ADDRESS: 625_000_000_000_000},
260
- Chain.POLYGON: {ZERO_ADDRESS: 187_500_000_000_000_000},
254
+ Chain.ARBITRUM_ONE: {ZERO_ADDRESS: BigInt(625_000_000_000_000)},
255
+ Chain.BASE: {ZERO_ADDRESS: BigInt(625_000_000_000_000)},
256
+ Chain.CELO: {ZERO_ADDRESS: BigInt(187_500_000_000_000_000)},
257
+ Chain.ETHEREUM: {ZERO_ADDRESS: BigInt(2_500_000_000_000_000)},
258
+ Chain.GNOSIS: {ZERO_ADDRESS: BigInt(187_500_000_000_000_000)},
259
+ Chain.MODE: {ZERO_ADDRESS: BigInt(62_500_000_000_000)},
260
+ Chain.OPTIMISM: {ZERO_ADDRESS: BigInt(625_000_000_000_000)},
261
+ Chain.POLYGON: {ZERO_ADDRESS: BigInt(187_500_000_000_000_000)},
261
262
  }
262
263
 
263
264
  DEFAULT_EOA_THRESHOLD = 0.5
operate/operate_types.py CHANGED
@@ -36,6 +36,7 @@ from typing_extensions import TypedDict
36
36
 
37
37
  from operate.constants import FERNET_KEY_LENGTH, NO_STAKING_PROGRAM_ID
38
38
  from operate.resource import LocalResource
39
+ from operate.serialization import BigInt, serialize
39
40
 
40
41
 
41
42
  LedgerType = LedgerTypeOA
@@ -178,8 +179,8 @@ class DeployedNodes(LocalResource):
178
179
  class OnChainFundRequirements(LocalResource):
179
180
  """On-chain fund requirements."""
180
181
 
181
- agent: float
182
- safe: float
182
+ agent: BigInt
183
+ safe: BigInt
183
184
 
184
185
 
185
186
  OnChainTokenRequirements = t.Dict[str, OnChainFundRequirements]
@@ -192,7 +193,7 @@ class OnChainUserParams(LocalResource):
192
193
  staking_program_id: str
193
194
  nft: str
194
195
  agent_id: int
195
- cost_of_bond: int
196
+ cost_of_bond: BigInt
196
197
  fund_requirements: OnChainTokenRequirements
197
198
 
198
199
  @property
@@ -296,35 +297,54 @@ class Version:
296
297
  return self.patch < other.patch
297
298
 
298
299
 
299
- class ChainAmounts(dict[str, dict[str, dict[str, int]]]):
300
+ class ChainAmounts(dict[str, dict[str, dict[str, BigInt]]]):
300
301
  """
301
302
  Class that represents chain amounts as a dictionary
302
303
 
303
304
  The standard format follows the convention {chain: {address: {token: amount}}}
304
305
  """
305
306
 
307
+ @property
308
+ def json(self) -> dict:
309
+ """Return JSON representation with amounts as strings."""
310
+ return serialize(self)
311
+
312
+ @staticmethod
313
+ def from_json(obj: dict) -> "ChainAmounts":
314
+ """Create ChainAmounts from JSON representation."""
315
+ result: dict[str, dict[str, dict[str, BigInt]]] = {}
316
+
317
+ for chain, addresses in obj.items():
318
+ for address, assets in addresses.items():
319
+ for asset, amount in assets.items():
320
+ result.setdefault(chain, {}).setdefault(address, {})[asset] = (
321
+ BigInt(amount)
322
+ )
323
+
324
+ return ChainAmounts(result)
325
+
306
326
  @classmethod
307
327
  def shortfalls(
308
328
  cls, requirements: "ChainAmounts", balances: "ChainAmounts"
309
329
  ) -> "ChainAmounts":
310
330
  """Return the shortfalls between requirements and balances."""
311
- result: dict[str, dict[str, dict[str, int]]] = {}
331
+ result: dict[str, dict[str, dict[str, BigInt]]] = {}
312
332
 
313
333
  for chain, addresses in requirements.items():
314
334
  for address, assets in addresses.items():
315
335
  for asset, required_amount in assets.items():
316
336
  available = balances.get(chain, {}).get(address, {}).get(asset, 0)
317
337
  shortfall = max(required_amount - available, 0)
318
- result.setdefault(chain, {}).setdefault(address, {})[
319
- asset
320
- ] = shortfall
338
+ result.setdefault(chain, {}).setdefault(address, {})[asset] = (
339
+ BigInt(shortfall)
340
+ )
321
341
 
322
342
  return cls(result)
323
343
 
324
344
  @classmethod
325
345
  def add(cls, *chainamounts: "ChainAmounts") -> "ChainAmounts":
326
346
  """Add multiple ChainAmounts"""
327
- result: dict[str, dict[str, dict[str, int]]] = {}
347
+ result: dict[str, dict[str, dict[str, BigInt]]] = {}
328
348
 
329
349
  for ca in chainamounts:
330
350
  for chain, addresses in ca.items():
@@ -332,7 +352,9 @@ class ChainAmounts(dict[str, dict[str, dict[str, int]]]):
332
352
  for address, assets in addresses.items():
333
353
  result_assets = result_addresses.setdefault(address, {})
334
354
  for asset, amount in assets.items():
335
- result_assets[asset] = result_assets.get(asset, 0) + amount
355
+ result_assets[asset] = BigInt(
356
+ result_assets.get(asset, 0) + amount
357
+ )
336
358
 
337
359
  return cls(result)
338
360
 
@@ -346,7 +368,7 @@ class ChainAmounts(dict[str, dict[str, dict[str, int]]]):
346
368
  for _, addresses in output.items():
347
369
  for _, balances in addresses.items():
348
370
  for asset, amount in balances.items():
349
- balances[asset] = int(amount * multiplier)
371
+ balances[asset] = BigInt(int(amount * multiplier))
350
372
  return output
351
373
 
352
374
  def __sub__(self, other: "ChainAmounts") -> "ChainAmounts":
@@ -362,7 +384,7 @@ class ChainAmounts(dict[str, dict[str, dict[str, int]]]):
362
384
  for _, addresses in output.items():
363
385
  for _, balances in addresses.items():
364
386
  for asset, amount in balances.items():
365
- balances[asset] = int(amount // divisor)
387
+ balances[asset] = BigInt(int(amount // divisor))
366
388
  return output
367
389
 
368
390
  def __lt__(self, other: "ChainAmounts") -> bool:
@@ -46,6 +46,7 @@ from operate.ledger import DEFAULT_RPCS
46
46
  from operate.ledger.profiles import STAKING, get_staking_contract
47
47
  from operate.operate_types import (
48
48
  Chain,
49
+ ChainAmounts,
49
50
  LedgerType,
50
51
  ServiceEnvProvisionType,
51
52
  ServiceTemplate,
@@ -649,7 +650,9 @@ def _ask_funds_from_requirements(
649
650
  )
650
651
 
651
652
  if not requirements["is_refill_required"] and requirements["allow_start_agent"]:
652
- for chain_name, balances in requirements["balances"].items():
653
+ for chain_name, balances in ChainAmounts.from_json(
654
+ requirements["balances"]
655
+ ).items():
653
656
  ledger_api = wallet.ledger_api(
654
657
  chain=Chain(chain_name),
655
658
  rpc=service.chain_configs[chain_name].ledger_config.rpc,
@@ -662,17 +665,19 @@ def _ask_funds_from_requirements(
662
665
 
663
666
  return True
664
667
 
665
- for chain_name, chain_requirements in requirements["refill_requirements"].items():
668
+ for chain_name, chain_requirements in ChainAmounts.from_json(
669
+ requirements["refill_requirements"]
670
+ ).items():
666
671
  chain = Chain(chain_name)
667
672
  ledger_api = wallet.ledger_api(
668
673
  chain=chain,
669
674
  rpc=service.chain_configs[chain_name].ledger_config.rpc,
670
675
  )
671
- for wallet_address, requirements in chain_requirements.items():
676
+ for wallet_address, _requirements in chain_requirements.items():
672
677
  if wallet_address in ("master_safe", "service_safe"):
673
678
  continue # we can't ask funds in placeholder addresses
674
679
 
675
- for asset_address, requirement in requirements.items():
680
+ for asset_address, requirement in _requirements.items():
676
681
  ask_funds_in_address(
677
682
  ledger_api=ledger_api,
678
683
  chain=chain_name,
operate/resource.py CHANGED
@@ -19,16 +19,14 @@
19
19
 
20
20
  """Local resource representation."""
21
21
 
22
- import enum
23
22
  import json
24
23
  import os
25
24
  import platform
26
25
  import shutil
27
- import types
28
26
  import typing as t
29
- from dataclasses import asdict, is_dataclass
30
27
  from pathlib import Path
31
28
 
29
+ from operate.serialization import deserialize, serialize
32
30
  from operate.utils import safe_file_operation
33
31
 
34
32
 
@@ -38,63 +36,6 @@ from operate.utils import safe_file_operation
38
36
  N_BACKUPS = 5
39
37
 
40
38
 
41
- def serialize(obj: t.Any) -> t.Any:
42
- """Serialize object."""
43
- if is_dataclass(obj) and not isinstance(obj, type):
44
- return serialize(asdict(obj))
45
- if isinstance(obj, Path):
46
- return str(obj)
47
- if isinstance(obj, dict):
48
- return {serialize(key): serialize(obj=value) for key, value in obj.items()}
49
- if isinstance(obj, list):
50
- return [serialize(obj=value) for value in obj]
51
- if isinstance(obj, enum.Enum):
52
- return obj.value
53
- if isinstance(obj, bytes):
54
- return obj.hex()
55
- return obj
56
-
57
-
58
- def deserialize(obj: t.Any, otype: t.Any) -> t.Any:
59
- """Desrialize a json object."""
60
-
61
- origin = getattr(otype, "__origin__", None)
62
-
63
- # Handle Union and Optional
64
- if origin is t.Union or isinstance(otype, types.UnionType):
65
- for arg in t.get_args(otype):
66
- if arg is type(None): # noqa: E721
67
- continue
68
- try:
69
- return deserialize(obj, arg)
70
- except Exception: # pylint: disable=broad-except # nosec
71
- continue
72
- return None
73
-
74
- base = getattr(otype, "__class__") # noqa: B009
75
- if base.__name__ == "_GenericAlias": # type: ignore
76
- args = otype.__args__ # type: ignore
77
- if len(args) == 1:
78
- (atype,) = args
79
- return [deserialize(arg, atype) for arg in obj]
80
- if len(args) == 2:
81
- (ktype, vtype) = args
82
- return {
83
- deserialize(key, ktype): deserialize(val, vtype)
84
- for key, val in obj.items()
85
- }
86
- return obj
87
- if base is enum.EnumMeta:
88
- return otype(obj)
89
- if otype is Path:
90
- return Path(obj)
91
- if is_dataclass(otype) and hasattr(otype, "from_json"):
92
- return otype.from_json(obj)
93
- if otype is bytes:
94
- return bytes.fromhex(obj)
95
- return obj
96
-
97
-
98
39
  class LocalResource:
99
40
  """Initialize local resource."""
100
41
 
@@ -0,0 +1,113 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ------------------------------------------------------------------------------
3
+ #
4
+ # Copyright 2026 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
+ """Serialization utilities."""
21
+
22
+ import enum
23
+ import types
24
+ import typing as t
25
+ from dataclasses import asdict, is_dataclass
26
+ from pathlib import Path
27
+
28
+
29
+ class BigInt(int):
30
+ """BigInt class for large integers that serialize as strings."""
31
+
32
+ def __iadd__(self, other: t.Union[int, str]) -> "BigInt":
33
+ """In-place addition."""
34
+ return BigInt(int(self) + int(other))
35
+
36
+ def __isub__(self, other: t.Union[int, str]) -> "BigInt":
37
+ """In-place subtraction."""
38
+ return BigInt(int(self) - int(other))
39
+
40
+ def __imul__(self, other: t.Union[int, str]) -> "BigInt":
41
+ """In-place multiplication."""
42
+ return BigInt(int(self) * int(other))
43
+
44
+ def __ifloordiv__(self, other: t.Union[int, str]) -> "BigInt":
45
+ """In-place floor division."""
46
+ return BigInt(int(self) // int(other))
47
+
48
+ def __itruediv__(self, other: t.Union[int, str]) -> "BigInt":
49
+ """In-place true division."""
50
+ return BigInt(int(self) / int(other))
51
+
52
+
53
+ def serialize(obj: t.Any) -> t.Any: # pylint: disable=too-many-return-statements
54
+ """Serialize object."""
55
+ if is_dataclass(obj) and not isinstance(obj, type):
56
+ return serialize(asdict(obj))
57
+ if isinstance(obj, Path):
58
+ return str(obj)
59
+ if isinstance(obj, dict):
60
+ return {serialize(key): serialize(obj=value) for key, value in obj.items()}
61
+ if isinstance(obj, list):
62
+ return [serialize(obj=value) for value in obj]
63
+ if isinstance(obj, enum.Enum):
64
+ return obj.value
65
+ if isinstance(obj, bytes):
66
+ return obj.hex()
67
+ if hasattr(obj, "__class__") and obj.__class__.__name__ == "BigInt":
68
+ return str(obj)
69
+ return obj
70
+
71
+
72
+ def deserialize( # pylint: disable=too-many-return-statements
73
+ obj: t.Any, otype: t.Any
74
+ ) -> t.Any:
75
+ """Deserialize a json object."""
76
+
77
+ origin = getattr(otype, "__origin__", None)
78
+
79
+ # Handle Union and Optional
80
+ if origin is t.Union or isinstance(otype, types.UnionType):
81
+ for arg in t.get_args(otype):
82
+ if arg is type(None): # noqa: E721
83
+ continue
84
+ try:
85
+ return deserialize(obj, arg)
86
+ except Exception: # pylint: disable=broad-except # nosec
87
+ continue
88
+ return None
89
+
90
+ base = getattr(otype, "__class__") # noqa: B009
91
+ if base.__name__ == "_GenericAlias": # type: ignore
92
+ args = otype.__args__ # type: ignore
93
+ if len(args) == 1:
94
+ (atype,) = args
95
+ return [deserialize(arg, atype) for arg in obj]
96
+ if len(args) == 2:
97
+ (ktype, vtype) = args
98
+ return {
99
+ deserialize(key, ktype): deserialize(val, vtype)
100
+ for key, val in obj.items()
101
+ }
102
+ return obj
103
+ if base is enum.EnumMeta:
104
+ return otype(obj)
105
+ if otype is Path:
106
+ return Path(obj)
107
+ if is_dataclass(otype) and hasattr(otype, "from_json"):
108
+ return otype.from_json(obj)
109
+ if otype is bytes:
110
+ return bytes.fromhex(obj)
111
+ if hasattr(otype, "__name__") and otype.__name__ == "BigInt":
112
+ return BigInt(obj)
113
+ return obj
@@ -58,6 +58,7 @@ from operate.ledger.profiles import (
58
58
  get_asset_name,
59
59
  )
60
60
  from operate.operate_types import Chain, ChainAmounts, LedgerType, OnChainState
61
+ from operate.serialization import BigInt
61
62
  from operate.services.protocol import EthSafeTxBuilder, StakingManager, StakingState
62
63
  from operate.services.service import NON_EXISTENT_TOKEN, Service
63
64
  from operate.utils import concurrent_execute
@@ -253,23 +254,23 @@ class FundingManager:
253
254
  user_params = chain_config.chain_data.user_params
254
255
  number_of_agents = len(service.agent_addresses)
255
256
 
256
- requirements: defaultdict = defaultdict(int)
257
+ requirements: defaultdict = defaultdict(BigInt)
257
258
 
258
259
  if (
259
260
  not user_params.use_staking
260
261
  or not user_params.staking_program_id
261
262
  or user_params.staking_program_id == NO_STAKING_PROGRAM_ID
262
263
  ):
263
- protocol_agent_bonds = (
264
+ protocol_agent_bonds = BigInt(
264
265
  max(MIN_AGENT_BOND, user_params.cost_of_bond) * number_of_agents
265
266
  )
266
267
  protocol_security_deposit = max(
267
268
  MIN_SECURITY_DEPOSIT, user_params.cost_of_bond
268
269
  )
269
- staking_agent_bonds = 0
270
- staking_security_deposit = 0
270
+ staking_agent_bonds = BigInt(0)
271
+ staking_security_deposit = BigInt(0)
271
272
  else:
272
- protocol_agent_bonds = MIN_AGENT_BOND * number_of_agents
273
+ protocol_agent_bonds = BigInt(MIN_AGENT_BOND * number_of_agents)
273
274
  protocol_security_deposit = MIN_SECURITY_DEPOSIT
274
275
 
275
276
  staking_manager = StakingManager(chain=Chain(chain))
@@ -279,10 +280,10 @@ class FundingManager:
279
280
  ),
280
281
  )
281
282
 
282
- staking_agent_bonds = (
283
+ staking_agent_bonds = BigInt(
283
284
  staking_params["min_staking_deposit"] * number_of_agents
284
285
  )
285
- staking_security_deposit = staking_params["min_staking_deposit"]
286
+ staking_security_deposit = BigInt(staking_params["min_staking_deposit"])
286
287
  staking_token = staking_params["staking_token"]
287
288
  requirements[staking_token] += staking_agent_bonds
288
289
  requirements[staking_token] += staking_security_deposit
@@ -290,7 +291,7 @@ class FundingManager:
290
291
  for token, amount in staking_params[
291
292
  "additional_staking_tokens"
292
293
  ].items():
293
- requirements[token] = amount
294
+ requirements[token] = BigInt(amount)
294
295
 
295
296
  requirements[ZERO_ADDRESS] += protocol_agent_bonds
296
297
  requirements[ZERO_ADDRESS] += protocol_security_deposit
@@ -316,7 +317,7 @@ class FundingManager:
316
317
  protocol_bonded_assets = ChainAmounts()
317
318
 
318
319
  for chain, chain_config in service.chain_configs.items():
319
- bonded_assets: defaultdict = defaultdict(int)
320
+ bonded_assets: defaultdict = defaultdict(BigInt)
320
321
  ledger_config = chain_config.ledger_config
321
322
  user_params = chain_config.chain_data.user_params
322
323
 
@@ -366,7 +367,8 @@ class FundingManager:
366
367
  )
367
368
 
368
369
  # Determine bonded native amount
369
- security_deposit = service_info[0]
370
+ operator_balance = BigInt(operator_balance)
371
+ security_deposit = BigInt(service_info[0])
370
372
  service_state = service_info[6]
371
373
  agent_ids = service_info[7]
372
374
 
@@ -449,25 +451,25 @@ class FundingManager:
449
451
  ),
450
452
  )
451
453
 
452
- agent_bonds = 0
454
+ agent_bonds = BigInt(0)
453
455
  for agent_instances, agent_bond in zip(
454
456
  agent_instances_and_bonds[: len(agent_ids)],
455
457
  agent_instances_and_bonds[len(agent_ids) :],
456
458
  ):
457
459
  num_agent_instances = agent_instances[0]
458
- agent_bonds += num_agent_instances * agent_bond
460
+ agent_bonds += BigInt(num_agent_instances * agent_bond)
459
461
 
460
462
  if service_state == OnChainState.TERMINATED_BONDED:
461
463
  num_agent_instances = service_info[5]
462
- agent_bonds += num_agent_instances * token_bond
464
+ agent_bonds += BigInt(num_agent_instances * token_bond)
463
465
 
464
- security_deposit = 0
466
+ security_deposit = BigInt(0)
465
467
  if (
466
468
  OnChainState.ACTIVE_REGISTRATION
467
469
  <= service_state
468
470
  < OnChainState.TERMINATED_BONDED
469
471
  ):
470
- security_deposit = security_deposits[1]
472
+ security_deposit = BigInt(security_deposits[1])
471
473
 
472
474
  bonded_assets[staking_params["staking_token"]] += agent_bonds
473
475
  bonded_assets[staking_params["staking_token"]] += security_deposit
@@ -476,7 +478,7 @@ class FundingManager:
476
478
  for token, amount in staking_params[
477
479
  "additional_staking_tokens"
478
480
  ].items():
479
- bonded_assets[token] += amount
481
+ bonded_assets[token] += BigInt(amount)
480
482
 
481
483
  protocol_bonded_assets[chain] = {master_safe: dict(bonded_assets)}
482
484
 
@@ -871,14 +873,14 @@ class FundingManager:
871
873
  allow_start_agent = False
872
874
 
873
875
  return {
874
- "balances": balances,
875
- "bonded_assets": protocol_bonded_assets,
876
- "total_requirements": total_requirements,
877
- "refill_requirements": refill_requirements,
878
- "protocol_asset_requirements": protocol_asset_requirements,
876
+ "balances": balances.json,
877
+ "bonded_assets": protocol_bonded_assets.json,
878
+ "total_requirements": total_requirements.json,
879
+ "refill_requirements": refill_requirements.json,
880
+ "protocol_asset_requirements": protocol_asset_requirements.json,
879
881
  "is_refill_required": is_refill_required,
880
882
  "allow_start_agent": allow_start_agent,
881
- "agent_funding_requests": funding_requests,
883
+ "agent_funding_requests": funding_requests.json,
882
884
  "agent_funding_requests_cooldown": funding_requests_cooldown,
883
885
  "agent_funding_in_progress": funding_in_progress,
884
886
  }
@@ -77,6 +77,7 @@ from operate.constants import (
77
77
  )
78
78
  from operate.keys import KeysManager
79
79
  from operate.ledger import get_default_ledger_api, get_default_rpc
80
+ from operate.ledger.profiles import WRAPPED_NATIVE_ASSET
80
81
  from operate.operate_http.exceptions import NotAllowed
81
82
  from operate.operate_types import (
82
83
  AgentRelease,
@@ -96,6 +97,7 @@ from operate.operate_types import (
96
97
  ServiceTemplate,
97
98
  )
98
99
  from operate.resource import LocalResource
100
+ from operate.serialization import BigInt
99
101
  from operate.services.deployment_runner import run_host_deployment, stop_host_deployment
100
102
  from operate.services.utils import tendermint
101
103
  from operate.utils import unrecoverable_delete
@@ -1199,10 +1201,13 @@ class Service(LocalResource):
1199
1201
 
1200
1202
  return amounts
1201
1203
 
1202
- def get_balances(self) -> ChainAmounts:
1203
- """Get balances of the agent addresses and service safe."""
1204
+ def get_balances(self, unify_wrapped_native_tokens: bool = True) -> ChainAmounts:
1205
+ """Get balances of the agent addresses and service safe.
1206
+
1207
+ :param unify_wrapped_native_tokens: Whether to consider wrapped native tokens as native tokens.
1208
+ """
1204
1209
  initial_funding_amounts = self.get_initial_funding_amounts()
1205
- return ChainAmounts(
1210
+ absolute_balances = ChainAmounts(
1206
1211
  {
1207
1212
  chain_str: {
1208
1213
  address: {
@@ -1221,6 +1226,27 @@ class Service(LocalResource):
1221
1226
  for chain_str, addresses in initial_funding_amounts.items()
1222
1227
  }
1223
1228
  )
1229
+ if unify_wrapped_native_tokens:
1230
+ for chain_str, addresses in absolute_balances.items():
1231
+ chain = Chain.from_string(chain_str)
1232
+ wrapped_asset = WRAPPED_NATIVE_ASSET[chain]
1233
+ for address, assets in addresses.items():
1234
+ if ZERO_ADDRESS in assets or wrapped_asset in assets:
1235
+ if ZERO_ADDRESS not in assets:
1236
+ assets[ZERO_ADDRESS] = 0
1237
+
1238
+ if wrapped_asset in assets:
1239
+ assets[ZERO_ADDRESS] += assets[wrapped_asset]
1240
+ del assets[wrapped_asset]
1241
+ else:
1242
+ assets[ZERO_ADDRESS] += get_asset_balance(
1243
+ ledger_api=get_default_ledger_api(chain),
1244
+ asset_address=wrapped_asset,
1245
+ address=address,
1246
+ raise_on_invalid_address=False,
1247
+ )
1248
+
1249
+ return absolute_balances
1224
1250
 
1225
1251
  def get_funding_requests(self) -> ChainAmounts:
1226
1252
  """Get funding amounts requested by the agent."""
@@ -1258,7 +1284,7 @@ class Service(LocalResource):
1258
1284
  funding_requests[chain_str].setdefault(address, {})
1259
1285
  for asset, amounts in assets.items():
1260
1286
  try:
1261
- funding_requests[chain_str][address][asset] = int(
1287
+ funding_requests[chain_str][address][asset] = BigInt(
1262
1288
  amounts["deficit"]
1263
1289
  )
1264
1290
  except (ValueError, TypeError):
operate/settings.py CHANGED
@@ -25,6 +25,7 @@ from operate.constants import SETTINGS_JSON
25
25
  from operate.ledger.profiles import DEFAULT_EOA_TOPUPS
26
26
  from operate.operate_types import ChainAmounts
27
27
  from operate.resource import LocalResource
28
+ from operate.serialization import BigInt
28
29
 
29
30
 
30
31
  SETTINGS_JSON_VERSION = 1
@@ -40,7 +41,7 @@ class Settings(LocalResource):
40
41
  _file = SETTINGS_JSON
41
42
 
42
43
  version: int
43
- eoa_topups: Dict[str, Dict[str, int]]
44
+ eoa_topups: Dict[str, Dict[str, BigInt]]
44
45
 
45
46
  def __init__(self, path: Optional[Path] = None, **kwargs: Any) -> None:
46
47
  """Initialize settings."""
@@ -60,11 +61,13 @@ class Settings(LocalResource):
60
61
 
61
62
  def get_eoa_topups(self, with_safe: bool = False) -> ChainAmounts:
62
63
  """Get the EOA topups."""
63
- return (
64
+ return ChainAmounts(
64
65
  self.eoa_topups
65
66
  if with_safe
66
67
  else {
67
- chain: {asset: amount * 2 for asset, amount in asset_amount.items()}
68
+ chain: {
69
+ asset: BigInt(amount * 2) for asset, amount in asset_amount.items()
70
+ }
68
71
  for chain, asset_amount in self.eoa_topups.items()
69
72
  }
70
73
  )
operate/utils/__init__.py CHANGED
@@ -34,6 +34,7 @@ from pathlib import Path
34
34
  from threading import Lock
35
35
 
36
36
  from operate.constants import DEFAULT_TIMEOUT
37
+ from operate.serialization import BigInt
37
38
 
38
39
 
39
40
  logger = logging.getLogger(__name__)
@@ -118,7 +119,7 @@ def subtract_dicts(
118
119
  va if isinstance(va, dict) else {}, vb if isinstance(vb, dict) else {}
119
120
  )
120
121
  else:
121
- result[key] = max((va or 0) - (vb or 0), 0) # type: ignore
122
+ result[key] = BigInt(max((va or 0) - (vb or 0), 0)) # type: ignore
122
123
  return result
123
124
 
124
125
 
operate/utils/gnosis.py CHANGED
@@ -41,6 +41,7 @@ from operate.constants import (
41
41
  )
42
42
  from operate.ledger import get_default_ledger_api
43
43
  from operate.operate_types import Chain
44
+ from operate.serialization import BigInt
44
45
 
45
46
 
46
47
  logger = setup_logger(name="operate.utils.gnosis")
@@ -572,7 +573,7 @@ def get_asset_balance(
572
573
  asset_address: str,
573
574
  address: str,
574
575
  raise_on_invalid_address: bool = True,
575
- ) -> int:
576
+ ) -> BigInt:
576
577
  """
577
578
  Get the balance of a native asset or ERC20 token.
578
579
 
@@ -581,12 +582,12 @@ def get_asset_balance(
581
582
  if not Web3.is_address(address):
582
583
  if raise_on_invalid_address:
583
584
  raise ValueError(f"Invalid address: {address}")
584
- return 0
585
+ return BigInt(0)
585
586
 
586
587
  try:
587
588
  if asset_address == ZERO_ADDRESS:
588
- return ledger_api.get_balance(address, raise_on_try=True)
589
- return (
589
+ return BigInt(ledger_api.get_balance(address, raise_on_try=True))
590
+ return BigInt(
590
591
  registry_contracts.erc20.get_instance(
591
592
  ledger_api=ledger_api,
592
593
  contract_address=asset_address,
@@ -605,13 +606,13 @@ def get_assets_balances(
605
606
  asset_addresses: t.Set[str],
606
607
  addresses: t.Set[str],
607
608
  raise_on_invalid_address: bool = True,
608
- ) -> t.Dict[str, t.Dict[str, int]]:
609
+ ) -> t.Dict[str, t.Dict[str, BigInt]]:
609
610
  """
610
611
  Get the balances of a list of native assets or ERC20 tokens.
611
612
 
612
613
  If asset address is a zero address, return the native balance.
613
614
  """
614
- output: t.Dict[str, t.Dict[str, int]] = {}
615
+ output: t.Dict[str, t.Dict[str, BigInt]] = {}
615
616
 
616
617
  for asset, address in itertools.product(asset_addresses, addresses):
617
618
  output.setdefault(address, {})[asset] = get_asset_balance(
operate/wallet/master.py CHANGED
@@ -48,6 +48,7 @@ from operate.ledger import (
48
48
  from operate.ledger.profiles import DUST, ERC20_TOKENS, format_asset_amount
49
49
  from operate.operate_types import Chain, EncryptedData, LedgerType
50
50
  from operate.resource import LocalResource
51
+ from operate.serialization import BigInt
51
52
  from operate.utils import create_backup
52
53
  from operate.utils.gnosis import add_owner
53
54
  from operate.utils.gnosis import create_safe as create_gnosis_safe
@@ -211,7 +212,7 @@ class MasterWallet(LocalResource):
211
212
 
212
213
  def get_balance(
213
214
  self, chain: Chain, asset: str = ZERO_ADDRESS, from_safe: bool = True
214
- ) -> int:
215
+ ) -> BigInt:
215
216
  """Get wallet balance on a given chain."""
216
217
  if from_safe:
217
218
  if chain not in self.safes:
@@ -770,7 +771,7 @@ class EthereumMasterWallet(MasterWallet):
770
771
  rpc = None
771
772
  wallet_json = self.json
772
773
 
773
- balances: t.Dict[str, t.Dict[str, t.Dict[str, int]]] = {}
774
+ balances: t.Dict[str, t.Dict[str, t.Dict[str, BigInt]]] = {}
774
775
  owner_sets = set()
775
776
  for chain, safe in self.safes.items():
776
777
  chain_str = chain.value
@@ -784,11 +785,11 @@ class EthereumMasterWallet(MasterWallet):
784
785
 
785
786
  assets = [token[chain] for token in ERC20_TOKENS.values()] + [ZERO_ADDRESS]
786
787
  for asset in assets:
787
- balances[chain_str][self.address][asset] = self.get_balance(
788
- chain=chain, asset=asset, from_safe=False
788
+ balances[chain_str][self.address][asset] = str(
789
+ self.get_balance(chain=chain, asset=asset, from_safe=False)
789
790
  )
790
- balances[chain_str][safe][asset] = self.get_balance(
791
- chain=chain, asset=asset, from_safe=True
791
+ balances[chain_str][safe][asset] = str(
792
+ self.get_balance(chain=chain, asset=asset, from_safe=True)
792
793
  )
793
794
  wallet_json["safes"][chain_str] = {
794
795
  safe: {
@@ -40,6 +40,7 @@ from operate.ledger import get_default_ledger_api
40
40
  from operate.ledger.profiles import DEFAULT_RECOVERY_TOPUPS
41
41
  from operate.operate_types import ChainAmounts
42
42
  from operate.resource import LocalResource
43
+ from operate.serialization import BigInt
43
44
  from operate.services.manage import ServiceManager
44
45
  from operate.utils.gnosis import get_asset_balance, get_owners
45
46
  from operate.wallet.master import MasterWalletManager
@@ -330,7 +331,7 @@ class WalletRecoveryManager:
330
331
  raise_on_invalid_address=False,
331
332
  )
332
333
  requirements[chain_str].setdefault(backup_owner, {}).setdefault(
333
- ZERO_ADDRESS, 0
334
+ ZERO_ADDRESS, BigInt(0)
334
335
  )
335
336
  if new_wallet.address not in owners:
336
337
  requirements[chain_str][backup_owner][
@@ -351,9 +352,9 @@ class WalletRecoveryManager:
351
352
  )
352
353
 
353
354
  return {
354
- "balances": balances,
355
- "total_requirements": requirements,
356
- "refill_requirements": refill_requirements,
355
+ "balances": balances.json,
356
+ "total_requirements": requirements.json,
357
+ "refill_requirements": refill_requirements.json,
357
358
  "is_refill_required": is_refill_required,
358
359
  "pending_backup_owner_swaps": pending_backup_owner_swaps,
359
360
  }