Coverage for src / api / spl.py: 0%
236 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-01 10:28 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-01 10:28 +0000
1import json
2import logging
3from binascii import hexlify
5import pandas as pd
6import requests
7from beemgraphenebase.ecdsasig import sign_message
8from dateutil import parser
9from requests.adapters import HTTPAdapter
11from src.api.logRetry import LogRetry
13base_url = 'https://api2.splinterlands.com/'
14land_url = 'https://vapi.splinterlands.com/'
15prices_url = 'https://prices.splinterlands.com/'
17retry_strategy = LogRetry(
18 total=10,
19 status_forcelist=[429, 500, 502, 503, 504],
20 backoff_factor=2, # wait will be [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
21 allowed_methods=['HEAD', 'GET', 'OPTIONS']
22)
23adapter = HTTPAdapter(max_retries=retry_strategy)
24http = requests.Session()
25http.mount('https://', adapter)
28def get_card_details():
29 address = base_url + 'cards/get_details'
30 return pd.DataFrame(http.get(address).json()).set_index('id')
33def get_rule_sets_list():
34 address = base_url + 'battle/rulesets'
35 df = pd.DataFrame(http.get(address).json())
36 return df.name.to_list()
39def get_player_collection_df(username):
40 address = base_url + 'cards/collection/' + username
41 collection = http.get(address).json()['cards']
42 df = pd.DataFrame(sorted(collection, key=lambda card: card['card_detail_id']))
43 return df[['player', 'uid', 'card_detail_id', 'xp', 'foil', 'gold', 'edition', 'level', 'bcx', 'bcx_unbound']]
46def get_battle_history_df(account_name, token_params):
47 address = base_url + 'battle/history2'
48 params = token_params
49 params['player'] = account_name
50 params['limit'] = 50
51 wild_df = pd.DataFrame()
52 wild_result = http.get(address, params=params)
53 if wild_result.status_code == 200:
54 wild_df = pd.DataFrame(wild_result.json()['battles'])
56 params['format'] = 'modern'
57 modern_result = http.get(address, params=params)
58 modern_df = pd.DataFrame()
59 if modern_result.status_code == 200:
60 modern_df = pd.DataFrame(modern_result.json()['battles'])
62 if wild_df.empty and modern_df.empty:
63 return None
64 else:
65 return pd.concat([wild_df, modern_df])
68def get_current_season():
69 address = base_url + 'settings'
70 current_season = http.get(address).json()['season']
72 return current_season
75def get_settings():
76 address = base_url + 'settings'
77 return http.get(address).json()
80def is_maintenance_mode():
81 return get_settings()['maintenance_mode']
84def get_season_end_time(season_id):
85 address = base_url + 'season'
86 params = {'id': season_id}
87 result = http.get(address, params=params)
88 if result.status_code == 200:
89 date = parser.parse(str(result.json()['ends']))
90 result = pd.DataFrame({'id': season_id, 'end_date': str(date)}, index=[0])
91 else:
92 logging.error('Failed call: '' + str(address) + ''')
93 logging.error('Unable to determine season end date return code: ' + str(result.status_code))
94 logging.error('This interrupts all other calculations, try re-execution.')
95 logging.error('Stopping program now ... ')
96 exit(1)
97 return result
100def get_unclaimed_sps_balance_history_for_token_impl(
101 offset=None,
102 limit=1000,
103 token_params=None):
104 balance_history_link = 'players/unclaimed_balance_history'
106 params = token_params
107 params['token_type'] = 'SPS'
108 if offset:
109 params['offset'] = offset
110 params['limit'] = limit
111 address = base_url + balance_history_link
113 response = http.get(address, params=params)
114 if response.status_code == 200 and response.text != '':
115 return response.json()
116 else:
117 return []
120def get_balance_history_for_token_impl_v2(
121 token='DEC',
122 from_date=None,
123 last_update_date=None,
124 limit=1000,
125 token_params=None):
126 token_types = ['SPS', 'DEC', 'VOUCHER', 'CREDITS', 'MERITS', 'GLINT']
127 if token not in token_types:
128 raise ValueError('Invalid token type. Expected one of: %s' % token_types)
130 balance_history_link = 'players/balance_history'
132 params = token_params
133 params['token_type'] = token
134 params['limit'] = limit
135 if from_date:
136 params["from"] = from_date
137 if last_update_date:
138 params["last_update_date"] = last_update_date
140 response = http.get(base_url + balance_history_link, params=params)
141 if response.status_code == 200 and response.text != '':
142 return response.json()
143 else:
144 return None
147def player_exist(account_name):
148 address = base_url + 'players/details'
149 params = {'name': account_name}
150 result = http.get(address, params=params)
151 if result.status_code == 200 and 'error' not in result.json():
152 return True
153 else:
154 return False
157def get_leaderboard_with_player_season(username, season, mode):
158 address = base_url + 'players/leaderboard_with_player'
159 params = {
160 'season': season,
161 'format': str(mode.value),
162 'username': username
163 }
165 result = http.get(address, params=params)
166 if result.status_code == 200:
167 return result.json()['player']
168 else:
169 return None
172def get_deeds_collection(username):
173 address = land_url + 'land/deeds'
174 params = {
175 'status': 'collection',
176 'player': username,
177 }
178 collection = http.get(address, params=params)
179 return collection.json()['data']['deeds']
182def get_deeds_market():
183 address = land_url + 'land/deeds'
184 params = {'status': 'market'}
185 market = http.get(address, params=params)
186 return market.json()['data']['deeds']
189def get_balances(username):
190 address = base_url + 'players/balances'
191 params = {'username': username}
192 return http.get(address, params=params).json()
195def get_all_cards_for_sale_df():
196 address = base_url + 'market/for_sale_grouped'
197 all_cards_for_sale = requests.get(address).json()
198 return pd.DataFrame(sorted(all_cards_for_sale, key=lambda card: card['card_detail_id']))
201def get_tournament(tournament_id):
202 address = base_url + 'tournaments/find'
203 params = {'id': tournament_id}
204 return http.get(address, params=params).json()
207def get_player_tournaments_ids(token_params):
208 address = base_url + 'players/history'
209 params = token_params
210 params['from_block'] = -1
211 params['limit'] = 500
212 params['types'] = 'token_transfer'
214 df = pd.DataFrame(http.get(address, params=params).json())
215 tournaments_ids = []
217 if not df.empty:
218 for index, row in df.iterrows():
219 data = json.loads(row.data)
220 if 'tournament_id' in data:
221 tournaments_ids.append(data['tournament_id'])
222 return tournaments_ids
225def get_market_transaction(trx_id):
226 # https://api.splinterlands.io/market/status?id=d8f8593d637ebdd0bca7994dd7e1a15d9f12efa7-0
227 address = base_url + 'market/status'
228 params = {'id': trx_id}
229 result = http.get(address, params=params)
230 if result.status_code == 200:
231 return result.json()
232 else:
233 return None
236def get_transaction(trx_id):
237 # https://api.splinterlands.com/transactions/lookup?trx_id=247d6ac02bbfd5b8c38528535baa0d8298697a57'
238 address = base_url + 'transactions/lookup'
239 params = {'trx_id': trx_id}
240 result = http.get(address, params=params)
241 if result.status_code == 200:
242 return result.json()
243 else:
244 return None
247def get_cards_by_ids(ids):
248 # https://api.splinterlands.io/cards/find?ids=C3-457-3VIL75QJ2O,
249 address = base_url + 'cards/find'
250 params = {'ids': ids}
251 result = http.get(address, params=params)
252 if result.status_code == 200:
253 return result.json()
254 else:
255 return None
258def get_player_history_season_rewards_df(token_params):
259 address = base_url + 'players/history'
261 params = token_params
262 params['from_block'] = -1
263 params['limit'] = 1000
264 params['types'] = 'claim_reward'
266 result = http.get(address, params=params).json()
267 df = pd.DataFrame()
268 for row in result:
269 df = pd.concat([df, pd.DataFrame(json.loads(row['data']), index=[0])], ignore_index=True)
270 if not df.empty:
271 df = df.loc[df['type'] == 'league_season']
272 return df
275def get_battle(battle_id):
276 address = base_url + 'battle/result'
277 params = {'id': battle_id}
278 return http.get(address, params=params).json()
281def get_staked_dec_df(account_name):
282 address = land_url + 'land/stake/decstaked'
283 params = {'player': account_name}
284 return pd.DataFrame(http.get(address, params=params).json()['data'])
287def compute_sig(string_to_sign: str, private_key: str):
288 bytestring_signature = sign_message(string_to_sign, private_key)
289 sig = hexlify(bytestring_signature).decode('ascii')
290 return sig
293def get_token(username, ts, sig):
294 login_endpoint = base_url + 'players/v2/login'
295 params = {
296 'name': username,
297 'ts': ts,
298 'sig': sig
299 }
300 result = http.get(login_endpoint, params=params)
301 token = ""
302 timestamp = ""
303 if result and result.status_code == 200:
304 result = result.json()
305 if 'error' in result:
306 raise ValueError(result['error'])
308 timestamp = result['timestamp']
309 token = result['token']
310 return token, timestamp
313def verify_token(token_params):
314 # Verify token is now done via battle history 2 that needs a specific user token to retrieve data
315 if token_params:
316 address = base_url + 'battle/history2'
317 params = token_params
318 result = http.get(address, params=params)
319 if result.status_code == 200:
320 return True
321 return False
324def get_owned_resource_sum(account, resource):
325 address = land_url + 'land/resources/owned'
326 params = {'player': account, 'resource': resource}
328 result = http.get(address, params=params).json()
329 if result and 'data' in result:
330 df = pd.DataFrame(result['data'])
331 if 'amount' in df.columns.tolist():
332 return df.amount.sum()
333 return None
336def get_prices():
337 address = prices_url + 'prices'
338 return http.get(address).json()
341def spl_get_pools():
342 address = land_url + 'land/liquidity/pools'
344 result = http.get(address).json()
345 if result and 'data' in result:
346 return pd.DataFrame(result['data'])
347 return pd.DataFrame()
350def get_liquidity(account, resource):
351 address = land_url + 'land/liquidity/pools/' + str(account) + '/' + resource
353 result = http.get(address).json()
354 if result and 'data' in result:
355 return pd.DataFrame(result['data']['single'])
356 return pd.DataFrame()