strideutils 0.3.3__tar.gz → 0.3.4__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 (33) hide show
  1. {strideutils-0.3.3 → strideutils-0.3.4}/PKG-INFO +1 -1
  2. {strideutils-0.3.3 → strideutils-0.3.4}/pyproject.toml +1 -1
  3. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/stride_config.py +2 -0
  4. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/stride_requests.py +291 -8
  5. strideutils-0.3.4/strideutils/types.py +23 -0
  6. {strideutils-0.3.3 → strideutils-0.3.4}/README.md +0 -0
  7. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/Makefile +0 -0
  8. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/__init__.py +0 -0
  9. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/coingecko.py +0 -0
  10. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/config_examples/strideutils_config.yaml.example +0 -0
  11. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/config_examples/strideutils_secrets.yaml.example +0 -0
  12. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/cryptography.py +0 -0
  13. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/exec_tx.py +0 -0
  14. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/invariant_helpers.py +0 -0
  15. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/run_safely.py +0 -0
  16. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/sheets_connector.py +0 -0
  17. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/slack_connector.py +0 -0
  18. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/stride_alerts.py +0 -0
  19. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/stride_upstash.py +0 -0
  20. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils/twilio_connector.py +0 -0
  21. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/__init__.pyi +0 -0
  22. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/coingecko.pyi +0 -0
  23. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/cryptography.pyi +0 -0
  24. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/exec_tx.pyi +0 -0
  25. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/invariant_helpers.pyi +0 -0
  26. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/run_safely.pyi +0 -0
  27. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/sheets_connector.pyi +0 -0
  28. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/slack_connector.pyi +0 -0
  29. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/stride_alerts.pyi +0 -0
  30. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/stride_config.pyi +0 -0
  31. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/stride_requests.pyi +0 -0
  32. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/stride_upstash.pyi +0 -0
  33. {strideutils-0.3.3 → strideutils-0.3.4}/strideutils-stubs/twilio_connector.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strideutils
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary:
5
5
  Author: Your Name
6
6
  Author-email: you@example.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "strideutils"
3
- version = "0.3.3"
3
+ version = "0.3.4"
4
4
  description = ""
5
5
  authors = ["Your Name <you@example.com>"]
6
6
  readme = "README.md"
@@ -105,6 +105,8 @@ class HostChainConfig(ChainConfig):
105
105
  denom_on_stride: str = ""
106
106
  # Indicates whether the chain has ICA enabled
107
107
  ica_enabled: bool = True
108
+ # Indicates whether the chain has LSM enabled
109
+ lsm_enabled: bool = False
108
110
 
109
111
  def __repr__(self) -> str:
110
112
  return f"HostChainConfig(name={self.name}, id={self.id})"
@@ -13,7 +13,7 @@ import pytz
13
13
  import requests
14
14
  from requests.adapters import HTTPAdapter, Retry
15
15
 
16
- from strideutils import stride_upstash
16
+ from strideutils import stride_upstash, types
17
17
  from strideutils.stride_config import config
18
18
 
19
19
  ACCOUNT_QUERY = "cosmos/auth/v1beta1/accounts/{address}"
@@ -34,8 +34,12 @@ TX_BY_ACCOUNT_EVENT = "tx.acc_seq='{address}/{sequence}'"
34
34
 
35
35
  HOST_ZONE_QUERY = "Stride-Labs/stride/stakeibc/host_zone"
36
36
  EPOCHS_QUERY = "Stridelabs/stride/epochs"
37
-
37
+ PENDING_ICQ_QUERY = "Stride-Labs/stride/interchainquery/pending_queries"
38
38
  RATE_LIMIT_QUERY = "Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits"
39
+ DEPOSIT_RECORDS_QUERY = "Stride-Labs/stride/records/deposit_record_by_host_zone/{chain_id}"
40
+ UNBONDING_RECORDS_QUERY = "Stride-Labs/stride/records/epoch_unbonding_record"
41
+ LSM_RECORDS_QUERY = "Stride-Labs/stride/stakeibc/lsm_deposits"
42
+ CALLBACK_DATA_QUERY = "Stride-Labs/stride/icacallbacks/callback_data"
39
43
 
40
44
  STAKETIA = "staketia"
41
45
  STAKEDYM = "stakedym"
@@ -50,6 +54,8 @@ MULTISIG_REDEMPTION_RECORDS_QUERY = "Stride-Labs/stride/{module}/redemption_reco
50
54
 
51
55
  COSMWASM_CONTRACT_QUERY = "cosmwasm/wasm/v1/contract/{contract_address}/smart/{query}"
52
56
 
57
+ HOST_CHANNELS_QUERY = "https://channels.main.stridenet.co/api/data/{chain_id}"
58
+
53
59
  requests_session = requests.Session()
54
60
 
55
61
  retries = Retry(total=5, backoff_factor=0.5, status_forcelist=[400, 403, 404, 500, 502, 503, 504])
@@ -244,6 +250,106 @@ def get_host_zone(chain_id: str, cast_types: bool = True, **kwargs) -> Dict[str,
244
250
  return host_zone
245
251
 
246
252
 
253
+ def get_deposit_records(
254
+ chain_id: str,
255
+ status: Optional[types.DepositRecordStatus] = None,
256
+ block_height: int = 0,
257
+ ) -> List[Dict[str, Any]]:
258
+ """
259
+ Queries all the deposit records for a given host zone with optional status filter
260
+
261
+ E.g.
262
+ [
263
+ {
264
+ "id": "36310",
265
+ "amount": "5305210",
266
+ "denom": "uluna",
267
+ "host_zone_id": "phoenix-1",
268
+ "status": "DELEGATION_QUEUE",
269
+ "deposit_epoch_number": "2424",
270
+ "source": "STRIDE"
271
+ },
272
+ ]
273
+ """
274
+ url = f"{config.stride.api_endpoint}/{DEPOSIT_RECORDS_QUERY.format(chain_id=chain_id)}"
275
+ deposit_records = request(url, block_height=block_height)["deposit_record"]
276
+ if status:
277
+ deposit_records = [dr for dr in deposit_records if dr["status"] == status]
278
+ return deposit_records
279
+
280
+
281
+ def get_unbonding_records(
282
+ chain_id: str,
283
+ status: Optional[types.UnbondingRecordStatus] = None,
284
+ block_height: int = 0,
285
+ ) -> List[Dict[str, Any]]:
286
+ """
287
+ Queries all the unbonding records for a given host zone with optional status filter
288
+
289
+ E.g.
290
+ [
291
+ {
292
+ "st_token_amount": "3218590",
293
+ "native_token_amount": "0",
294
+ "denom": "ucmdx",
295
+ "host_zone_id": "comdex-1",
296
+ "unbonding_time": "1713812526371636619",
297
+ "status": "CLAIMABLE",
298
+ "user_redemption_records": [
299
+ "comdex-1.575.comdex1gwnfjj65zhxmtnpxzy625cpx692lfjuwlqeg8p",
300
+ ...
301
+ ]
302
+ },
303
+ ...
304
+ ]
305
+ """
306
+ # Query the epoch unbonding records
307
+ url = f"{config.stride.api_endpoint}/{UNBONDING_RECORDS_QUERY}"
308
+ epoch_unbondings = query_list_with_pagination(url, rel_key="epoch_unbonding_record", block_height=block_height)
309
+
310
+ # The structure from the response consists of:
311
+ # - List of epoch unbonding records - one record per epoch
312
+ # - Within each epoch unbonding record, there's one host zone unbonding record per host
313
+ # This function returns the host zone unbonding record
314
+ host_zone_unbondings = []
315
+ for epoch_unbonding in epoch_unbondings:
316
+ for host_zone_unbonding in epoch_unbonding["host_zone_unbondings"]:
317
+
318
+ chain_id_match = host_zone_unbonding["host_zone_id"] == chain_id
319
+ status_match = not status or host_zone_unbonding["status"] == status
320
+
321
+ if chain_id_match and status_match:
322
+ host_zone_unbondings.append(host_zone_unbonding)
323
+
324
+ return host_zone_unbondings
325
+
326
+
327
+ def get_lsm_deposit_records(chain_id: str) -> List[Dict[str, Any]]:
328
+ """
329
+ Queries all the LSM deposit records
330
+
331
+ [
332
+ {
333
+ "deposit_id": "800000.cosmoshub-4.strideXXX.cosmosvaloperXXX/1",
334
+ "chain_id": "cosmoshub-4",
335
+ "ibc_denom": "ibc/cosmosvaloperXXX/1",
336
+ "staker_address": "strideXXX",
337
+ "validator_address": "cosmosvaloperXXX",
338
+ "amount": "10000",
339
+ "st_token": {
340
+ "amount": "10000",
341
+ "denom": "stuatom"
342
+ }
343
+ "status": "DEPOSIT_PENDING"
344
+ },
345
+ ]
346
+ """
347
+ params = {"chain_id": chain_id}
348
+ url = f"{config.stride.api_endpoint}/{LSM_RECORDS_QUERY}"
349
+ deposit_records = request(url, params=params)["deposits"]
350
+ return deposit_records
351
+
352
+
247
353
  def get_multisig_delegation_records(module: str, include_archived: bool = False) -> List[Dict]:
248
354
  """
249
355
  Queries the delegation records from staketia or stakedym
@@ -338,6 +444,76 @@ def get_rate_limits(**kwargs):
338
444
  return host_zone
339
445
 
340
446
 
447
+ def get_pending_interchain_queries(chain_id: Optional[str] = None, block_height: int = 0) -> List[Dict[str, Any]]:
448
+ """
449
+ Gets the list of all pending ICQs on stride
450
+
451
+ E.g.
452
+ [
453
+ {
454
+ "id": "86170fade2b01f18a1f5e448c8a9dabdc60293151828f881a40708396ec383e0",
455
+ "connection_id": "connection-0",
456
+ "chain_id": "cosmoshub-4",
457
+ "query_type": "store/bank/key",
458
+ "request_data": ...bytestring...,
459
+ "callback_module": "stakeibc",
460
+ "callback_id": "withdrawalbalance",
461
+ "callback_data": ...bytestring...,
462
+ "timeout_policy": "REJECT_QUERY_RESPONSE",
463
+ "timeout_duration": "1hr",
464
+ "timeout_timestamp": "1714689884000000000",
465
+ "request_sent": true,
466
+ "submission_height": 80000
467
+ }
468
+ ...
469
+ ]
470
+ """
471
+ url = f"{config.stride.api_endpoint}/{PENDING_ICQ_QUERY}"
472
+ queries = request(url, block_height=block_height)["pending_queries"]
473
+ if chain_id:
474
+ queries = [query for query in queries if query["chain_id"] == chain_id]
475
+ return queries
476
+
477
+
478
+ def get_callback_data(
479
+ chain_id: Optional[str] = None,
480
+ channel_id: Optional[str] = None,
481
+ port_id: Optional[str] = None,
482
+ callback_id: Optional[str] = None,
483
+ block_height: int = 0,
484
+ ) -> List[Dict[str, Any]]:
485
+ """
486
+ Gets all the ica or ibc callback data stored on stride, with optional filters
487
+
488
+ E.g.
489
+ [
490
+ {
491
+ "callback_key": "icacontroller-cosmoshub-4.DELEGATION.channel-1.23",
492
+ "port_id": "icacontroller-cosmoshub-4.DELEGATION",
493
+ "channel_id": "channel-1",
494
+ "sequence": "23",
495
+ "callback_id": "delegate",
496
+ "callback_args": "...bytestring..."
497
+ }
498
+ ]
499
+ """
500
+ url = f"{config.stride.api_endpoint}/{CALLBACK_DATA_QUERY}"
501
+ callback_data = query_list_with_pagination(url, rel_key="callback_data", block_height=block_height)
502
+
503
+ filtered_callback_data = []
504
+ for data in callback_data:
505
+
506
+ chain_id_match = not chain_id or chain_id in data["port_id"]
507
+ channel_id_match = not channel_id or data["channel_id"] == channel_id
508
+ port_id_match = not port_id or data["port_id"] == port_id
509
+ callback_id_match = not callback_id or data["callback_id"] == callback_id
510
+
511
+ if all([chain_id_match, channel_id_match, port_id_match, callback_id_match]):
512
+ filtered_callback_data.append(data)
513
+
514
+ return filtered_callback_data
515
+
516
+
341
517
  def get_validators(api_endpoint: str = config.stride.api_endpoint) -> List[Dict[str, Any]]:
342
518
  """
343
519
  Queries the list of validators from a chain
@@ -790,17 +966,124 @@ def get_epochs() -> List[Dict]:
790
966
  return epochs["epochs"]
791
967
 
792
968
 
793
- def get_day_epoch() -> int:
969
+ def get_day_epoch() -> Dict[str, Any]:
794
970
  """
795
- Get the day epoch from the stride-labs/stride/epochs endpoint
971
+ Returns the "day" epoch struct on Stride
972
+
973
+ E.g.
974
+ {
975
+ "identifier": "day",
976
+ "start_time": "2022-09-04T19:00:00.451745Z",
977
+ "duration": "86400s",
978
+ "current_epoch": "607",
979
+ "current_epoch_start_time": "2024-05-02T19:00:00.451745Z",
980
+ "epoch_counting_started": true,
981
+ "current_epoch_start_height": "8829138"
982
+ }
796
983
  """
797
- epochs_request = f"{config.stride.api_endpoint}/Stridelabs/stride/epochs"
798
- epochs = request(epochs_request)["epochs"]
799
- epochs_df = pd.DataFrame(epochs)
800
- day_epoch = int(epochs_df[epochs_df["identifier"] == "day"]["current_epoch"].values[0])
984
+ epochs = get_epochs()
985
+ day_epoch = [epoch for epoch in epochs if epoch["identifier"] == "day"][0]
801
986
  return day_epoch
802
987
 
803
988
 
989
+ def get_stride_epoch() -> Dict[str, Any]:
990
+ """
991
+ Returns the "stride" epoch struct on stride
992
+
993
+ E.g.
994
+ {
995
+ "identifier": "stride_epoch",
996
+ "start_time": "2022-09-04T19:00:00.451745Z",
997
+ "duration": "21600s",
998
+ "current_epoch": "2425",
999
+ "current_epoch_start_time": "2024-05-02T19:00:00.451745Z",
1000
+ "epoch_counting_started": true,
1001
+ "current_epoch_start_height": "8829138"
1002
+ }
1003
+ """
1004
+ epochs = get_epochs()
1005
+ stride_epoch = [epoch for epoch in epochs if epoch["identifier"] == "stride_epoch"][0]
1006
+ return stride_epoch
1007
+
1008
+
1009
+ def get_stride_epoch_number() -> int:
1010
+ """
1011
+ Returns the epoch number for the current "stride" epoch
1012
+ """
1013
+ stride_epoch = get_stride_epoch()
1014
+ return int(stride_epoch["current_epoch"])
1015
+
1016
+
1017
+ def get_day_epoch_number() -> int:
1018
+ """
1019
+ Returns the epoch number for the current "day" epoch
1020
+ """
1021
+ day_epoch = get_day_epoch()
1022
+ return int(day_epoch["current_epoch"])
1023
+
1024
+
1025
+ def get_stride_epoch_start_time() -> datetime.datetime:
1026
+ """
1027
+ Returns the epoch start time for the current "stride" epoch
1028
+ """
1029
+ stride_epoch = get_stride_epoch()
1030
+ return dateutil.parser.parse(stride_epoch["current_epoch_start_time"]).replace(tzinfo=None)
1031
+
1032
+
1033
+ def get_day_epoch_start_time() -> datetime.datetime:
1034
+ """
1035
+ Returns the epoch start time for the current "day" epoch
1036
+ """
1037
+ day_epoch = get_day_epoch()
1038
+ return dateutil.parser.parse(day_epoch["current_epoch_start_time"]).replace(tzinfo=None)
1039
+
1040
+
1041
+ def get_stride_epoch_start_height() -> int:
1042
+ """
1043
+ Returns the epoch start time for the current "stride" epoch
1044
+ """
1045
+ stride_epoch = get_stride_epoch()
1046
+ return int(stride_epoch["current_epoch_start_height"])
1047
+
1048
+
1049
+ def get_day_epoch_start_height() -> int:
1050
+ """
1051
+ Returns the epoch start time for the current "day" epoch
1052
+ """
1053
+ day_epoch = get_day_epoch()
1054
+ return int(day_epoch["current_epoch_start_height"])
1055
+
1056
+
1057
+ def get_host_zone_channels(chain_id: str) -> Dict[str, Any]:
1058
+ """
1059
+ Returns the JSON response from the channels endpoint, which holds the client and connection info,
1060
+ as well as all the ICA channels
1061
+
1062
+ E.g.
1063
+ {
1064
+ "chain_id": "cosmoshub-4",
1065
+ "client_id": "07-tendermint-0",
1066
+ "counterparty_client_id": "07-tendermint-913",
1067
+ "connection_id": "connection-0",
1068
+ "counterparty_connection_id": "connection-635",
1069
+ "transfer_channel_id": "channel-0",
1070
+ "counterparty_transfer_channel_id": "channel-391",
1071
+ "ica_channels": [
1072
+ {
1073
+ "type": "DELEGATION",
1074
+ "port_id": "icacontroller-cosmoshub-4.DELEGATION",
1075
+ "channel_id": "channel-203",
1076
+ "counterparty_channel_id": "channel-810",
1077
+ "state": "STATE_OPEN",
1078
+ "counterparty_state": "STATE_OPEN"
1079
+ },
1080
+ ...
1081
+ ]
1082
+ }
1083
+ """
1084
+ return request(HOST_CHANNELS_QUERY.format(chain_id=chain_id))
1085
+
1086
+
804
1087
  def query_wasm_contract(contract_address: str, query_msg: Dict, api_endpoint: str, block_height: int = 0) -> Dict:
805
1088
  """
806
1089
  Queries a cosmowasm contract address with the provided query message
@@ -0,0 +1,23 @@
1
+ from enum import Enum
2
+
3
+
4
+ class DepositRecordStatus(str, Enum):
5
+ TRANSFER_QUEUE = "TRANSFER_QUEUE"
6
+ TRANSFER_IN_PROGRESS = "TRANSFER_IN_PROGRESS"
7
+ DELEGATION_QUEUE = "DELEGATION_QUEUE"
8
+ DELEGATION_IN_PROGRESS = "DELEGATION_IN_PROGRESS"
9
+
10
+
11
+ class CallbackId(str, Enum):
12
+ TRANSFER = "transfer"
13
+ DELEGATE = "delegate"
14
+ UNDELEGATE = "undelegate"
15
+ REDEMPTION = "redemption"
16
+
17
+
18
+ class UnbondingRecordStatus(str, Enum):
19
+ UNBONDING_QUEUE = "UNBONDING_QUEUE"
20
+ UNBONDING_IN_PROGRESS = "UNBONDING_IN_PROGRESS"
21
+ EXIT_TRANSFER_QUEUE = "EXIT_TRANSFER_QUEUE"
22
+ EXIT_TRANSFER_IN_PROGRESS = "EXIT_TRANSFER_IN_PROGRESS"
23
+ CLAIMABLE = "CLAIMABLE"
File without changes