strideutils 0.4.4__tar.gz → 0.5.0__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.4.4 → strideutils-0.5.0}/PKG-INFO +12 -4
- {strideutils-0.4.4 → strideutils-0.5.0}/README.md +10 -3
- {strideutils-0.4.4 → strideutils-0.5.0}/pyproject.toml +2 -1
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/coingecko.py +5 -11
- strideutils-0.5.0/strideutils/config_examples/env.local.example +24 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/exec_tx.py +4 -2
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/slack_connector.py +21 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/stride_config.py +8 -13
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/stride_requests.py +27 -41
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/stride_upstash.py +47 -3
- strideutils-0.4.4/strideutils/config_examples/strideutils_secrets.yaml.example +0 -28
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/Makefile +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/__init__.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/config_examples/strideutils_config.yaml.example +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/cryptography.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/invariant_helpers.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/run_safely.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/sheets_connector.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/stride_alerts.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/twilio_connector.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils/types.py +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/__init__.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/coingecko.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/cryptography.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/exec_tx.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/invariant_helpers.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/run_safely.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/sheets_connector.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/slack_connector.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/stride_alerts.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/stride_config.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/stride_requests.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/strideutils-stubs/stride_upstash.pyi +0 -0
- {strideutils-0.4.4 → strideutils-0.5.0}/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
|
+
Version: 0.5.0
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Your Name
|
|
6
6
|
Author-email: you@example.com
|
|
@@ -18,6 +18,7 @@ Requires-Dist: gspread (>=6.0.2)
|
|
|
18
18
|
Requires-Dist: pandas (>=2.1.1)
|
|
19
19
|
Requires-Dist: pycryptodome (>=3.20.0)
|
|
20
20
|
Requires-Dist: python-dateutil (>=2.8.2)
|
|
21
|
+
Requires-Dist: python-dotenv (==1.0.1)
|
|
21
22
|
Requires-Dist: pytz (>=2023.3)
|
|
22
23
|
Requires-Dist: pyyaml (>=6.0.1)
|
|
23
24
|
Requires-Dist: redis (>=4.5.4)
|
|
@@ -49,12 +50,11 @@ Strideutils requires three different environment variables that can be added to
|
|
|
49
50
|
|
|
50
51
|
```
|
|
51
52
|
export STRIDEUTILS_CONFIG_PATH=
|
|
52
|
-
export
|
|
53
|
-
export ENV=DEV
|
|
53
|
+
export STRIDEUTILS_ENV_PATH=
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Examples of these files are included under strideutils/config_examples.
|
|
57
|
-
Stride Labs employees can find config.yaml in launchpad and
|
|
57
|
+
Stride Labs employees can find config.yaml in launchpad and .env.local in lastpass. We recommend you place .env.local in your launchpad repo.
|
|
58
58
|
|
|
59
59
|
Any configuration or secrets that aren't consumed don't need to be set. However if one is accessed but unset, an error will be thrown for easier debugging.
|
|
60
60
|
|
|
@@ -77,6 +77,14 @@ import sys
|
|
|
77
77
|
sys.path = ['/path/to/strideutils/'] + sys.path
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
Alternatively, you can install strideutils through local mode. However, please be warned that this will make your local Python environment _always_ use your local strideutils. This might lead to unexpected behavior if you local changes.
|
|
81
|
+
|
|
82
|
+
To install in local mode, run the following:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
pip3 install -e /Users/username/Documents/strideutils
|
|
86
|
+
```
|
|
87
|
+
|
|
80
88
|
Confirm the location of where it's being imported from by printing the module.
|
|
81
89
|
After making changes to strideutils, reload it before testing your application.
|
|
82
90
|
|
|
@@ -20,12 +20,11 @@ Strideutils requires three different environment variables that can be added to
|
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
export STRIDEUTILS_CONFIG_PATH=
|
|
23
|
-
export
|
|
24
|
-
export ENV=DEV
|
|
23
|
+
export STRIDEUTILS_ENV_PATH=
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
Examples of these files are included under strideutils/config_examples.
|
|
28
|
-
Stride Labs employees can find config.yaml in launchpad and
|
|
27
|
+
Stride Labs employees can find config.yaml in launchpad and .env.local in lastpass. We recommend you place .env.local in your launchpad repo.
|
|
29
28
|
|
|
30
29
|
Any configuration or secrets that aren't consumed don't need to be set. However if one is accessed but unset, an error will be thrown for easier debugging.
|
|
31
30
|
|
|
@@ -48,6 +47,14 @@ import sys
|
|
|
48
47
|
sys.path = ['/path/to/strideutils/'] + sys.path
|
|
49
48
|
```
|
|
50
49
|
|
|
50
|
+
Alternatively, you can install strideutils through local mode. However, please be warned that this will make your local Python environment _always_ use your local strideutils. This might lead to unexpected behavior if you local changes.
|
|
51
|
+
|
|
52
|
+
To install in local mode, run the following:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
pip3 install -e /Users/username/Documents/strideutils
|
|
56
|
+
```
|
|
57
|
+
|
|
51
58
|
Confirm the location of where it's being imported from by printing the module.
|
|
52
59
|
After making changes to strideutils, reload it before testing your application.
|
|
53
60
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "strideutils"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Your Name <you@example.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -21,6 +21,7 @@ slack-sdk = ">=3.23.0"
|
|
|
21
21
|
pandas = ">=2.1.1"
|
|
22
22
|
twilio = ">=8.10.0"
|
|
23
23
|
tabulate = ">=0.9.0"
|
|
24
|
+
python-dotenv = "==1.0.1"
|
|
24
25
|
pyyaml = ">=6.0.1"
|
|
25
26
|
python-dateutil = ">=2.8.2"
|
|
26
27
|
pycryptodome = ">=3.20.0"
|
|
@@ -79,11 +79,8 @@ def get_token_price_history(token: str, num_days=90, use_key=False, memo={}) ->
|
|
|
79
79
|
price_key = (token, num_days)
|
|
80
80
|
if price_key not in memo:
|
|
81
81
|
tstr = get_coingecko_name(config.get_chain(ticker=token))
|
|
82
|
-
rurl =
|
|
83
|
-
f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
|
|
84
|
-
)
|
|
82
|
+
rurl = f"{COINGECKO_ENDPOINT}api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
|
|
85
83
|
rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN} if use_key else None
|
|
86
|
-
|
|
87
84
|
r = requests.get(
|
|
88
85
|
rurl,
|
|
89
86
|
headers=rel_headers,
|
|
@@ -98,7 +95,7 @@ def get_token_price_history(token: str, num_days=90, use_key=False, memo={}) ->
|
|
|
98
95
|
return memo[token]
|
|
99
96
|
|
|
100
97
|
|
|
101
|
-
def get_token_volume_history(token: str, num_days=90, use_key=
|
|
98
|
+
def get_token_volume_history(token: str, num_days=90, use_key=True, memo={}) -> pd.Series:
|
|
102
99
|
"""
|
|
103
100
|
returns a Pandas Series with token volume data going back num_days
|
|
104
101
|
e.g. get_token_volume_history('uatom', 30) returns a Series with 30 days of ATOM volume data
|
|
@@ -107,11 +104,8 @@ def get_token_volume_history(token: str, num_days=90, use_key=False, memo={}) ->
|
|
|
107
104
|
volume_key = (token, num_days)
|
|
108
105
|
if volume_key not in memo:
|
|
109
106
|
tstr = get_coingecko_name(config.get_chain(ticker=token))
|
|
110
|
-
rurl =
|
|
111
|
-
f"https://api.coingecko.com/api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
|
|
112
|
-
)
|
|
107
|
+
rurl = f"{COINGECKO_ENDPOINT}api/v3/coins/{tstr}/market_chart?vs_currency=usd&days={num_days}" # noqa:E231
|
|
113
108
|
rel_headers = {"x-cg-pro-api-key": config.COINGECKO_API_TOKEN} if use_key else None
|
|
114
|
-
|
|
115
109
|
r = requests.get(
|
|
116
110
|
rurl,
|
|
117
111
|
headers=rel_headers,
|
|
@@ -126,7 +120,7 @@ def get_token_volume_history(token: str, num_days=90, use_key=False, memo={}) ->
|
|
|
126
120
|
return memo[token]
|
|
127
121
|
|
|
128
122
|
|
|
129
|
-
def get_dataframe_of_prices(token_list: List[str], num_days: int = 90) -> pd.DataFrame:
|
|
123
|
+
def get_dataframe_of_prices(token_list: List[str], num_days: int = 90, use_key: bool = True) -> pd.DataFrame:
|
|
130
124
|
"""
|
|
131
125
|
returns a Pandas DataFrame with token price data going back num_days, for the given tokens
|
|
132
126
|
e.g. get_dataframe_of_prices(["ATOM", "OSMO", "STRD"], 30) returns a DataFrame of 30 days of price data
|
|
@@ -134,7 +128,7 @@ def get_dataframe_of_prices(token_list: List[str], num_days: int = 90) -> pd.Dat
|
|
|
134
128
|
# gather the dataframe
|
|
135
129
|
df = {}
|
|
136
130
|
for token in token_list:
|
|
137
|
-
df[token] = get_token_price_history(token, num_days)["price"]
|
|
131
|
+
df[token] = get_token_price_history(token, num_days, use_key=use_key)["price"]
|
|
138
132
|
df = pd.DataFrame(df)
|
|
139
133
|
# resample based on how much data we're gathering
|
|
140
134
|
if num_days > 90:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
ENV=DEV
|
|
2
|
+
CONFIGURE_STRIDEUTILS_LOGS=true
|
|
3
|
+
|
|
4
|
+
# Slack
|
|
5
|
+
SLACK_CHANNELS={"test": "U33D4351C2V"}
|
|
6
|
+
|
|
7
|
+
# API Tokens
|
|
8
|
+
NUMIA_API_TOKEN=token
|
|
9
|
+
COINGECKO_API_TOKEN=cgtoken
|
|
10
|
+
|
|
11
|
+
# Upstash
|
|
12
|
+
UPSTASH_PUBLIC_PASSWORD=password
|
|
13
|
+
|
|
14
|
+
# Twilio
|
|
15
|
+
TWILIO_ALERTS_NUMBER=+11111111111
|
|
16
|
+
|
|
17
|
+
# Slashbot twitter
|
|
18
|
+
TWITTER_CONSUMER_KEY=consumerkey
|
|
19
|
+
|
|
20
|
+
# Epoch Summary
|
|
21
|
+
EPOCH_SUMMARY_SLACK_BEARER_TOKEN=token
|
|
22
|
+
|
|
23
|
+
# Google Sheets
|
|
24
|
+
PUBLICSHEETS_AUTH={}
|
|
@@ -18,14 +18,16 @@ class TxResponse:
|
|
|
18
18
|
raw_log: Optional[str] = None
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def execute_tx(command: str, api_endpoint: str = config.stride.api_endpoint) -> TxResponse:
|
|
21
|
+
def execute_tx(command: str, api_endpoint: str = config.stride.api_endpoint, verbose=False) -> TxResponse:
|
|
22
22
|
"""
|
|
23
23
|
Execute a tx and query the tx hash
|
|
24
24
|
"""
|
|
25
25
|
output = subprocess.run(command, shell=True, capture_output=True)
|
|
26
26
|
standard_out = re.sub(r'\x1b\[[0-9;]*[mGKH]', '', output.stdout.decode('utf-8'))
|
|
27
27
|
error_out = re.sub(r'\x1b\[[0-9;]*[mGKH]', '', output.stderr.decode('utf-8'))
|
|
28
|
-
|
|
28
|
+
if verbose:
|
|
29
|
+
print("Standard Out: ", standard_out)
|
|
30
|
+
print("Error Out: ", error_out)
|
|
29
31
|
tx_hash = ""
|
|
30
32
|
for output_line in standard_out.split('\n'):
|
|
31
33
|
if 'txhash' in output_line:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import traceback
|
|
2
3
|
from typing import List, Optional, Union
|
|
3
4
|
|
|
4
5
|
from slack_sdk import WebClient
|
|
@@ -51,3 +52,23 @@ def post_msg(
|
|
|
51
52
|
print("Error sending message: ", e)
|
|
52
53
|
raise
|
|
53
54
|
return thread_ts
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def upload_file(file_name: str, content: str) -> str:
|
|
58
|
+
'''
|
|
59
|
+
This uploads a file called "file_name" with the string contents "content"
|
|
60
|
+
|
|
61
|
+
This will return a link that can be used to embed a file in slack.
|
|
62
|
+
For example:
|
|
63
|
+
url = upload_file("test.txt", "Hello World")
|
|
64
|
+
post_msg(f"<{url}|This is a file>", channel="#alerts-debug")
|
|
65
|
+
'''
|
|
66
|
+
client = WebClient(token=config.STRIDEBOT_API_TOKEN)
|
|
67
|
+
try:
|
|
68
|
+
slack_file = client.files_upload_v2(filename=file_name, content=content)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
print(f"Error uploading file to slack: {e}")
|
|
71
|
+
traceback.print_exc()
|
|
72
|
+
raise ValueError(f"Error uploading file to slack: {e}")
|
|
73
|
+
file_link = slack_file['file']['permalink']
|
|
74
|
+
return file_link
|
|
@@ -8,6 +8,7 @@ from dataclasses import dataclass, field, fields
|
|
|
8
8
|
from typing import Any, List, Optional, Union
|
|
9
9
|
|
|
10
10
|
import yaml
|
|
11
|
+
from dotenv import load_dotenv
|
|
11
12
|
|
|
12
13
|
MISSING_CONFIG_MSG = "Configuration or environment variable '{x}' is not set or unknown"
|
|
13
14
|
|
|
@@ -191,6 +192,8 @@ class Config(ConfigObj):
|
|
|
191
192
|
UPSTASH_STRIDE_FRONTEND_PASSWORD: str = ""
|
|
192
193
|
UPSTASH_STRIDE_BACKEND_PASSWORD: str = ""
|
|
193
194
|
UPSTASH_STRIDE_DYDX_PUBLIC_PASSWORD: str = ""
|
|
195
|
+
UPSTASH_STRIDE_DYDX_AIRDROP_PASSWORD: str = ""
|
|
196
|
+
UPSTASH_STRIDE_MILESTONES_PASSWORD: str = ""
|
|
194
197
|
|
|
195
198
|
# Stride internal secrets
|
|
196
199
|
SLACK_BEARER_TOKEN: str = ""
|
|
@@ -317,7 +320,6 @@ def _load_raw_config() -> dict[str, Any]:
|
|
|
317
320
|
'Shell var STRIDEUTILS_CONFIG_PATH is missing or the file does not exist in the default location.'
|
|
318
321
|
'The default file and location is config/config.yaml in the current working directory'
|
|
319
322
|
)
|
|
320
|
-
|
|
321
323
|
with open(strideutils_config_path, 'r') as config_file:
|
|
322
324
|
raw_config = yaml.load(config_file, Loader)
|
|
323
325
|
|
|
@@ -327,20 +329,13 @@ def _load_raw_config() -> dict[str, Any]:
|
|
|
327
329
|
def _load_raw_secrets() -> dict[str, Optional[str]]:
|
|
328
330
|
"""
|
|
329
331
|
Loads the secret variables into a dictionary
|
|
330
|
-
If this is running locally in dev mode, secrets are grabbed from the path defined by
|
|
332
|
+
If this is running locally in dev mode, secrets are grabbed from the path defined by STRIDEUTILS_ENV_PATH
|
|
331
333
|
Otherwise, their loaded as environment variables
|
|
332
334
|
"""
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
raise ValueError(MISSING_CONFIG_MSG.format(x='STRIDEUTILS_SECRETS_PATH'))
|
|
338
|
-
|
|
339
|
-
with open(strideutils_secrets_path, 'r') as f:
|
|
340
|
-
raw_secrets = yaml.load(f, Loader)
|
|
341
|
-
raw_secrets.update({'ENV': ENV})
|
|
342
|
-
|
|
343
|
-
return raw_secrets
|
|
335
|
+
strideutils_env_path = os.environ.get('STRIDEUTILS_ENV_PATH', '.env.local')
|
|
336
|
+
if os.path.exists(strideutils_env_path):
|
|
337
|
+
load_dotenv(strideutils_env_path)
|
|
338
|
+
return {secret.name: os.environ.get(secret.name) for secret in fields(Config) if os.environ.get(secret.name)}
|
|
344
339
|
|
|
345
340
|
|
|
346
341
|
def _parse_raw_configs(raw_config: dict[str, Any], raw_secrets: dict[str, Optional[str]]) -> Config:
|
|
@@ -916,36 +916,6 @@ def get_sttoken_apr(token: str) -> Optional[float]:
|
|
|
916
916
|
return float(cast(str, apr))
|
|
917
917
|
|
|
918
918
|
|
|
919
|
-
def get_delegated_tokens_on_address(
|
|
920
|
-
delegator_address: str,
|
|
921
|
-
api_endpoint: str = config.stride.api_endpoint,
|
|
922
|
-
) -> Dict[str, int]:
|
|
923
|
-
"""
|
|
924
|
-
Returns a dict mapping from "validator_address" to "num tokens delegated", given a delegator address
|
|
925
|
-
|
|
926
|
-
Raw response example (stake_endpoint)
|
|
927
|
-
{
|
|
928
|
-
"delegation_responses": [
|
|
929
|
-
{"delegation": {
|
|
930
|
-
"delegator_address": "cosmos10...28",
|
|
931
|
-
"validator_address": "cosmosvaloper1p..r2qs",
|
|
932
|
-
"shares":"1.180957009445999997"},
|
|
933
|
-
"balance":{"denom":"uatom","amount":"1"}
|
|
934
|
-
}, ...],
|
|
935
|
-
"pagination": {...}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
Returns
|
|
939
|
-
e.g. {'valoper1': 10, 'valoper2': 20}
|
|
940
|
-
"""
|
|
941
|
-
stake_endpoint = f"{api_endpoint}/{ACCOUNT_DELEGATIONS_QUERY.format(delegator_address=delegator_address)}"
|
|
942
|
-
host_zone_balance = query_list_with_pagination(stake_endpoint, rel_key="delegation_responses")
|
|
943
|
-
stake_amounts: Dict[str, int] = {}
|
|
944
|
-
for hzb in host_zone_balance:
|
|
945
|
-
stake_amounts[hzb["delegation"]["validator_address"]] = int(hzb["balance"]["amount"])
|
|
946
|
-
return stake_amounts
|
|
947
|
-
|
|
948
|
-
|
|
949
919
|
def get_unbonding_tokens_on_address(
|
|
950
920
|
delegator_address: str,
|
|
951
921
|
api_endpoint: str = config.stride.api_endpoint,
|
|
@@ -1003,18 +973,20 @@ def get_delegations(delegator_address: str, api_endpoint: str = config.stride.ap
|
|
|
1003
973
|
return delegations_by_validator
|
|
1004
974
|
|
|
1005
975
|
|
|
1006
|
-
def
|
|
976
|
+
def _parse_validator_dict(raw_validators: List[dict[str, Any]]) -> pd.DataFrame:
|
|
1007
977
|
"""
|
|
1008
|
-
Given
|
|
978
|
+
Given the output of a host_zone's "validator" field,
|
|
979
|
+
this will parse the data into a Pandas DataFrame.
|
|
1009
980
|
|
|
1010
|
-
|
|
1011
|
-
on the host zone delegaiton account.
|
|
981
|
+
Will also cast the relevant columns to ints and floats.
|
|
1012
982
|
"""
|
|
1013
|
-
|
|
983
|
+
int_fields = [
|
|
1014
984
|
"weight",
|
|
1015
985
|
"delegation",
|
|
1016
|
-
"slash_query_progress_tracker",
|
|
1017
986
|
"slash_query_checkpoint",
|
|
987
|
+
"slash_query_progress_tracker",
|
|
988
|
+
]
|
|
989
|
+
float_cols = [
|
|
1018
990
|
"shares_to_tokens_rate",
|
|
1019
991
|
]
|
|
1020
992
|
output_cols = [
|
|
@@ -1027,12 +999,26 @@ def get_host_zone_delegations(host_zone_id: str, include_ground_truth: bool = Tr
|
|
|
1027
999
|
"shares_to_tokens_rate",
|
|
1028
1000
|
]
|
|
1029
1001
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1002
|
+
def parse_validator(field_name: str, field_value: Any) -> Any:
|
|
1003
|
+
if field_name in int_fields:
|
|
1004
|
+
return int(field_value)
|
|
1005
|
+
if field_name in float_cols:
|
|
1006
|
+
return float(field_value)
|
|
1007
|
+
return field_value
|
|
1008
|
+
|
|
1009
|
+
cast_validators = [{k: parse_validator(k, v) for k, v in val_dict.items()} for val_dict in raw_validators]
|
|
1010
|
+
return pd.DataFrame(cast_validators, dtype=object)[output_cols]
|
|
1011
|
+
|
|
1035
1012
|
|
|
1013
|
+
def get_host_zone_delegations(host_zone_id: str, include_ground_truth: bool = True) -> pd.DataFrame:
|
|
1014
|
+
"""
|
|
1015
|
+
Given a host zone id, returns a Dataframe of validator delegations.
|
|
1016
|
+
|
|
1017
|
+
If `include_ground_truth=True`, then will also return the "true" delegations
|
|
1018
|
+
on the host zone delegaiton account.
|
|
1019
|
+
"""
|
|
1020
|
+
host_zone = get_host_zone(host_zone_id)
|
|
1021
|
+
validator_df = _parse_validator_dict(host_zone["validators"])
|
|
1036
1022
|
# If the ground truth isn't requested, return as is
|
|
1037
1023
|
if not include_ground_truth:
|
|
1038
1024
|
return validator_df
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Dict, Optional
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
import redis
|
|
4
4
|
|
|
@@ -43,7 +43,20 @@ def get_redis_db(redis_db_name: str) -> redis.Redis:
|
|
|
43
43
|
password=config.UPSTASH_STRIDE_DYDX_PUBLIC_PASSWORD,
|
|
44
44
|
ssl=True,
|
|
45
45
|
)
|
|
46
|
-
|
|
46
|
+
elif redis_db_name == 'dydx_airdrop':
|
|
47
|
+
r = redis.Redis(
|
|
48
|
+
host='pleasant-pipefish-54904.upstash.io',
|
|
49
|
+
port=6379,
|
|
50
|
+
password=config.UPSTASH_STRIDE_DYDX_AIRDROP_PASSWORD,
|
|
51
|
+
ssl=True,
|
|
52
|
+
)
|
|
53
|
+
elif redis_db_name == "milestones":
|
|
54
|
+
r = redis.Redis(
|
|
55
|
+
host='adapting-snail-56076.upstash.io',
|
|
56
|
+
port=6379,
|
|
57
|
+
password=config.UPSTASH_STRIDE_MILESTONES_PASSWORD,
|
|
58
|
+
ssl=True,
|
|
59
|
+
)
|
|
47
60
|
else:
|
|
48
61
|
raise ValueError(f'Invalid Redis DB: {redis_db_name}')
|
|
49
62
|
|
|
@@ -64,6 +77,35 @@ def get(redis_key: str, db_name='frontend') -> Optional[str]:
|
|
|
64
77
|
return value.decode('utf-8') if value is not None else None
|
|
65
78
|
|
|
66
79
|
|
|
80
|
+
def get_multiple_keys(redis_keys: List[str], db_name='frontend') -> List[Optional[str]]:
|
|
81
|
+
"""
|
|
82
|
+
This function will read multiple keys in at once.
|
|
83
|
+
Value will be "None" if the key does not exist.
|
|
84
|
+
|
|
85
|
+
Pulls from the specified redis db.
|
|
86
|
+
"""
|
|
87
|
+
db = get_redis_db(db_name)
|
|
88
|
+
values = db.mget(redis_keys)
|
|
89
|
+
|
|
90
|
+
return [value.decode('utf-8') if value is not None else None for value in values]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_all_keys(db_name='dydx_airdrop') -> List[str]:
|
|
94
|
+
"""
|
|
95
|
+
This function will return all keys in the redis db specified.
|
|
96
|
+
"""
|
|
97
|
+
db = get_redis_db(db_name)
|
|
98
|
+
|
|
99
|
+
out = []
|
|
100
|
+
|
|
101
|
+
cursor = '0'
|
|
102
|
+
while cursor != 0:
|
|
103
|
+
cursor, keys = db.scan(cursor, count=1000)
|
|
104
|
+
if keys:
|
|
105
|
+
out.extend(keys)
|
|
106
|
+
return [key.decode('utf-8') for key in out]
|
|
107
|
+
|
|
108
|
+
|
|
67
109
|
def set(redis_key: str, redis_val: str, db_name='frontend'):
|
|
68
110
|
"""
|
|
69
111
|
This function will set the given key to value in the redis_db specified.
|
|
@@ -79,5 +121,7 @@ def set_keys(dict_to_upload: Dict[str, str], db_name='frontend', prefix=''):
|
|
|
79
121
|
Will append "prefix" to all keys in the dict.
|
|
80
122
|
"""
|
|
81
123
|
db = get_redis_db(db_name)
|
|
124
|
+
pipe = db.pipeline()
|
|
82
125
|
for k, v in dict_to_upload.items():
|
|
83
|
-
|
|
126
|
+
pipe.set(prefix + k, v)
|
|
127
|
+
pipe.execute()
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# Twilio
|
|
2
|
-
TWILIO_ALERTS_NUMBER: +18663326515
|
|
3
|
-
TWILIO_ACCOUNT_ID:
|
|
4
|
-
TWILIO_API_TOKEN:
|
|
5
|
-
PHONE_NUMBERS: {}
|
|
6
|
-
|
|
7
|
-
# Slack
|
|
8
|
-
STRIDEBOT_API_TOKEN:
|
|
9
|
-
|
|
10
|
-
# GSHEETS
|
|
11
|
-
PUBLICSHEETS_AUTH:
|
|
12
|
-
|
|
13
|
-
# Coingecko
|
|
14
|
-
COINGECKO_API_TOKEN:
|
|
15
|
-
|
|
16
|
-
# Stride Internal secrets
|
|
17
|
-
SLACK_BEARER_TOKEN:
|
|
18
|
-
SLACK_SUCCESS_CHANNEL_ID:
|
|
19
|
-
SLACK_INVARIANT_FAILURE_CHANNEL_ID:
|
|
20
|
-
SLACK_PACKET_FAILURE_CHANNEL_ID:
|
|
21
|
-
NUMIA_API_TOKEN:
|
|
22
|
-
UPSTASH_PUBLIC_PASSWORD:
|
|
23
|
-
UPSTASH_STRIDE_FRONTEND_PASSWORD:
|
|
24
|
-
UPSTASH_STRIDE_BACKEND_PASSWORD:
|
|
25
|
-
|
|
26
|
-
# AWS
|
|
27
|
-
AWS_ACCESS_KEY_ID:
|
|
28
|
-
AWS_SECRET_ACCESS_KEY:
|
|
File without changes
|
|
File without changes
|
{strideutils-0.4.4 → strideutils-0.5.0}/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
|