strideutils 0.3.6__tar.gz → 0.3.8__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.6 → strideutils-0.3.8}/PKG-INFO +1 -1
  2. {strideutils-0.3.6 → strideutils-0.3.8}/pyproject.toml +1 -1
  3. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/coingecko.py +30 -11
  4. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/stride_config.py +1 -1
  5. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/stride_requests.py +43 -40
  6. {strideutils-0.3.6 → strideutils-0.3.8}/README.md +0 -0
  7. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/Makefile +0 -0
  8. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/__init__.py +0 -0
  9. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/config_examples/strideutils_config.yaml.example +0 -0
  10. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/config_examples/strideutils_secrets.yaml.example +0 -0
  11. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/cryptography.py +0 -0
  12. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/exec_tx.py +0 -0
  13. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/invariant_helpers.py +0 -0
  14. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/run_safely.py +0 -0
  15. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/sheets_connector.py +0 -0
  16. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/slack_connector.py +0 -0
  17. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/stride_alerts.py +0 -0
  18. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/stride_upstash.py +0 -0
  19. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/twilio_connector.py +0 -0
  20. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils/types.py +0 -0
  21. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/__init__.pyi +0 -0
  22. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/coingecko.pyi +0 -0
  23. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/cryptography.pyi +0 -0
  24. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/exec_tx.pyi +0 -0
  25. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/invariant_helpers.pyi +0 -0
  26. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/run_safely.pyi +0 -0
  27. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/sheets_connector.pyi +0 -0
  28. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/slack_connector.pyi +0 -0
  29. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/stride_alerts.pyi +0 -0
  30. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/stride_config.pyi +0 -0
  31. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/stride_requests.pyi +0 -0
  32. {strideutils-0.3.6 → strideutils-0.3.8}/strideutils-stubs/stride_upstash.pyi +0 -0
  33. {strideutils-0.3.6 → strideutils-0.3.8}/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.6
3
+ Version: 0.3.8
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.6"
3
+ version = "0.3.8"
4
4
  description = ""
5
5
  authors = ["Your Name <you@example.com>"]
6
6
  readme = "README.md"
@@ -12,6 +12,7 @@ from strideutils.stride_config import config
12
12
 
13
13
  COINGECKO_ENDPOINT = "https://pro-api.coingecko.com/"
14
14
  COINGECKO_PRICE_QUERY = "api/v3/simple/price?ids={ticker_id}&vs_currencies=usd"
15
+ COINGECKO_TVL_QUERY = "api/v3/coins/{ticker_id}"
15
16
 
16
17
 
17
18
  def get_coingecko_name(chain_config: stride_config.ChainConfig) -> str:
@@ -31,7 +32,6 @@ def get_token_price(
31
32
  ):
32
33
  """
33
34
  Reads token price from coingecko
34
- If a redis_client is provided, then store the value.
35
35
  """
36
36
  # TODO: Consider using the coingecko ID for stTokens instead of the redemption rate
37
37
  # Get redemption rate for calculating st token prices
@@ -53,6 +53,23 @@ def get_token_price(
53
53
  return price
54
54
 
55
55
 
56
+ def get_tvl(
57
+ chain_config: stride_config.ChainConfig,
58
+ api_token: str = config.COINGECKO_API_TOKEN,
59
+ cache_response: bool = False,
60
+ ) -> float:
61
+ """
62
+ Fetch TVL from coingecko in USD
63
+ """
64
+ coingecko_name = get_coingecko_name(chain_config)
65
+ endpoint = COINGECKO_ENDPOINT + COINGECKO_TVL_QUERY.format(ticker_id=coingecko_name)
66
+ headers = {'x-cg-pro-api-key': api_token}
67
+
68
+ # The data structure is huge https://docs.coingecko.com/reference/coins-id
69
+ response = stride_requests.request(endpoint, headers=headers, cache_response=cache_response)
70
+ return float(response['market_data']['market_cap']['usd'])
71
+
72
+
56
73
  def get_token_price_history(token: str, num_days=90, use_key=False, memo={}) -> pd.Series:
57
74
  """
58
75
  returns a Pandas Series with token price data going back num_days
@@ -62,17 +79,18 @@ def get_token_price_history(token: str, num_days=90, use_key=False, memo={}) ->
62
79
  price_key = (token, num_days)
63
80
  if price_key not in memo:
64
81
  tstr = get_coingecko_name(config.get_chain(ticker=token))
65
- rurl = f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}"
66
- rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN}
67
- if not use_key:
68
- rel_headers = None
82
+ rurl = (
83
+ f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
84
+ )
85
+ rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN} if use_key else None
86
+
69
87
  r = requests.get(
70
88
  rurl,
71
89
  headers=rel_headers,
72
90
  )
73
91
  assert r.status_code == 200
74
92
  out_df = pd.DataFrame(r.json()["prices"])
75
- out_df.columns = ["time", "price"]
93
+ out_df.columns = pd.Index(["time", "price"])
76
94
  out_df["time"] = pd.to_datetime(out_df["time"], unit="ms")
77
95
  out_df["price"] = out_df["price"].astype(float)
78
96
  out_df.set_index("time", inplace=True)
@@ -89,17 +107,18 @@ def get_token_volume_history(token: str, num_days=90, use_key=False, memo={}) ->
89
107
  volume_key = (token, num_days)
90
108
  if volume_key not in memo:
91
109
  tstr = get_coingecko_name(config.get_chain(ticker=token))
92
- rurl = f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}"
93
- rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN}
94
- if not use_key:
95
- rel_headers = None
110
+ rurl = (
111
+ f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
112
+ )
113
+ rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN} if use_key else None
114
+
96
115
  r = requests.get(
97
116
  rurl,
98
117
  headers=rel_headers,
99
118
  )
100
119
  assert r.status_code == 200
101
120
  out_df = pd.DataFrame(r.json()["total_volumes"])
102
- out_df.columns = ["time", "volume"]
121
+ out_df.columns = pd.Index(["time", "volume"])
103
122
  out_df["time"] = pd.to_datetime(out_df["time"], unit="ms")
104
123
  out_df["volume"] = out_df["volume"].astype(float)
105
124
  out_df.set_index("time", inplace=True)
@@ -361,7 +361,7 @@ def _parse_raw_configs(raw_config: dict[str, Any], raw_secrets: dict[str, Option
361
361
  # Load non-nested configs, then overwrite with the chain configs
362
362
  config_dict = raw_secrets
363
363
  config_dict.update(raw_config)
364
- config_dict.update(chain_configs)
364
+ config_dict.update(chain_configs) # type: ignore
365
365
  return Config(**config_dict) # type: ignore
366
366
 
367
367
 
@@ -811,64 +811,67 @@ def generate_vesting_account(
811
811
 
812
812
 
813
813
  def get_block_height_in_past(
814
- time_in_past: datetime.timedelta = datetime.timedelta(hours=24),
815
- max_acceptable_error_seconds: int = 60 * 5,
814
+ target_time: Optional[datetime.datetime] = None,
815
+ target_time_offset: Optional[datetime.timedelta] = None,
816
+ error_tolerance: datetime.timedelta = datetime.timedelta(minutes=5),
816
817
  seconds_per_block: int = 6,
817
- prev_time: Optional[str] = None,
818
- verbose: bool = False,
819
818
  rpc_endpoint: str = config.stride.rpc_endpoint,
820
819
  ) -> int:
821
820
  """
822
821
  Gets the block height at a specified time by binary searching at different heights
823
822
 
824
823
  Args:
825
- time_in_past: target time to search for
826
- max_acceptable_error_seconds: max time delta before the height is considered find
824
+ target_time (datetime): the target time to search for
825
+ (e.g. search for the block at time 2024-01-01 01:00:00 UTC)
826
+ target_time_offset (timedelta): the target time to search for,
827
+ defined as an offset from the current time
828
+ (e.g. search for the block 24 hours ago)
829
+ error_tolerance (timedelta): max time delta before the height is considered found
827
830
  seconds_per_block: block time to use for the estimation start
828
- prev_time: Optional time to start the search at (instead of using time_in_past)
829
831
 
830
832
  Returns:
831
833
  The block height at the specified time
832
834
  """
835
+ # Get the current time and latest block height
836
+ current_time = datetime.datetime.now(tz=datetime.timezone.utc)
833
837
  latest_block = get_latest_block(rpc_endpoint=rpc_endpoint)
834
838
 
835
- # set parameters so we can search for the block height
836
- blocks_per_day = (24 * 60 * 60) // seconds_per_block
837
- if prev_time is not None:
838
- if type(prev_time) is str:
839
- prev_time: datetime.datetime = pd.to_datetime(prev_time) # type: ignore
840
- ts = (datetime.datetime.utcnow() - cast(datetime.datetime, prev_time)).total_seconds()
841
- num_days_back = ts / (60 * 60 * 24)
842
- time_in_past = datetime.timedelta(seconds=ts)
839
+ # Depending on whether the target time or target_time_offset was used,
840
+ # calculate the parameter that was not provided
841
+ if target_time and not target_time_offset:
842
+ target_time_offset = current_time - target_time
843
+ elif target_time_offset and not target_time:
844
+ target_time = current_time - target_time_offset
843
845
  else:
844
- num_days_back = time_in_past.total_seconds() / (60 * 60 * 24)
845
- blocks_in_past = int(num_days_back * blocks_per_day)
846
- time_estimate_error = float(100000)
847
-
848
- current_time = datetime.datetime.utcnow()
849
-
850
- # do an iterative search to find the block
851
- while abs(time_estimate_error) > max_acceptable_error_seconds:
852
- backwards_looking_height = latest_block - blocks_in_past
853
- backwards_looking_time = get_block_time(backwards_looking_height, rpc_endpoint=rpc_endpoint)
854
- time_estimate_error = (current_time - backwards_looking_time - time_in_past).total_seconds()
855
- error_in_blocks = time_estimate_error / seconds_per_block
856
- blocks_in_past -= int(error_in_blocks)
857
- if verbose:
858
- print("\tEstimated block: {}".format(backwards_looking_height))
859
- print("\tEstimated time: {}".format(backwards_looking_time))
860
- print("\tError in blocks: {}".format(error_in_blocks))
861
- print("\tTotal Seconds: {}".format(time_estimate_error))
862
- print("\t-------------------------")
863
- block_last_day = latest_block - blocks_in_past
864
- return block_last_day
865
-
866
-
867
- def get_block_height_one_day_ago(verbose: bool = False) -> int:
846
+ raise ValueError("Either target time or target time offset must be specified (but not both)")
847
+
848
+ # Using the target offset, determine the block delta to start our search, based
849
+ # on the estimated block time
850
+ blocks_in_past = int(target_time_offset.total_seconds() / seconds_per_block)
851
+ estimated_height = latest_block - blocks_in_past
852
+
853
+ # Continually loop over the following until we find a block that lines up with
854
+ # our target time (within our margin of error)
855
+ # - Guess a height
856
+ # - Find the time at that height
857
+ # - Check if the time is close enough to our target
858
+ # - Refine our block height guess and repeat
859
+ while True:
860
+ estimated_time = get_block_time(estimated_height, rpc_endpoint=rpc_endpoint)
861
+
862
+ time_error = target_time.timestamp() - estimated_time.timestamp()
863
+ if abs(time_error) < error_tolerance.total_seconds():
864
+ return estimated_height
865
+
866
+ blocks_correction = int(time_error / seconds_per_block)
867
+ estimated_height += blocks_correction
868
+
869
+
870
+ def get_block_height_one_day_ago() -> int:
868
871
  """
869
872
  Get the block height from 1 day ago
870
873
  """
871
- return get_block_height_in_past(datetime.timedelta(hours=24), verbose=verbose)
874
+ return get_block_height_in_past(target_time_offset=datetime.timedelta(hours=24))
872
875
 
873
876
 
874
877
  def get_sttoken_apr(token: str) -> Optional[float]:
File without changes