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.
@@ -0,0 +1,51 @@
1
+ from typing import Any, Dict, List
2
+
3
+
4
+ class SupportedFeatures:
5
+ def __init__(self, custom_token: bool, wallet: bool, payment: bool):
6
+ self.custom_token = custom_token
7
+ self.wallet = wallet
8
+ self.payment = payment
9
+
10
+ def __repr__(self):
11
+ return (
12
+ f"SupportedFeatures(custom_token={self.custom_token}, wallet={self.wallet}, "
13
+ f"trend={self.payment})"
14
+ )
15
+
16
+
17
+ class Blockchain:
18
+ def __init__(
19
+ self,
20
+ id: str,
21
+ symbol: str,
22
+ name: str,
23
+ native_token: str,
24
+ explorer: str,
25
+ evm: bool,
26
+ trending_prices: Dict[str, Dict[int, float]],
27
+ quote_tokens: List[str],
28
+ boost_price: Dict[int, float],
29
+ supported_features: SupportedFeatures,
30
+ min_bounty: float = 0.0,
31
+ extras: Dict[str, Any] = {}
32
+ ):
33
+ self.id = id
34
+ self.symbol = symbol
35
+ self.name = name
36
+ self.native_token = native_token
37
+ self.explorer = explorer
38
+ self.evm = evm
39
+ self.min_bounty = min_bounty
40
+ self.trending_prices = trending_prices
41
+ self.quote_tokens = quote_tokens
42
+ self.boost_price = boost_price
43
+ self.supported_features = supported_features
44
+ self.extras = extras.copy()
45
+
46
+ @property
47
+ def chain_type(self):
48
+ return "evm" if self.evm else self.id
49
+
50
+ def __repr__(self):
51
+ return f"{self.name}"
@@ -0,0 +1,376 @@
1
+ from typing import List
2
+ import aiohttp
3
+ from typing import Dict, List, Optional
4
+
5
+
6
+ class API:
7
+ DEXSC = "DexScreener"
8
+ GECKO = "GeckoTerminal"
9
+
10
+
11
+ class Token:
12
+ def __init__(self, address: str, name: str, symbol: str) -> None:
13
+ self.address = address
14
+ self.name = name
15
+ self.symbol = symbol
16
+
17
+ @classmethod
18
+ def from_dict(cls, token_dict: Dict[str, str]) -> "Token":
19
+ return cls(token_dict["address"], token_dict["name"], token_dict["symbol"])
20
+
21
+
22
+ class Transaction:
23
+ def __init__(self, buys: int, sells: int) -> None:
24
+ self.buys = buys
25
+ self.sells = sells
26
+
27
+ @classmethod
28
+ def from_dict(cls, txn_dict: Dict[str, int]) -> "Transaction":
29
+ return cls(txn_dict["buys"], txn_dict["sells"])
30
+
31
+
32
+ class Volume:
33
+ def __init__(self, h1: int, h24: int) -> None:
34
+ self.h1 = h1
35
+ self.h24 = h24
36
+
37
+ @classmethod
38
+ def from_dict(cls, volume_dict: Dict[str, int]) -> "Volume":
39
+ return cls(volume_dict["h1"], volume_dict["h24"])
40
+
41
+
42
+ class PriceChange:
43
+ def __init__(self, h1: int, h24: int) -> None:
44
+ self.h1 = h1
45
+ self.h24 = h24
46
+
47
+ @classmethod
48
+ def from_dict(cls, price_change_dict: Dict[str, int]) -> "PriceChange":
49
+ return cls(
50
+ price_change_dict["h1"],
51
+ price_change_dict["h24"],
52
+ )
53
+
54
+
55
+ class Pair:
56
+ def __init__(
57
+ self,
58
+ api: str,
59
+ chainId: str,
60
+ dexId: str,
61
+ url: str,
62
+ pairAddress: str,
63
+ baseToken: Token,
64
+ quoteToken: Token,
65
+ priceNative: str,
66
+ txns: Dict[str, Transaction],
67
+ volume: Volume,
68
+ priceChange: PriceChange,
69
+ labels: List[str] = [],
70
+ priceUsd: Optional[str] = None,
71
+ liquidity: Optional[float] = None,
72
+ fdv: Optional[int] = None,
73
+ telegram: Optional[str] = None,
74
+ twitter: Optional[str] = None,
75
+ website: Optional[str] = None,
76
+ ) -> None:
77
+ self.api = api
78
+ self.chainId = chainId
79
+ self.dexId = dexId
80
+ self.url = url
81
+ self.pairAddress = pairAddress
82
+ self.baseToken = baseToken
83
+ self.quoteToken = quoteToken
84
+ # self.priceNative = priceNative
85
+ self.priceNative = None
86
+ self.priceUsd = priceUsd
87
+ self.txns = None
88
+ self.volume = volume
89
+ self.priceChange = priceChange
90
+ self.labels = labels
91
+ self.liquidity = liquidity
92
+ self.fdv = fdv
93
+ self.telegram = telegram
94
+ self.twitter = twitter
95
+ self.website = website
96
+
97
+ @classmethod
98
+ def from_dict(cls, pair_dict: dict) -> "Pair":
99
+ base_token = Token(
100
+ pair_dict["baseToken"]["address"],
101
+ pair_dict["baseToken"]["name"],
102
+ pair_dict["baseToken"]["symbol"],
103
+ )
104
+ quote_token = Token(
105
+ pair_dict["quoteToken"]["address"],
106
+ pair_dict["quoteToken"]["name"],
107
+ pair_dict["quoteToken"]["symbol"],
108
+ )
109
+ # txns = (
110
+ # {
111
+ # key: Transaction(value["buys"], value["sells"])
112
+ # for key, value in pair_dict["txns"].items()
113
+ # }
114
+ # if pair_dict["txns"]
115
+ # else None
116
+ # )
117
+ txns = None
118
+ # volume = (
119
+ # Volume(pair_dict["volume"]["h1"], pair_dict["volume"]["h24"])
120
+ # if pair_dict["volume"]
121
+ # else None
122
+ # )
123
+ volume = None
124
+ # price_change = (
125
+ # PriceChange(pair_dict["priceChange"]["h1"], pair_dict["priceChange"]["h24"])
126
+ # if pair_dict["priceChange"]
127
+ # else None
128
+ # )
129
+ price_change = None
130
+ liquidity = pair_dict.get("liquidity", 0)
131
+
132
+ return Pair(
133
+ pair_dict["api"],
134
+ pair_dict["chainId"],
135
+ pair_dict["dexId"],
136
+ pair_dict["url"],
137
+ pair_dict["pairAddress"],
138
+ base_token,
139
+ quote_token,
140
+ # pair_dict["priceNative"],
141
+ 0,
142
+ txns,
143
+ volume,
144
+ price_change,
145
+ pair_dict["labels"],
146
+ pair_dict["priceUsd"],
147
+ liquidity,
148
+ pair_dict["fdv"],
149
+ pair_dict["telegram"],
150
+ pair_dict["twitter"],
151
+ pair_dict["website"],
152
+ )
153
+
154
+ @staticmethod
155
+ def from_dexsc_dict(pair_dict: Dict):
156
+ try:
157
+ base_token = Token.from_dict(pair_dict["baseToken"])
158
+ quote_token = Token.from_dict(pair_dict["quoteToken"])
159
+ # txns = (
160
+ # {
161
+ # key: Transaction.from_dict(value)
162
+ # for key, value in pair_dict["txns"].items()
163
+ # if key not in ["m5", "h6"]
164
+ # }
165
+ # if pair_dict["txns"]
166
+ # else None
167
+ # )
168
+ txns = None
169
+ # volume = (
170
+ # Volume.from_dict(pair_dict["volume"]) if pair_dict["volume"] else None
171
+ # )
172
+ volume = None
173
+ # price_change = (
174
+ # PriceChange.from_dict(pair_dict["priceChange"])
175
+ # if pair_dict["priceChange"]
176
+ # else None
177
+ # )
178
+ price_change = None
179
+ liquidity_info = pair_dict.get("liquidity", {})
180
+ liquidity = liquidity_info.get("usd", 0) if liquidity_info else 0
181
+
182
+ # Handle fdv more safely, ensuring it is converted to an int
183
+ fdv = pair_dict.get("fdv")
184
+ fdv = int(fdv) if fdv is not None else 0
185
+
186
+ return Pair(
187
+ API.DEXSC,
188
+ pair_dict.get("chainId"),
189
+ pair_dict.get("dexId"),
190
+ pair_dict.get("url"),
191
+ pair_dict.get("pairAddress"),
192
+ base_token,
193
+ quote_token,
194
+ pair_dict["priceNative"],
195
+ txns,
196
+ volume,
197
+ price_change,
198
+ pair_dict.get("labels") or [],
199
+ pair_dict.get("priceUsd"),
200
+ liquidity,
201
+ fdv,
202
+ pair_dict.get("telegram"),
203
+ pair_dict.get("twitter"),
204
+ pair_dict.get("website"),
205
+ )
206
+ except Exception as e:
207
+ print(f"from_dexsc_dict: {e}")
208
+
209
+ @staticmethod
210
+ def from_gecko_dict(data: dict):
211
+ relationships = data["relationships"]
212
+ base_token_data = relationships["base_token"]["data"]
213
+ quote_token_data = relationships["quote_token"]["data"]
214
+ dex = relationships["dex"]["data"]["id"].split("_")
215
+ dexId = dex[0]
216
+ labels = dex[1] if len(dex) > 1 else []
217
+ attrs = data["attributes"]
218
+ symbols = attrs["name"].split(" / ")
219
+ liquidity = float(attrs["reserve_in_usd"])
220
+ base_token_address = base_token_data["id"].split("_")[1]
221
+ base_token = Token(
222
+ base_token_address,
223
+ symbols[0],
224
+ symbols[0],
225
+ )
226
+ quote_token = Token(
227
+ quote_token_data["id"].split("_")[1],
228
+ symbols[1],
229
+ symbols[1],
230
+ )
231
+
232
+ # txns_data = attrs["transactions"]
233
+ # txns = {
234
+ # "h1": Transaction(
235
+ # int(txns_data["h1"]["buys"]), int(txns_data["h1"]["sells"])
236
+ # ),
237
+ # "h24": Transaction(
238
+ # int(txns_data["h24"]["buys"]), int(txns_data["h24"]["sells"])
239
+ # ),
240
+ # }
241
+ txns = None
242
+ pairAddress = attrs["address"]
243
+
244
+ # volume_data = attrs["volume_usd"]
245
+ # volume = Volume(float(volume_data["h1"]), float(volume_data["h24"]))
246
+ volume = None
247
+
248
+ price_change_data = attrs["price_change_percentage"]
249
+ price_change = PriceChange(
250
+ float(price_change_data["h1"]), float(price_change_data["h24"])
251
+ )
252
+ chainId = data["id"].split("_")[0]
253
+ url = f"https://www.geckoterminal.com/{chainId}/pools/{pairAddress}"
254
+ return Pair(
255
+ API.GECKO,
256
+ chainId,
257
+ dexId,
258
+ url,
259
+ pairAddress,
260
+ base_token,
261
+ quote_token,
262
+ float(attrs["base_token_price_quote_token"]),
263
+ txns,
264
+ volume,
265
+ price_change,
266
+ labels,
267
+ float(attrs.get("base_token_price_usd")),
268
+ liquidity,
269
+ float(attrs.get("fdv_usd")),
270
+ )
271
+
272
+ def to_dict(self) -> Dict:
273
+ pair_dict = {
274
+ "api": self.api,
275
+ "chainId": self.chainId,
276
+ "dexId": self.dexId,
277
+ "url": self.url,
278
+ "pairAddress": self.pairAddress,
279
+ "baseToken": {
280
+ "address": self.baseToken.address,
281
+ "name": self.baseToken.name,
282
+ "symbol": self.baseToken.symbol,
283
+ },
284
+ "quoteToken": {
285
+ "address": self.quoteToken.address,
286
+ "name": self.quoteToken.name,
287
+ "symbol": self.quoteToken.symbol,
288
+ },
289
+ # "priceNative": self.priceNative,
290
+ # "txns": (
291
+ # {
292
+ # key: {"buys": value.buys, "sells": value.sells}
293
+ # for key, value in self.txns.items()
294
+ # }
295
+ # if self.txns
296
+ # else None
297
+ # ),
298
+ # "volume": {
299
+ # "h1": self.volume.h1,
300
+ # "h24": self.volume.h24,
301
+ # },
302
+ # "priceChange": {
303
+ # "h1": self.priceChange.h1,
304
+ # "h24": self.priceChange.h24,
305
+ # },
306
+ "labels": self.labels,
307
+ "priceUsd": self.priceUsd,
308
+ "fdv": self.fdv,
309
+ "liquidity": self.liquidity,
310
+ "telegram": self.telegram,
311
+ "twitter": self.twitter,
312
+ "website": self.website,
313
+ }
314
+ return pair_dict
315
+
316
+
317
+ class DEXScreener:
318
+ async def get_pair_by_token(
319
+ token_address: str, chain_id: str, dex_id: str = None, ver: str = None
320
+ ):
321
+ url = f"https://api.dexscreener.com/latest/dex/tokens/{token_address}"
322
+ try:
323
+ async with aiohttp.ClientSession() as session:
324
+ async with session.get(url) as response:
325
+ if response.status != 200:
326
+ raise Exception(response.status)
327
+
328
+ data = await response.json()
329
+ if not data["pairs"]:
330
+ return None
331
+ for pair in data["pairs"]:
332
+ if (
333
+ pair["chainId"] == chain_id
334
+ and (dex_id is None or pair.get("dexId") == dex_id)
335
+ and (ver is None or ver in pair.get("labels", []))
336
+ ):
337
+ return Pair.from_dexsc_dict(pair)
338
+ except Exception as err:
339
+ print(f"failed to get pair by token address from dexscreener: {err}")
340
+
341
+ async def get_pair_by_pairAddress(pair_address: str, chain_id: str):
342
+ url = f"https://api.dexscreener.com/latest/dex/pairs/{chain_id}/{pair_address}"
343
+ try:
344
+ async with aiohttp.ClientSession() as session:
345
+ async with session.get(url) as response:
346
+ if response.status != 200:
347
+ raise Exception(response.status)
348
+ data = await response.json()
349
+ if not data["pairs"]:
350
+ return None
351
+ for pair in data["pairs"]:
352
+ if pair["pairAddress"].lower() == pair_address.lower():
353
+ return Pair.from_dexsc_dict(pair)
354
+
355
+ except Exception as err:
356
+ print(f"failed to get pair address from dexscreener: {err}")
357
+
358
+ async def search_address(token_address: str):
359
+ url = f"https://api.dexscreener.com/latest/dex/search/?q={token_address}"
360
+ try:
361
+ async with aiohttp.ClientSession() as session:
362
+ async with session.get(url) as response:
363
+ if response.status != 200:
364
+ raise Exception(response.status)
365
+ data = await response.json()
366
+ if not data["pairs"]:
367
+ return None
368
+ pairs: List[Pair] = []
369
+ for pair in data["pairs"]:
370
+ try:
371
+ pairs.append(Pair.from_dexsc_dict(pair))
372
+ except:
373
+ pass
374
+ return pairs
375
+ except Exception as err:
376
+ print(f"failed to search address from dexscreener: {err}")
@@ -0,0 +1,72 @@
1
+ class LaunchpadToken:
2
+ def __init__(
3
+ self,
4
+ token_address: str,
5
+ decimals: str,
6
+ total_supply: str,
7
+ token_name: str,
8
+ token_symbol: str,
9
+ chain: str,
10
+ pair_address: str,
11
+ telegram: str,
12
+ twitter: str,
13
+ website: str,
14
+ ):
15
+ self.token_address = token_address
16
+ self.decimals = int(decimals)
17
+ self.total_supply = int(float(total_supply))
18
+ self.token_name = token_name
19
+ self.token_symbol = token_symbol
20
+ self.chain = chain
21
+ self.pair_address = pair_address
22
+ self.telegram = telegram
23
+ self.twitter = twitter
24
+ self.website = website
25
+
26
+ @staticmethod
27
+ def create_token_info(data_dict):
28
+ # Defensive copy to avoid mutating input
29
+ data = dict(data_dict) if data_dict else {}
30
+
31
+ # Handle totalSupply safely
32
+ total_supply = data.get("totalSupply", 0)
33
+ try:
34
+ if str(total_supply).lower() == "nan":
35
+ total_supply = 0
36
+ total_supply = int(float(total_supply))
37
+ except (ValueError, TypeError):
38
+ total_supply = 0
39
+
40
+ # Handle decimals safely
41
+ decimals = data.get("decimals", 0)
42
+ try:
43
+ decimals = int(decimals)
44
+ except (ValueError, TypeError):
45
+ decimals = 0
46
+
47
+ return LaunchpadToken(
48
+ token_address=data.get("tokenAddress", ""),
49
+ decimals=decimals,
50
+ total_supply=total_supply,
51
+ token_name=data.get("name", ""),
52
+ token_symbol=data.get("symbol", ""),
53
+ chain=data.get("chain", ""),
54
+ pair_address=data.get("pairAddress", ""),
55
+ telegram=data.get("telegram", ""),
56
+ twitter=data.get("twitter", ""),
57
+ website=data.get("website", ""),
58
+ )
59
+
60
+ def to_dict(self):
61
+ return {
62
+ "tokenAddress": self.token_address,
63
+ "decimals": self.decimals,
64
+ "totalSupply": self.total_supply,
65
+ "name": self.token_name,
66
+ "symbol": self.token_symbol,
67
+ "chain": self.chain,
68
+ "pairAddress": self.pair_address,
69
+ "telegram": self.telegram,
70
+ "twitter": self.twitter,
71
+ "website": self.website,
72
+ }
@@ -0,0 +1,62 @@
1
+ class LeaderboardEntry:
2
+ def __init__(
3
+ self,
4
+ chat_id: int,
5
+ chat_name: str = None,
6
+ chat_link: str = None,
7
+ token_link: str = None,
8
+ boosted_score: int = 0,
9
+ raid_score: int = 0,
10
+ ):
11
+ self.chat_id = chat_id
12
+ self.chat_name = chat_name
13
+ self.chat_link = chat_link
14
+ self.token_link = token_link
15
+ self.boosted_score = boosted_score
16
+ self.raid_score = raid_score
17
+
18
+ @property
19
+ def boosted(self):
20
+ return self.boosted_score > 0
21
+
22
+ @boosted.setter
23
+ def boosted(self, value):
24
+ pass # Prevent setting boosted directly
25
+
26
+ @property
27
+ def score(self):
28
+ return int((self.boosted_score or 0) + (self.raid_score or 0))
29
+
30
+ @score.setter
31
+ def score(self, value):
32
+ pass # Prevent setting score directly
33
+
34
+ def to_dict(self):
35
+ return {
36
+ "chat_id": str(self.chat_id),
37
+ "chat_name": self.chat_name,
38
+ "chat_link": self.chat_link,
39
+ "token_link": self.token_link,
40
+ "boosted": int(self.boosted),
41
+ "score": str(self.score),
42
+ "boosted_score": (str(int(self.boosted_score or 0))),
43
+ "raid_score": (str(int(self.raid_score or 0))),
44
+ }
45
+
46
+ def __repr__(self):
47
+ return (
48
+ f"LeaderboardEntry(chat_id={self.chat_id}, chat_name={self.chat_name}, "
49
+ f"chat_link={self.chat_link}, token_link={self.token_link}, score={self.score}), boosted={self.boosted}, "
50
+ f"boosted_score={self.boosted_score}, raid_score={self.raid_score})"
51
+ )
52
+
53
+ @classmethod
54
+ def from_dict(cls, data: dict):
55
+ return cls(
56
+ chat_id=int(data.get("chat_id")),
57
+ chat_name=data.get("chat_name"),
58
+ chat_link=data.get("chat_link"),
59
+ token_link=data.get("token_link"),
60
+ boosted_score=int(data.get("boosted_score", 0)),
61
+ raid_score=int(data.get("raid_score", 0)),
62
+ )
@@ -0,0 +1,92 @@
1
+ class PostInfo:
2
+ def __init__(
3
+ self, link: str, likes: int, comments: int, shares: int = 0, bookmarks: int = 0
4
+ ):
5
+ self.link = link
6
+ self.likes = likes
7
+ self.shares = shares
8
+ self.comments = comments
9
+ self.bookmarks = bookmarks
10
+
11
+ def __str__(self):
12
+ return (
13
+ f"{self.link},{self.likes},{self.comments},{self.shares},{self.bookmarks}"
14
+ )
15
+
16
+ def __repr__(self):
17
+ return self.__str__()
18
+
19
+ def log(self):
20
+ return f"Post info likes={self.likes}, comments={self.comments}, shares={self.shares}, bookmarks={self.bookmarks}"
21
+
22
+ @classmethod
23
+ def from_string(cls, string: str):
24
+ parts = string.split(",")
25
+ link = parts[0] if parts[0] != "None" else None
26
+ likes, shares, comments, bookmarks = map(int, parts[1:])
27
+ return cls(link, likes, shares, comments, bookmarks)
28
+
29
+
30
+ class RaidInfo:
31
+ def __init__(
32
+ self,
33
+ post: PostInfo,
34
+ started_by: int,
35
+ bounty: float,
36
+ message_id: int,
37
+ lock: bool = False,
38
+ platform: str = None,
39
+ bounty_type: int = None,
40
+ ):
41
+ self.post = post
42
+ self.started_by = started_by
43
+ self.bounty = bounty
44
+ self.message_id = message_id
45
+ self.lock = lock
46
+ self.platform = platform
47
+ self.bounty_type = bounty_type
48
+
49
+ def make(
50
+ started_by: int,
51
+ message_id: int,
52
+ link: str = None,
53
+ likes: int = 0,
54
+ shares: int = 0,
55
+ comments: int = 0,
56
+ bookmarks: int = 0,
57
+ bounty: float = 0,
58
+ lock: bool = False,
59
+ platform: str = None,
60
+ bounty_type: int = None,
61
+ ):
62
+ post = PostInfo(link, likes, comments, shares, bookmarks)
63
+ return RaidInfo(
64
+ post, started_by, bounty, message_id, lock, platform, bounty_type
65
+ )
66
+
67
+ def __str__(self):
68
+ return f"{str(self.post)}|{self.started_by},{self.bounty},{self.message_id},{int(self.lock)},{self.platform},{self.bounty_type}"
69
+
70
+ def __repr__(self):
71
+ return self.__str__()
72
+
73
+ @classmethod
74
+ def from_string(cls, string: str):
75
+
76
+ post_string, raid_string = string.split("|")
77
+ parts = raid_string.split(",")
78
+ started_by = int(parts[0])
79
+ bounty = float(parts[1])
80
+ message_id = int(parts[2])
81
+ lock = bool(int(parts[3]))
82
+ platform = parts[4] if parts[4] != "None" else None
83
+ bounty_type = int(parts[5]) if parts[5] != "None" else None
84
+ post = PostInfo.from_string(post_string)
85
+ return cls(post, started_by, bounty, message_id, lock, platform, bounty_type)
86
+
87
+ def log(self) -> str:
88
+ return (
89
+ f"Raid info: started_by={self.started_by}, bounty={self.bounty}, "
90
+ f"message_id={self.message_id}, bounty_type={self.bounty_type}, "
91
+ f"lock={self.lock}, platform={self.platform}, post={self.post.log()}"
92
+ )
@@ -0,0 +1,9 @@
1
+ class UserWallet:
2
+ def __init__(self, user_id: int, address: str, pk: str, chain: str):
3
+ self.user_id = user_id
4
+ self.address = address
5
+ self.pk = pk
6
+ self.chain = chain
7
+
8
+ def __repr__(self):
9
+ return f"Wallet(user_id={self.user_id}, address={self.address}, pk={self.pk}, chain={self.chain})"