strideutils 0.3.6__tar.gz → 0.3.15__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.
- {strideutils-0.3.6 → strideutils-0.3.15}/PKG-INFO +2 -1
- {strideutils-0.3.6 → strideutils-0.3.15}/pyproject.toml +2 -1
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/coingecko.py +30 -11
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/config_examples/strideutils_secrets.yaml.example +5 -1
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/exec_tx.py +2 -2
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/run_safely.py +5 -3
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/stride_config.py +9 -1
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/stride_requests.py +101 -41
- {strideutils-0.3.6 → strideutils-0.3.15}/README.md +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/Makefile +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/__init__.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/config_examples/strideutils_config.yaml.example +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/cryptography.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/invariant_helpers.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/sheets_connector.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/slack_connector.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/stride_alerts.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/stride_upstash.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/twilio_connector.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils/types.py +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/__init__.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/coingecko.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/cryptography.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/exec_tx.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/invariant_helpers.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/run_safely.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/sheets_connector.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/slack_connector.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/stride_alerts.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/stride_config.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/stride_requests.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/strideutils-stubs/stride_upstash.pyi +0 -0
- {strideutils-0.3.6 → strideutils-0.3.15}/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
|
+
Version: 0.3.15
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Your Name
|
|
6
6
|
Author-email: you@example.com
|
|
@@ -9,6 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
11
|
Requires-Dist: bech32 (>=1.2.0)
|
|
12
|
+
Requires-Dist: boto3 (>=1.34.115,<2.0.0)
|
|
12
13
|
Requires-Dist: google-api-python-client (>=2.100.0)
|
|
13
14
|
Requires-Dist: google-auth-httplib2 (>=0.1.1)
|
|
14
15
|
Requires-Dist: google-auth-oauthlib (>=1.1.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "strideutils"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.15"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Your Name <you@example.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -24,6 +24,7 @@ tabulate = ">=0.9.0"
|
|
|
24
24
|
pyyaml = ">=6.0.1"
|
|
25
25
|
python-dateutil = ">=2.8.2"
|
|
26
26
|
pycryptodome = ">=3.20.0"
|
|
27
|
+
boto3 = "^1.34.115"
|
|
27
28
|
|
|
28
29
|
[tool.poetry.group.dev.dependencies]
|
|
29
30
|
pytest = "^8.1.1"
|
|
@@ -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 =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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)
|
|
@@ -33,10 +33,10 @@ def execute_tx(command: str, api_endpoint: str = config.stride.api_endpoint) ->
|
|
|
33
33
|
|
|
34
34
|
tx_response = None
|
|
35
35
|
response_success = False
|
|
36
|
-
raw_log = ""
|
|
36
|
+
raw_log = "Transaction not found on chain after one minute" # default message
|
|
37
37
|
if not error_out:
|
|
38
38
|
event_filters = [(f"tx.hash='{tx_hash}'")]
|
|
39
|
-
for _ in range(
|
|
39
|
+
for _ in range(30):
|
|
40
40
|
time.sleep(2)
|
|
41
41
|
tx_response = stride_requests.get_txs(event_filters, api_endpoint)
|
|
42
42
|
if tx_response['total'] != '0':
|
|
@@ -29,13 +29,15 @@ def try_and_log_with_status(
|
|
|
29
29
|
# (to cover cases where click was used)
|
|
30
30
|
func_name = getattr(func, 'name', None) or func.__name__
|
|
31
31
|
try:
|
|
32
|
+
print(f"Running {func_name}...", end="")
|
|
32
33
|
func()
|
|
33
|
-
|
|
34
|
+
print("✅")
|
|
35
|
+
msgs += [f':white_check_mark: {func_name}']
|
|
34
36
|
except Exception:
|
|
37
|
+
print("❌")
|
|
35
38
|
print(traceback.format_exc())
|
|
36
|
-
|
|
39
|
+
msgs += [f':x: {func_name} ']
|
|
37
40
|
tracebacks.append(f"{func_name} \n\n" + traceback.format_exc())
|
|
38
|
-
msgs += msg
|
|
39
41
|
|
|
40
42
|
count_succeeded_msg = f"{len(functions) - len(tracebacks)}/{len(functions)} {job_name} succeeded"
|
|
41
43
|
if len(tracebacks) > 0:
|
|
@@ -78,6 +78,7 @@ class ChainConfig(ConfigObj):
|
|
|
78
78
|
ticker: str = ""
|
|
79
79
|
api_endpoint: str = ""
|
|
80
80
|
rpc_endpoint: str = ""
|
|
81
|
+
evm_chain: bool = False
|
|
81
82
|
|
|
82
83
|
def __repr__(self) -> str:
|
|
83
84
|
return f"ChainConfig(name={self.name}, id={self.id})"
|
|
@@ -152,6 +153,9 @@ class AppChainsConfig(ConfigObj):
|
|
|
152
153
|
mars: ChainConfig = field(default_factory=ChainConfig)
|
|
153
154
|
canto: ChainConfig = field(default_factory=ChainConfig)
|
|
154
155
|
agoric: ChainConfig = field(default_factory=ChainConfig)
|
|
156
|
+
sei: ChainConfig = field(default_factory=ChainConfig)
|
|
157
|
+
noble: ChainConfig = field(default_factory=ChainConfig)
|
|
158
|
+
forma: ChainConfig = field(default_factory=ChainConfig)
|
|
155
159
|
|
|
156
160
|
|
|
157
161
|
@dataclass(repr=False)
|
|
@@ -195,6 +199,10 @@ class Config(ConfigObj):
|
|
|
195
199
|
NUMIA_API_TOKEN: str = ""
|
|
196
200
|
founders: List[str] = field(default_factory=lambda: ['riley', 'aidan', 'vishal'])
|
|
197
201
|
|
|
202
|
+
# AWS
|
|
203
|
+
AWS_ACCESS_KEY_ID: str = ""
|
|
204
|
+
AWS_SECRET_ACCESS_KEY: str = ""
|
|
205
|
+
|
|
198
206
|
# Chain configs
|
|
199
207
|
stride: StrideChainConfig = field(default_factory=StrideChainConfig)
|
|
200
208
|
host_zones: HostChainsConfig = field(default_factory=HostChainsConfig)
|
|
@@ -361,7 +369,7 @@ def _parse_raw_configs(raw_config: dict[str, Any], raw_secrets: dict[str, Option
|
|
|
361
369
|
# Load non-nested configs, then overwrite with the chain configs
|
|
362
370
|
config_dict = raw_secrets
|
|
363
371
|
config_dict.update(raw_config)
|
|
364
|
-
config_dict.update(chain_configs)
|
|
372
|
+
config_dict.update(chain_configs) # type: ignore
|
|
365
373
|
return Config(**config_dict) # type: ignore
|
|
366
374
|
|
|
367
375
|
|
|
@@ -37,6 +37,7 @@ PENDING_ICQ_QUERY = "Stride-Labs/stride/interchainquery/pending_queries"
|
|
|
37
37
|
RATE_LIMIT_QUERY = "Stride-Labs/ibc-rate-limiting/ratelimit/ratelimits"
|
|
38
38
|
DEPOSIT_RECORDS_QUERY = "Stride-Labs/stride/records/deposit_record_by_host_zone/{chain_id}"
|
|
39
39
|
UNBONDING_RECORDS_QUERY = "Stride-Labs/stride/records/epoch_unbonding_record"
|
|
40
|
+
REDEMPTION_RECORDS_QUERY = "Stride-Labs/stride/records/user_redemption_record"
|
|
40
41
|
LSM_RECORDS_QUERY = "Stride-Labs/stride/stakeibc/lsm_deposits"
|
|
41
42
|
CALLBACK_DATA_QUERY = "Stride-Labs/stride/icacallbacks/callback_data"
|
|
42
43
|
|
|
@@ -67,6 +68,7 @@ def request(
|
|
|
67
68
|
url: str,
|
|
68
69
|
headers: dict = {},
|
|
69
70
|
params: Union[dict, List[Tuple[str, str]]] = {},
|
|
71
|
+
data: Optional[str] = None,
|
|
70
72
|
block_height: int = 0,
|
|
71
73
|
cache_response: bool = False,
|
|
72
74
|
_cache: Dict[str, Any] = {},
|
|
@@ -95,7 +97,7 @@ def request(
|
|
|
95
97
|
if type(params) is dict:
|
|
96
98
|
params = list(params.items())
|
|
97
99
|
|
|
98
|
-
resp = requests_session.get(url, headers=headers, params=params)
|
|
100
|
+
resp = requests_session.get(url, headers=headers, params=params, data=data)
|
|
99
101
|
if not resp.ok: # resp.ok is true if state_code is less than 400
|
|
100
102
|
print(f"Error fetching {url}: {resp.status_code} {resp.json()}")
|
|
101
103
|
raise Exception(f"Error fetching {url}: {resp.status_code} {resp.json()}")
|
|
@@ -381,6 +383,33 @@ def get_unbonded_records(
|
|
|
381
383
|
return filtered_unbonding_records
|
|
382
384
|
|
|
383
385
|
|
|
386
|
+
def get_user_redemption_records(chain_id: Optional[str] = None) -> list[dict]:
|
|
387
|
+
"""
|
|
388
|
+
Queries all user redemption records with optional chain_id filter
|
|
389
|
+
|
|
390
|
+
[
|
|
391
|
+
{
|
|
392
|
+
"id": "comdex-1.601.comdex1fq0klaec7s59drpl93w6yycgqqtd3d38d34zn0",
|
|
393
|
+
"receiver": "comdex1fq0klaec7s59drpl93w6yycgqqtd3d38d34zn0",
|
|
394
|
+
"native_token_amount": "63303481323",
|
|
395
|
+
"denom": "ucmdx",
|
|
396
|
+
"host_zone_id": "comdex-1",
|
|
397
|
+
"epoch_number": "601",
|
|
398
|
+
"claim_is_pending": false,
|
|
399
|
+
"st_token_amount": "51025461480"
|
|
400
|
+
},
|
|
401
|
+
...
|
|
402
|
+
"""
|
|
403
|
+
url = f"{config.stride.api_endpoint}/{REDEMPTION_RECORDS_QUERY}"
|
|
404
|
+
redemption_records = query_list_with_pagination(url, rel_key="user_redemption_record", max_pages=50)
|
|
405
|
+
|
|
406
|
+
if not chain_id:
|
|
407
|
+
return redemption_records
|
|
408
|
+
|
|
409
|
+
redemption_records = [rr for rr in redemption_records if rr["host_zone_id"] == chain_id]
|
|
410
|
+
return redemption_records
|
|
411
|
+
|
|
412
|
+
|
|
384
413
|
def get_lsm_deposit_records(chain_id: str) -> List[Dict[str, Any]]:
|
|
385
414
|
"""
|
|
386
415
|
Queries all the LSM deposit records
|
|
@@ -811,64 +840,67 @@ def generate_vesting_account(
|
|
|
811
840
|
|
|
812
841
|
|
|
813
842
|
def get_block_height_in_past(
|
|
814
|
-
|
|
815
|
-
|
|
843
|
+
target_time: Optional[datetime.datetime] = None,
|
|
844
|
+
target_time_offset: Optional[datetime.timedelta] = None,
|
|
845
|
+
error_tolerance: datetime.timedelta = datetime.timedelta(minutes=5),
|
|
816
846
|
seconds_per_block: int = 6,
|
|
817
|
-
prev_time: Optional[str] = None,
|
|
818
|
-
verbose: bool = False,
|
|
819
847
|
rpc_endpoint: str = config.stride.rpc_endpoint,
|
|
820
848
|
) -> int:
|
|
821
849
|
"""
|
|
822
850
|
Gets the block height at a specified time by binary searching at different heights
|
|
823
851
|
|
|
824
852
|
Args:
|
|
825
|
-
|
|
826
|
-
|
|
853
|
+
target_time (datetime): the target time to search for
|
|
854
|
+
(e.g. search for the block at time 2024-01-01 01:00:00 UTC)
|
|
855
|
+
target_time_offset (timedelta): the target time to search for,
|
|
856
|
+
defined as an offset from the current time
|
|
857
|
+
(e.g. search for the block 24 hours ago)
|
|
858
|
+
error_tolerance (timedelta): max time delta before the height is considered found
|
|
827
859
|
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
860
|
|
|
830
861
|
Returns:
|
|
831
862
|
The block height at the specified time
|
|
832
863
|
"""
|
|
864
|
+
# Get the current time and latest block height
|
|
865
|
+
current_time = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
833
866
|
latest_block = get_latest_block(rpc_endpoint=rpc_endpoint)
|
|
834
867
|
|
|
835
|
-
#
|
|
836
|
-
|
|
837
|
-
if
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
num_days_back = ts / (60 * 60 * 24)
|
|
842
|
-
time_in_past = datetime.timedelta(seconds=ts)
|
|
868
|
+
# Depending on whether the target time or target_time_offset was used,
|
|
869
|
+
# calculate the parameter that was not provided
|
|
870
|
+
if target_time and not target_time_offset:
|
|
871
|
+
target_time_offset = current_time - target_time
|
|
872
|
+
elif target_time_offset and not target_time:
|
|
873
|
+
target_time = current_time - target_time_offset
|
|
843
874
|
else:
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
875
|
+
raise ValueError("Either target time or target time offset must be specified (but not both)")
|
|
876
|
+
|
|
877
|
+
# Using the target offset, determine the block delta to start our search, based
|
|
878
|
+
# on the estimated block time
|
|
879
|
+
blocks_in_past = int(target_time_offset.total_seconds() / seconds_per_block)
|
|
880
|
+
estimated_height = latest_block - blocks_in_past
|
|
881
|
+
|
|
882
|
+
# Continually loop over the following until we find a block that lines up with
|
|
883
|
+
# our target time (within our margin of error)
|
|
884
|
+
# - Guess a height
|
|
885
|
+
# - Find the time at that height
|
|
886
|
+
# - Check if the time is close enough to our target
|
|
887
|
+
# - Refine our block height guess and repeat
|
|
888
|
+
while True:
|
|
889
|
+
estimated_time = get_block_time(estimated_height, rpc_endpoint=rpc_endpoint)
|
|
890
|
+
|
|
891
|
+
time_error = target_time.timestamp() - estimated_time.timestamp()
|
|
892
|
+
if abs(time_error) < error_tolerance.total_seconds():
|
|
893
|
+
return estimated_height
|
|
894
|
+
|
|
895
|
+
blocks_correction = int(time_error / seconds_per_block)
|
|
896
|
+
estimated_height += blocks_correction
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
def get_block_height_one_day_ago() -> int:
|
|
868
900
|
"""
|
|
869
901
|
Get the block height from 1 day ago
|
|
870
902
|
"""
|
|
871
|
-
return get_block_height_in_past(datetime.timedelta(hours=24)
|
|
903
|
+
return get_block_height_in_past(target_time_offset=datetime.timedelta(hours=24))
|
|
872
904
|
|
|
873
905
|
|
|
874
906
|
def get_sttoken_apr(token: str) -> Optional[float]:
|
|
@@ -1187,3 +1219,31 @@ def get_empirical_annual_fees(ticker: str) -> float:
|
|
|
1187
1219
|
stride_upstash.get("sheet_STRD_STAKING_ST{}_DOLLARS".format(ticker.upper()), db_name="frontend") or "0"
|
|
1188
1220
|
)
|
|
1189
1221
|
return float(cast(str, empirical_dollar_fees))
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
def query_evm_method(method: str, params: list[str], rpc_endpoint: str) -> str:
|
|
1225
|
+
"""
|
|
1226
|
+
Generic querier for evm contract calls
|
|
1227
|
+
Returns a hex endcoded response specific to the contract call
|
|
1228
|
+
"""
|
|
1229
|
+
headers = {"Content-Type": "application/json"}
|
|
1230
|
+
payload = {
|
|
1231
|
+
"jsonrpc": "2.0",
|
|
1232
|
+
"method": method,
|
|
1233
|
+
"params": params,
|
|
1234
|
+
"id": 1,
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
response = request(rpc_endpoint, headers=headers, data=json.dumps(payload))
|
|
1238
|
+
return response["result"]
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
def get_evm_balance(address: str, rpc_endpoint: str) -> int:
|
|
1242
|
+
"""
|
|
1243
|
+
Queries the native token balance of an evm address
|
|
1244
|
+
Address should be a hex address with an 0x prefix
|
|
1245
|
+
"""
|
|
1246
|
+
params = [address, "latest"]
|
|
1247
|
+
balance_raw = query_evm_method("eth_getBalance", params=params, rpc_endpoint=rpc_endpoint)
|
|
1248
|
+
balance = int(balance_raw, 16)
|
|
1249
|
+
return balance
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{strideutils-0.3.6 → strideutils-0.3.15}/strideutils/config_examples/strideutils_config.yaml.example
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|