cherry-shared2 0.1.26__py3-none-any.whl
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.
- cherry_shared/InfoService.py +369 -0
- cherry_shared/__init__.py +5 -0
- cherry_shared/blockchains.py +265 -0
- cherry_shared/bot_strings.py +529 -0
- cherry_shared/constants.py +36 -0
- cherry_shared/emojis.py +63 -0
- cherry_shared/functions.py +511 -0
- cherry_shared/launchpads.py +193 -0
- cherry_shared/types/__init__.py +6 -0
- cherry_shared/types/blockchain.py +51 -0
- cherry_shared/types/dexscreener.py +376 -0
- cherry_shared/types/launchpad.py +72 -0
- cherry_shared/types/leaderboardEntry.py +62 -0
- cherry_shared/types/raid_info.py +92 -0
- cherry_shared/types/user_wallet.py +9 -0
- cherry_shared2-0.1.26.dist-info/METADATA +91 -0
- cherry_shared2-0.1.26.dist-info/RECORD +19 -0
- cherry_shared2-0.1.26.dist-info/WHEEL +5 -0
- cherry_shared2-0.1.26.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Any, Dict, Literal, Optional
|
|
4
|
+
import aiohttp
|
|
5
|
+
from cherry_shared.launchpads import LaunchPad
|
|
6
|
+
from cherry_shared.types.dexscreener import Pair
|
|
7
|
+
from cherry_shared.types.launchpad import LaunchpadToken
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InfoService:
|
|
11
|
+
|
|
12
|
+
def __init__(self, info_url: str, helper_url: str, logger: logging.Logger = None):
|
|
13
|
+
self.info_url = info_url
|
|
14
|
+
self.helper_url = helper_url
|
|
15
|
+
if logger is None:
|
|
16
|
+
self._logger = logging.getLogger(__name__)
|
|
17
|
+
else:
|
|
18
|
+
self._logger = logger
|
|
19
|
+
|
|
20
|
+
async def process_request(
|
|
21
|
+
self,
|
|
22
|
+
url: str,
|
|
23
|
+
body: Dict[str, Any] = None,
|
|
24
|
+
method: str = "GET",
|
|
25
|
+
query: Dict[str, str] = None,
|
|
26
|
+
headers: Dict[str, str] = None,
|
|
27
|
+
timeout: int = 60,
|
|
28
|
+
):
|
|
29
|
+
if headers is None:
|
|
30
|
+
headers = {"Content-Type": "application/json"}
|
|
31
|
+
# Define a custom timeout
|
|
32
|
+
custom_timeout = aiohttp.ClientTimeout(total=timeout)
|
|
33
|
+
|
|
34
|
+
async with aiohttp.ClientSession(
|
|
35
|
+
headers=headers, timeout=custom_timeout
|
|
36
|
+
) as session:
|
|
37
|
+
try:
|
|
38
|
+
if method == "GET":
|
|
39
|
+
async with session.get(
|
|
40
|
+
url, params=query, data=json.dumps(body) if body else None
|
|
41
|
+
) as resp:
|
|
42
|
+
if resp.status >= 400:
|
|
43
|
+
return False, resp.reason
|
|
44
|
+
if "application/json" in resp.headers.get("Content-Type", ""):
|
|
45
|
+
res = await resp.json()
|
|
46
|
+
else:
|
|
47
|
+
res = await resp.text()
|
|
48
|
+
return (
|
|
49
|
+
False,
|
|
50
|
+
f"Unexpected Content-Type: {resp.headers.get('Content-Type')}, Response: {res}",
|
|
51
|
+
)
|
|
52
|
+
elif method == "POST":
|
|
53
|
+
async with session.post(url, data=json.dumps(body)) as resp:
|
|
54
|
+
if resp.status >= 400:
|
|
55
|
+
return False, resp.reason
|
|
56
|
+
if "application/json" in resp.headers.get("Content-Type", ""):
|
|
57
|
+
res = await resp.json()
|
|
58
|
+
else:
|
|
59
|
+
res = await resp.text()
|
|
60
|
+
return (
|
|
61
|
+
False,
|
|
62
|
+
f"Unexpected Content-Type: {resp.headers.get('Content-Type')}, Response: {res}",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return True, res
|
|
66
|
+
except Exception as e:
|
|
67
|
+
self._logger.error(f"Error in InfoService.process_request(): {e}")
|
|
68
|
+
return False, "Exception: " + str(e)
|
|
69
|
+
|
|
70
|
+
async def search_address(self, address: str):
|
|
71
|
+
url = f"{self.info_url}/info/{address}"
|
|
72
|
+
success, data = await self.process_request(url)
|
|
73
|
+
if success:
|
|
74
|
+
return [Pair.from_dexsc_dict(item) for item in data["data"][:10]]
|
|
75
|
+
|
|
76
|
+
async def get_address_type(self, address: str):
|
|
77
|
+
url = f"{self.info_url}/address"
|
|
78
|
+
body = {"address": address}
|
|
79
|
+
success, res = await self.process_request(url, body)
|
|
80
|
+
if success:
|
|
81
|
+
return res["data"]
|
|
82
|
+
|
|
83
|
+
async def get_pair_by_pair_address(self, address: str, chainId: str):
|
|
84
|
+
url = f"{self.info_url}/info/pair"
|
|
85
|
+
success, res = await self.process_request(
|
|
86
|
+
url, {"address": address, "chainId": chainId}, "POST"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if not success:
|
|
90
|
+
self._logger.error(res)
|
|
91
|
+
return None
|
|
92
|
+
return Pair.from_dexsc_dict(res["data"])
|
|
93
|
+
|
|
94
|
+
async def get_chains_data(self):
|
|
95
|
+
url = f"{self.info_url}/chains"
|
|
96
|
+
success, data = await self.process_request(url)
|
|
97
|
+
if success:
|
|
98
|
+
return data
|
|
99
|
+
|
|
100
|
+
async def get_total_supply(self, chain: str, address: str):
|
|
101
|
+
url = self.helper_url + "/totalsupply"
|
|
102
|
+
body = {"chain": chain, "address": address}
|
|
103
|
+
success, data = await self.process_request(url, body, "POST")
|
|
104
|
+
if success:
|
|
105
|
+
return data["supply"], data["decimals"]
|
|
106
|
+
return None, None
|
|
107
|
+
|
|
108
|
+
async def get_trending(self):
|
|
109
|
+
url = self.helper_url + "/trending"
|
|
110
|
+
success, data = await self.process_request(url)
|
|
111
|
+
if success:
|
|
112
|
+
return data
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
async def send_confirm_req(
|
|
116
|
+
self, pair_address: str, contract_address: str, chain_id: str, chat_id: int
|
|
117
|
+
):
|
|
118
|
+
url = self.helper_url + "/confirm"
|
|
119
|
+
self._logger.debug(f"{pair_address}, {chain_id}, {chat_id}")
|
|
120
|
+
body = {
|
|
121
|
+
"pairAddress": pair_address,
|
|
122
|
+
"tokenAddress": contract_address,
|
|
123
|
+
"chainId": chain_id,
|
|
124
|
+
"chatId": chat_id,
|
|
125
|
+
}
|
|
126
|
+
self._logger.debug(f"send_confirm_req: {body}")
|
|
127
|
+
success, data = await self.process_request(url, body, "POST")
|
|
128
|
+
if not success:
|
|
129
|
+
self._logger.error(f"failed to send confirm req: {data}")
|
|
130
|
+
|
|
131
|
+
async def send_delete_req(self, tokenAddress: str, chat_id: int):
|
|
132
|
+
url = self.helper_url + "/delete"
|
|
133
|
+
body = {
|
|
134
|
+
"tokenAddress": tokenAddress,
|
|
135
|
+
"chatId": chat_id,
|
|
136
|
+
}
|
|
137
|
+
success, data = await self.process_request(url, body, "POST")
|
|
138
|
+
if not success:
|
|
139
|
+
self._logger.error(f"failed delete token req: {data}")
|
|
140
|
+
|
|
141
|
+
async def send_update_supply(self, tokenAddress: str, chat_id: int, supply: int):
|
|
142
|
+
self._logger.debug(f"{tokenAddress}, {chat_id}, {supply}")
|
|
143
|
+
url = self.helper_url + "/updatesupply"
|
|
144
|
+
body = {
|
|
145
|
+
"address": tokenAddress,
|
|
146
|
+
"chatId": chat_id,
|
|
147
|
+
"supply": supply,
|
|
148
|
+
}
|
|
149
|
+
success, data = await self.process_request(url, body, "POST")
|
|
150
|
+
if not success:
|
|
151
|
+
self._logger.error(f"failed update supply req: {data}")
|
|
152
|
+
|
|
153
|
+
async def generate_wallet(self, wallet_type: str):
|
|
154
|
+
wallet_endpoints = {
|
|
155
|
+
"solana": "/generatesolanawallet",
|
|
156
|
+
"tron": "/generatetronwallet",
|
|
157
|
+
"sui": "/generatesuiawallet",
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if wallet_type not in wallet_endpoints:
|
|
161
|
+
self._logger.error(f"wallet endpoint not provided: {wallet_type}")
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
url = self.helper_url + wallet_endpoints[wallet_type]
|
|
165
|
+
success, data = await self.process_request(url)
|
|
166
|
+
|
|
167
|
+
if not success:
|
|
168
|
+
self._logger.error(f"Failed {wallet_type} wallet request: {data}")
|
|
169
|
+
return
|
|
170
|
+
self._logger.debug(f"generated new wallet {data['publicKey'][:10]}")
|
|
171
|
+
return data["publicKey"], data["privateKey"]
|
|
172
|
+
|
|
173
|
+
async def get_balance(self, wallet_address: str, chain: str):
|
|
174
|
+
url = self.helper_url + "/balance"
|
|
175
|
+
success, data = await self.process_request(
|
|
176
|
+
url, query={"tokenAddress": wallet_address, "chain": chain}
|
|
177
|
+
)
|
|
178
|
+
if not success:
|
|
179
|
+
self._logger.error(f"failed to get balance: {data}")
|
|
180
|
+
return None
|
|
181
|
+
return float(data["balance"])
|
|
182
|
+
|
|
183
|
+
async def buyNburn(
|
|
184
|
+
self,
|
|
185
|
+
raid_id: int,
|
|
186
|
+
chat_id: int,
|
|
187
|
+
amount: float,
|
|
188
|
+
token_address: str,
|
|
189
|
+
pair_address: str,
|
|
190
|
+
chain: str,
|
|
191
|
+
pk: str,
|
|
192
|
+
):
|
|
193
|
+
url = self.helper_url + "/burn"
|
|
194
|
+
body = {
|
|
195
|
+
"raidId": raid_id,
|
|
196
|
+
"chatId": chat_id,
|
|
197
|
+
"amount": amount,
|
|
198
|
+
"tokenAddress": token_address,
|
|
199
|
+
"pairAddress": pair_address,
|
|
200
|
+
"chain": chain,
|
|
201
|
+
"privateKey": pk,
|
|
202
|
+
}
|
|
203
|
+
success, data = await self.process_request(url, body, "POST")
|
|
204
|
+
if not success:
|
|
205
|
+
self._logger.error(f"failed to send confirm req: {data}")
|
|
206
|
+
return False, data
|
|
207
|
+
|
|
208
|
+
status: bool = data["status"]
|
|
209
|
+
self._logger.debug(f"buyNburn status = {status}")
|
|
210
|
+
return status, None
|
|
211
|
+
|
|
212
|
+
async def check_status(self, raid_id: int):
|
|
213
|
+
try:
|
|
214
|
+
url = self.helper_url + f"/status?raidId={raid_id}"
|
|
215
|
+
success, data = await self.process_request(url)
|
|
216
|
+
if not success:
|
|
217
|
+
self._logger.error(f"failed to send confirm req: {data}")
|
|
218
|
+
return "error", data
|
|
219
|
+
res = data["status"], (
|
|
220
|
+
data["buyTx"],
|
|
221
|
+
data["burnTx"],
|
|
222
|
+
data["finalBountyAmount"],
|
|
223
|
+
)
|
|
224
|
+
return res
|
|
225
|
+
except Exception as e:
|
|
226
|
+
self._logger.error(
|
|
227
|
+
f"Error in InfoService.check_status(): {e}", exc_info=True
|
|
228
|
+
)
|
|
229
|
+
return "error", str(e)
|
|
230
|
+
|
|
231
|
+
async def withdraw(self, chain: str, toAddress: str, userId: int):
|
|
232
|
+
url = self.helper_url + "/withdraw"
|
|
233
|
+
query = {"chain": chain, "toAddress": toAddress, "userId": userId}
|
|
234
|
+
success, res = await self.process_request(url, query=query)
|
|
235
|
+
if not success:
|
|
236
|
+
self._logger.error(f"Info Withdraw: {res}")
|
|
237
|
+
return False, res
|
|
238
|
+
tx_hash = res["txHash"]
|
|
239
|
+
return True, tx_hash
|
|
240
|
+
|
|
241
|
+
async def validate_purchase(
|
|
242
|
+
self,
|
|
243
|
+
user_id: int,
|
|
244
|
+
value: float,
|
|
245
|
+
chain: str,
|
|
246
|
+
promo_code: str = None,
|
|
247
|
+
payout_value: float = None,
|
|
248
|
+
token_id: int = None,
|
|
249
|
+
trendingId: int = None,
|
|
250
|
+
volume_bot=0,
|
|
251
|
+
status: Literal["normal", "volume", "holder"] = "normal",
|
|
252
|
+
hours=None,
|
|
253
|
+
base_amount: float = 0.01,
|
|
254
|
+
**kwargs,
|
|
255
|
+
):
|
|
256
|
+
url = self.helper_url + "/trendingslot/verify"
|
|
257
|
+
body = {
|
|
258
|
+
"chain": chain,
|
|
259
|
+
"value": value,
|
|
260
|
+
"userId": user_id,
|
|
261
|
+
"promoCode": promo_code,
|
|
262
|
+
"payoutValue": payout_value,
|
|
263
|
+
"tokenId": token_id,
|
|
264
|
+
"trendingId": trendingId,
|
|
265
|
+
"volumeBot": 1 if status == "holder" else volume_bot,
|
|
266
|
+
"status": status,
|
|
267
|
+
"hours": hours,
|
|
268
|
+
"baseAmount": base_amount,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# Add any additional key-value arguments to the body
|
|
272
|
+
body.update(kwargs)
|
|
273
|
+
|
|
274
|
+
success, res = await self.process_request(url, body, "POST")
|
|
275
|
+
if not success:
|
|
276
|
+
self._logger.error(f"Info validate_purchase: {res}")
|
|
277
|
+
return -1, res
|
|
278
|
+
|
|
279
|
+
code = int(res["code"])
|
|
280
|
+
message = res["message"] if code == 0 else res["error"]
|
|
281
|
+
|
|
282
|
+
return code, message
|
|
283
|
+
|
|
284
|
+
async def get_token_info(self, address: str, chain: str):
|
|
285
|
+
url = self.info_url + "/info/tokeninfo"
|
|
286
|
+
body = {"address": address, "chain": chain}
|
|
287
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
288
|
+
if not success:
|
|
289
|
+
self._logger.error(f"get_token_info: {res}")
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
code = int(res["code"])
|
|
293
|
+
if code == 0:
|
|
294
|
+
self._logger.debug(f"get_token_info: {res['data']}")
|
|
295
|
+
return res["data"]
|
|
296
|
+
|
|
297
|
+
async def get_launchpad_data(self, launchpad: LaunchPad, address: str):
|
|
298
|
+
url = self.info_url + f"/{launchpad.info_route}"
|
|
299
|
+
body = {"address": address, "chatId": 0}
|
|
300
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
301
|
+
if not success:
|
|
302
|
+
self._logger.error(f"get {launchpad.name} info: {res}")
|
|
303
|
+
return None
|
|
304
|
+
|
|
305
|
+
code = int(res["code"])
|
|
306
|
+
self._logger.debug(f"get_launchpad_data: {res['data']}")
|
|
307
|
+
if code == 0:
|
|
308
|
+
return LaunchpadToken.create_token_info(res["data"])
|
|
309
|
+
|
|
310
|
+
async def get_fees(self, address: str):
|
|
311
|
+
try:
|
|
312
|
+
url = self.helper_url + f"/getFees"
|
|
313
|
+
body = {"address": address}
|
|
314
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
315
|
+
if not success:
|
|
316
|
+
self._logger.error(f"get_fees info for address {address}: {res}")
|
|
317
|
+
return None
|
|
318
|
+
self._logger.debug(f"get_fees: {res}")
|
|
319
|
+
return round(float(res.get("fee", 1)), 2)
|
|
320
|
+
except Exception as e:
|
|
321
|
+
self._logger.error(f"Error in InfoService.get_fees(): {e}", exc_info=True)
|
|
322
|
+
return 1
|
|
323
|
+
|
|
324
|
+
async def send_message(self, chat_id: int, message: str, thread_id: str = None):
|
|
325
|
+
url = self.helper_url + "/sendtrendingmessage"
|
|
326
|
+
body = {
|
|
327
|
+
"chat_id": chat_id,
|
|
328
|
+
"text": message,
|
|
329
|
+
"thread_id": thread_id,
|
|
330
|
+
}
|
|
331
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
332
|
+
if not success:
|
|
333
|
+
self._logger.error(f"send_message: {res}")
|
|
334
|
+
return False, res
|
|
335
|
+
return True, res
|
|
336
|
+
|
|
337
|
+
async def edit_message(
|
|
338
|
+
self, chat_id: int, message_id: int, message: str, thread_id: str = None
|
|
339
|
+
):
|
|
340
|
+
url = self.helper_url + "/sendtrendingmessage"
|
|
341
|
+
body = {
|
|
342
|
+
"chat_id": chat_id,
|
|
343
|
+
"msg_id": message_id,
|
|
344
|
+
"text": message,
|
|
345
|
+
"thread_id": thread_id,
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
349
|
+
if not success:
|
|
350
|
+
self._logger.error(f"edit_message: {res}")
|
|
351
|
+
return False, res
|
|
352
|
+
return True, res
|
|
353
|
+
|
|
354
|
+
async def check_rate_limit(
|
|
355
|
+
self,
|
|
356
|
+
chat_id: Optional[int] = None,
|
|
357
|
+
priority: Literal["high", "normal", "low"] = "normal",
|
|
358
|
+
):
|
|
359
|
+
url = self.helper_url + "/check-rate-limit"
|
|
360
|
+
body = {
|
|
361
|
+
"chat_id": chat_id,
|
|
362
|
+
"priority": priority,
|
|
363
|
+
}
|
|
364
|
+
success, res = await self.process_request(url, body=body, method="POST")
|
|
365
|
+
if not success:
|
|
366
|
+
self._logger.error(f"check_rate_limit: {res}")
|
|
367
|
+
return 0
|
|
368
|
+
delay = int(res.get("delay_ms", 0)) / 1000.0
|
|
369
|
+
return delay
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
from typing import Dict, List, Set
|
|
2
|
+
from cherry_shared.types.blockchain import Blockchain, SupportedFeatures
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ChainType(Enum):
|
|
8
|
+
EVM = "evm"
|
|
9
|
+
SOLANA = "solana"
|
|
10
|
+
TRON = "tron"
|
|
11
|
+
TON = "ton"
|
|
12
|
+
SUI = "sui"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BlockchainId:
|
|
16
|
+
SOL = "solana"
|
|
17
|
+
ETH = "ethereum"
|
|
18
|
+
BSC = "bsc"
|
|
19
|
+
TRX = "tron"
|
|
20
|
+
BASE = "base"
|
|
21
|
+
SUI = "sui"
|
|
22
|
+
MANTA = "manta"
|
|
23
|
+
MATIC = "polygon"
|
|
24
|
+
XPL = "plasma"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Blockchains:
|
|
28
|
+
SOL = Blockchain(
|
|
29
|
+
BlockchainId.SOL,
|
|
30
|
+
"SOL",
|
|
31
|
+
"Solana",
|
|
32
|
+
"SOL",
|
|
33
|
+
"https://solscan.io/token",
|
|
34
|
+
False,
|
|
35
|
+
{
|
|
36
|
+
3: {3: 0, 6: 0, 12: 6, 24: 9},
|
|
37
|
+
10: {3: 1.6 , 6: 2.5, 12: 4, 24: 7},
|
|
38
|
+
},
|
|
39
|
+
["SOL", "USDC"],
|
|
40
|
+
{
|
|
41
|
+
150: 0.2,
|
|
42
|
+
300: 0.4,
|
|
43
|
+
},
|
|
44
|
+
SupportedFeatures(custom_token=True, wallet=True, payment=True),
|
|
45
|
+
0.1,
|
|
46
|
+
extras={
|
|
47
|
+
"volume_price": {
|
|
48
|
+
50000: 3.2,
|
|
49
|
+
100_000: 5.8,
|
|
50
|
+
250_000: 13.0,
|
|
51
|
+
500_000: 24.6,
|
|
52
|
+
1_000_000: 45.8,
|
|
53
|
+
5_000_000: 214.6,
|
|
54
|
+
},
|
|
55
|
+
"holders_price": {
|
|
56
|
+
1000: 2.2,
|
|
57
|
+
2500: 5.5,
|
|
58
|
+
5000: 11,
|
|
59
|
+
10000: 22,
|
|
60
|
+
25000: 55,
|
|
61
|
+
100_000: 220,
|
|
62
|
+
},
|
|
63
|
+
"boost_price": {1000: 0.4, 2000: 0.7, 4000: 1.3, 8000: 2.5},
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
ETH = Blockchain(
|
|
68
|
+
BlockchainId.ETH,
|
|
69
|
+
"ETH",
|
|
70
|
+
"Ethereum",
|
|
71
|
+
"ETH",
|
|
72
|
+
"https://etherscan.io/token",
|
|
73
|
+
True,
|
|
74
|
+
{
|
|
75
|
+
3: {3: 0.2, 6: 0.4, 12: 0.6, 24: 0.9},
|
|
76
|
+
10: {3: 0.1, 6: 0.2, 12: 0.4, 24: 0.6},
|
|
77
|
+
},
|
|
78
|
+
["WETH", "USDT", "USDC"],
|
|
79
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
80
|
+
SupportedFeatures(custom_token=True, wallet=True, payment=True),
|
|
81
|
+
0.05,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
BSC = Blockchain(
|
|
85
|
+
BlockchainId.BSC,
|
|
86
|
+
"BSC",
|
|
87
|
+
"Binance Smart Chain",
|
|
88
|
+
"BNB",
|
|
89
|
+
"https://bscscan.com/token",
|
|
90
|
+
True,
|
|
91
|
+
{
|
|
92
|
+
3: {3: 0.7, 6: 1.2, 12: 2.0, 24: 3.5},
|
|
93
|
+
10: {3: 0.6, 6: 0.8, 12: 1.5, 24: 2.5},
|
|
94
|
+
},
|
|
95
|
+
["WBNB", "USDT", "USDC"],
|
|
96
|
+
{150: 0.1, 300: 0.2, 950: 0.5, 2500: 1},
|
|
97
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
98
|
+
0.1,
|
|
99
|
+
extras={
|
|
100
|
+
"boost_price": {1000: 0.7, 2000: 1.4, 4000: 2.5, 8000: 4.6},
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
TRX = Blockchain(
|
|
105
|
+
BlockchainId.TRX,
|
|
106
|
+
"TRX",
|
|
107
|
+
"Tron",
|
|
108
|
+
"TRX",
|
|
109
|
+
"https://tronscan.org/#/token20",
|
|
110
|
+
False,
|
|
111
|
+
{
|
|
112
|
+
3: {3: 1260, 6: 2270, 12: 3530, 24: 6050},
|
|
113
|
+
10: {3: 1000, 6: 1770, 12: 3020, 24: 4540},
|
|
114
|
+
},
|
|
115
|
+
["WTRX", "USDT", "USDC"],
|
|
116
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
117
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
118
|
+
10,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
BASE = Blockchain(
|
|
122
|
+
BlockchainId.BASE,
|
|
123
|
+
"BASE",
|
|
124
|
+
"Base",
|
|
125
|
+
"ETH",
|
|
126
|
+
"https://basescan.org/token",
|
|
127
|
+
True,
|
|
128
|
+
{
|
|
129
|
+
3: {3: 0.2, 6: 0.4, 12: 0.6, 24: 0.9},
|
|
130
|
+
10: {3: 0.1, 6: 0.2, 12: 0.4, 24: 0.6},
|
|
131
|
+
},
|
|
132
|
+
["WETH", "USDT", "USDC"],
|
|
133
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
134
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
135
|
+
0.1,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
MATIC = Blockchain(
|
|
139
|
+
BlockchainId.MATIC,
|
|
140
|
+
"POL",
|
|
141
|
+
"Polygon",
|
|
142
|
+
"POL",
|
|
143
|
+
"https://polygonscan.com/token",
|
|
144
|
+
True,
|
|
145
|
+
{
|
|
146
|
+
3: {3: 800, 6: 1330, 12: 2100, 24: 3430},
|
|
147
|
+
10: {3: 520, 6: 800, 12: 1330, 24: 2100},
|
|
148
|
+
},
|
|
149
|
+
["WPOL", "USDT", "USDC"],
|
|
150
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
151
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
152
|
+
10,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
MANTA = Blockchain(
|
|
156
|
+
BlockchainId.MANTA,
|
|
157
|
+
"MANTA",
|
|
158
|
+
"MANTA",
|
|
159
|
+
"ETH",
|
|
160
|
+
"https://pacific-explorer.manta.network/token",
|
|
161
|
+
True,
|
|
162
|
+
{
|
|
163
|
+
3: {3: 0.2, 6: 0.4, 12: 0.6, 24: 0.9},
|
|
164
|
+
10: {3: 0.1, 6: 0.2, 12: 0.4, 24: 0.6},
|
|
165
|
+
},
|
|
166
|
+
["WETH", "USDT", "USDC", "MANTA"],
|
|
167
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
168
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
169
|
+
0.05,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
SUI = Blockchain(
|
|
173
|
+
"sui",
|
|
174
|
+
"SUI",
|
|
175
|
+
"SUI Network",
|
|
176
|
+
"SUI",
|
|
177
|
+
"https://suiscan.xyz/mainnet/coin",
|
|
178
|
+
False,
|
|
179
|
+
{
|
|
180
|
+
3: {3: 170, 6: 295, 12: 505, 24: 845},
|
|
181
|
+
10: {3: 125, 6: 230, 12: 395, 24: 675},
|
|
182
|
+
},
|
|
183
|
+
["SUI", "USDC"],
|
|
184
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
185
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
186
|
+
10,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
XPL = Blockchain(
|
|
190
|
+
"plasma",
|
|
191
|
+
"XPL",
|
|
192
|
+
"Plasma",
|
|
193
|
+
"XPL",
|
|
194
|
+
"https://plasmascan.to/token",
|
|
195
|
+
True,
|
|
196
|
+
{
|
|
197
|
+
3: {3: 518, 6: 951, 12: 1677, 24: 2715},
|
|
198
|
+
10: {3: 415, 6: 726, 12: 1487, 24: 1989},
|
|
199
|
+
},
|
|
200
|
+
["WXPL", "USDT0", "USDC", "XPL"],
|
|
201
|
+
{150: 0.02, 300: 0.04, 950: 0.1, 2500: 0.2},
|
|
202
|
+
SupportedFeatures(custom_token=False, wallet=True, payment=True),
|
|
203
|
+
10,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
@staticmethod
|
|
207
|
+
@lru_cache()
|
|
208
|
+
def dict() -> Dict[str, Blockchain]:
|
|
209
|
+
return {
|
|
210
|
+
BlockchainId.SOL: Blockchains.SOL,
|
|
211
|
+
BlockchainId.ETH: Blockchains.ETH,
|
|
212
|
+
BlockchainId.BSC: Blockchains.BSC,
|
|
213
|
+
BlockchainId.TRX: Blockchains.TRX,
|
|
214
|
+
BlockchainId.BASE: Blockchains.BASE,
|
|
215
|
+
BlockchainId.SUI: Blockchains.SUI,
|
|
216
|
+
BlockchainId.MANTA: Blockchains.MANTA,
|
|
217
|
+
BlockchainId.MATIC: Blockchains.MATIC,
|
|
218
|
+
BlockchainId.XPL: Blockchains.XPL,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@staticmethod
|
|
222
|
+
def all() -> List[Blockchain]:
|
|
223
|
+
return Blockchains.dict().values()
|
|
224
|
+
|
|
225
|
+
@lru_cache()
|
|
226
|
+
def get_by_id(id: str) -> Blockchain:
|
|
227
|
+
"""Retrieve a blockchain by its ID."""
|
|
228
|
+
return Blockchains.dict().get(id)
|
|
229
|
+
|
|
230
|
+
@lru_cache()
|
|
231
|
+
def get_all_ids() -> List[str]:
|
|
232
|
+
"""Return a list of all blockchain IDs."""
|
|
233
|
+
return Blockchains.dict().keys()
|
|
234
|
+
|
|
235
|
+
@lru_cache()
|
|
236
|
+
def all_chain_types() -> Set[str]:
|
|
237
|
+
"""Return a list of all blockchain IDs."""
|
|
238
|
+
types = {c.chain_type for c in Blockchains.all()}
|
|
239
|
+
return types
|
|
240
|
+
|
|
241
|
+
@lru_cache()
|
|
242
|
+
def evms() -> List[Blockchain]:
|
|
243
|
+
"""Retrieve all EVM-compatible blockchains."""
|
|
244
|
+
return [chain for chain in Blockchains.all() if chain.evm]
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
@lru_cache()
|
|
248
|
+
def get_by_chain_type(chain_type: str) -> List[Blockchain]:
|
|
249
|
+
return [chain for chain in Blockchains.all() if chain.chain_type == chain_type]
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
@lru_cache()
|
|
253
|
+
def get_chain_symbols() -> List[str]:
|
|
254
|
+
return [c.symbol for c in Blockchains.all()]
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
@lru_cache()
|
|
258
|
+
def get_active_wallet_chains() -> List[str]:
|
|
259
|
+
chain_types = Blockchains.all_chain_types()
|
|
260
|
+
active_chain_types = []
|
|
261
|
+
for chain_type in chain_types:
|
|
262
|
+
chain = Blockchains.get_by_chain_type(chain_type)[0]
|
|
263
|
+
if chain and chain.supported_features.wallet:
|
|
264
|
+
active_chain_types.append(chain_type)
|
|
265
|
+
return active_chain_types
|