Coverage for src/api/spl.py: 0%

236 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-03 19:06 +0000

1import json 

2import logging 

3from binascii import hexlify 

4 

5import pandas as pd 

6import requests 

7from beemgraphenebase.ecdsasig import sign_message 

8from dateutil import parser 

9from requests.adapters import HTTPAdapter 

10 

11from src.api.logRetry import LogRetry 

12 

13base_url = 'https://api2.splinterlands.com/' 

14land_url = 'https://vapi.splinterlands.com/' 

15prices_url = 'https://prices.splinterlands.com/' 

16 

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) 

26 

27 

28def get_card_details(): 

29 address = base_url + 'cards/get_details' 

30 return pd.DataFrame(http.get(address).json()).set_index('id') 

31 

32 

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() 

37 

38 

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']] 

44 

45 

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']) 

55 

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']) 

61 

62 if wild_df.empty and modern_df.empty: 

63 return None 

64 else: 

65 return pd.concat([wild_df, modern_df]) 

66 

67 

68def get_current_season(): 

69 address = base_url + 'settings' 

70 current_season = http.get(address).json()['season'] 

71 

72 return current_season 

73 

74 

75def get_settings(): 

76 address = base_url + 'settings' 

77 return http.get(address).json() 

78 

79 

80def is_maintenance_mode(): 

81 return get_settings()['maintenance_mode'] 

82 

83 

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 

98 

99 

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' 

105 

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 

112 

113 response = http.get(address, params=params) 

114 if response.status_code == 200 and response.text != '': 

115 return response.json() 

116 else: 

117 return [] 

118 

119 

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) 

129 

130 balance_history_link = 'players/balance_history' 

131 

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 

139 

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 

145 

146 

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 

155 

156 

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 } 

164 

165 result = http.get(address, params=params) 

166 if result.status_code == 200: 

167 return result.json()['player'] 

168 else: 

169 return None 

170 

171 

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'] 

180 

181 

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'] 

187 

188 

189def get_balances(username): 

190 address = base_url + 'players/balances' 

191 params = {'username': username} 

192 return http.get(address, params=params).json() 

193 

194 

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'])) 

199 

200 

201def get_tournament(tournament_id): 

202 address = base_url + 'tournaments/find' 

203 params = {'id': tournament_id} 

204 return http.get(address, params=params).json() 

205 

206 

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' 

213 

214 df = pd.DataFrame(http.get(address, params=params).json()) 

215 tournaments_ids = [] 

216 

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 

223 

224 

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 

234 

235 

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 

245 

246 

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 

256 

257 

258def get_player_history_season_rewards_df(token_params): 

259 address = base_url + 'players/history' 

260 

261 params = token_params 

262 params['from_block'] = -1 

263 params['limit'] = 1000 

264 params['types'] = 'claim_reward' 

265 

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 

273 

274 

275def get_battle(battle_id): 

276 address = base_url + 'battle/result' 

277 params = {'id': battle_id} 

278 return http.get(address, params=params).json() 

279 

280 

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']) 

285 

286 

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 

291 

292 

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']) 

307 

308 timestamp = result['timestamp'] 

309 token = result['token'] 

310 return token, timestamp 

311 

312 

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 

322 

323 

324def get_owned_resource_sum(account, resource): 

325 address = land_url + 'land/resources/owned' 

326 params = {'player': account, 'resource': resource} 

327 

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 

334 

335 

336def get_prices(): 

337 address = prices_url + 'prices' 

338 return http.get(address).json() 

339 

340 

341def spl_get_pools(): 

342 address = land_url + 'land/liquidity/pools' 

343 

344 result = http.get(address).json() 

345 if result and 'data' in result: 

346 return pd.DataFrame(result['data']) 

347 return pd.DataFrame() 

348 

349 

350def get_liquidity(account, resource): 

351 address = land_url + 'land/liquidity/pools/' + str(account) + '/' + resource 

352 

353 result = http.get(address).json() 

354 if result and 'data' in result: 

355 return pd.DataFrame(result['data']['single']) 

356 return pd.DataFrame()