xync-client 0.0.150__py3-none-any.whl → 0.0.152__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.

Potentially problematic release.


This version of xync-client might be problematic. Click here for more details.

@@ -57,7 +57,6 @@ class AdLoader:
57
57
  coinex: models.CoinEx = None,
58
58
  curex: models.CurEx = None,
59
59
  rname: str = None,
60
- pms_from_cond: bool = False,
61
60
  ) -> models.Ad:
62
61
  if not maker:
63
62
  if not (maker := await models.Actor.get_or_none(exid=pad.userId, ex=self.ex)):
@@ -87,13 +86,13 @@ class AdLoader:
87
86
  price=int(float(pad.price) * cur_scale),
88
87
  premium=int(float(pad.premium) * 100),
89
88
  cond_id=cid,
89
+ status=self.ad_status(ad_upd.status),
90
90
  )
91
91
  try:
92
92
  ad_db, _ = await models.Ad.update_or_create(**df_unq)
93
93
  except OperationalError as e:
94
94
  raise e
95
- if not pms_from_cond:
96
- await ad_db.pms.add(*(await models.Pm.filter(pmexs__ex=self.ex, pmexs__exid__in=pad.payments)))
95
+ await ad_db.pms.add(*(await models.Pm.filter(pmexs__ex=self.ex, pmexs__exid__in=pad.payments)))
97
96
  return ad_db
98
97
 
99
98
  async def cond_load( # todo: refact from Bybit Ad format to universal
@@ -120,13 +119,7 @@ class AdLoader:
120
119
  # if not len((old_cond := await Cond.get(id=old_cid).prefetch_related('ads')).ads):
121
120
  # await old_cond.delete()
122
121
  # logging.warning(f"Cond#{old_cid} deleted!")
123
- return (
124
- ad_db
125
- or force
126
- and await self.ad_load(
127
- ad, cid, ps, coinex=coinex, curex=curex, rname=rname, pms_from_cond=pms_from_cond
128
- )
129
- ), False
122
+ return (ad_db or force and await self.ad_load(ad, cid, ps, coinex=coinex, curex=curex, rname=rname)), False
130
123
  # если эта объява в таким ид уже есть в бд, но с другим условием (или без), а текущего условия еще нет в бд
131
124
  if ad_db:
132
125
  await ad_db.fetch_related("cond__ads", "maker")
@@ -154,9 +147,7 @@ class AdLoader:
154
147
  return ad_db, False
155
148
 
156
149
  cond = await self.cond_new(cleaned, {int(ad.userId)})
157
- ad_db = await self.ad_load(
158
- ad, cond.id, ps, coinex=coinex, curex=curex, rname=rname, pms_from_cond=pms_from_cond
159
- )
150
+ ad_db = await self.ad_load(ad, cond.id, ps, coinex=coinex, curex=curex, rname=rname)
160
151
  ad_db.cond = cond
161
152
  return ad_db, True
162
153
 
xync_client/Abc/Agent.py CHANGED
@@ -1,10 +1,13 @@
1
1
  from abc import abstractmethod
2
+ from asyncio.tasks import gather
2
3
 
3
4
  from pydantic import BaseModel
4
5
  from pyro_client.client.file import FileClient
5
6
  from x_client import df_hdrs
6
7
  from x_client.aiohttp import Client as HttpClient
7
8
  from xync_bot import XyncBot
9
+ from xync_client.Abc.InAgent import BaseInAgentClient
10
+
8
11
  from xync_client.Bybit.etype.order import TakeAdReq
9
12
  from xync_schema import models
10
13
  from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Actor, Agent
@@ -15,13 +18,14 @@ from xync_client.Abc.xtype import CredExOut, BaseOrderReq, BaseAdUpdate
15
18
  from xync_client.Gmail import GmClient
16
19
 
17
20
 
18
- class BaseAgentClient(HttpClient):
21
+ class BaseAgentClient(HttpClient, BaseInAgentClient):
19
22
  bbot: XyncBot
20
23
  fbot: FileClient
21
24
 
22
25
  def __init__(
23
26
  self,
24
27
  agent: Agent,
28
+ ex_client: BaseExClient,
25
29
  fbot: FileClient,
26
30
  bbot: XyncBot,
27
31
  headers: dict[str, str] = df_hdrs,
@@ -32,8 +36,20 @@ class BaseAgentClient(HttpClient):
32
36
  self.agent: Agent = agent
33
37
  self.actor: Actor = agent.actor
34
38
  self.gmail = GmClient(agent.actor.person.user)
39
+ self.ex_client: BaseExClient = ex_client
35
40
  super().__init__(self.actor.ex.host_p2p, headers, cookies)
36
- self.ex_client: BaseExClient = self.actor.ex.client(fbot)
41
+
42
+ async def start(self):
43
+ tasks = []
44
+ if not self.is_started:
45
+ if self.agent.status & 1: # race
46
+ tasks.append(self.start_race())
47
+ if self.agent.status & 2: # in agent
48
+ tasks.append(self.start_listen())
49
+ if self.agent.status & 4: # for further
50
+ ...
51
+ self.is_started = True
52
+ return await gather(*tasks)
37
53
 
38
54
  # 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
39
55
  @abstractmethod
@@ -134,21 +150,7 @@ class BaseAgentClient(HttpClient):
134
150
  async def my_assets(self) -> dict: ...
135
151
 
136
152
  @abstractmethod
137
- async def _take_ad(self, req: TakeAdReq): ...
138
-
139
- async def take_ad(self, req: TakeAdReq):
140
- if req.is_sell:
141
- fltr = dict(ex_id=self.actor.ex_id, cred__pmcur__pm_id=req.pm_id, cred__person_id=self.actor.person.id)
142
- if req.cur_:
143
- fltr |= dict(cred__pmcur__cur__ticker=req.cur_)
144
- pmexs = await models.CredEx.filter(**fltr)
145
- else:
146
- pmexs = await models.PmEx.filter(ex_id=self.actor.ex_id, pm_id=req.pm_id)
147
- if len(pmexs) > 1:
148
- pmexs = [p for p in pmexs if p.name.endswith(f" ({req.cur_})")]
149
- req.pm_id = pmexs[0].exid
150
- req.quantity = round(req.amount / req.price, 4) # todo: to get the scale from coinEx
151
- return await self._take_ad(req)
153
+ async def take_ad(self, req: TakeAdReq): ...
152
154
 
153
155
  # Сохранение объявления (с Pm/Cred-ами) в бд
154
156
  # async def ad_pydin2db(self, ad_pydin: AdSaleIn | AdBuyIn) -> Ad:
xync_client/Abc/Ex.py CHANGED
@@ -17,6 +17,7 @@ from xync_client.pm_unifier import PmUnifier, PmUni
17
17
 
18
18
 
19
19
  class BaseExClient(HttpClient, AdLoader):
20
+ host: str = None
20
21
  cur_map: dict[int, str] = {}
21
22
  unifier_class: type = PmUnifier
22
23
  logo_pre_url: str
@@ -34,7 +35,7 @@ class BaseExClient(HttpClient, AdLoader):
34
35
  ):
35
36
  self.ex = ex
36
37
  self.bot = bot
37
- super().__init__(getattr(ex, attr), headers, cookies, proxy and proxy.str())
38
+ super().__init__(self.host or getattr(ex, attr), headers, cookies, proxy and proxy.str())
38
39
 
39
40
  @abstractmethod
40
41
  def pm_type_map(self, typ: models.PmEx) -> str: ...
@@ -1,20 +1,7 @@
1
1
  from abc import abstractmethod
2
2
 
3
- from pyro_client.client.file import FileClient
4
- from xync_bot import XyncBot
5
-
6
- from xync_client.Abc.PmAgent import PmAgentClient
7
- from xync_schema.models import Agent
8
-
9
- from xync_client.Abc.Agent import BaseAgentClient
10
-
11
3
 
12
4
  class BaseInAgentClient:
13
- pmacs: dict[int, PmAgentClient] = {}
14
-
15
- def __init__(self, agent: Agent, fbot: FileClient, bbot: XyncBot):
16
- self.agent_client: BaseAgentClient = agent.client(fbot, bbot)
17
-
18
5
  @abstractmethod
19
6
  async def start_listen(self) -> bool: ...
20
7
 
xync_client/Abc/xtype.py CHANGED
@@ -53,7 +53,7 @@ class BaseOrderReq(BaseModel):
53
53
  asset_amount: float | None = None
54
54
  fiat_amount: float | None = None
55
55
 
56
- pm_id: int = (None,)
56
+ pmex_exid: str = None # int
57
57
 
58
58
  # todo: mv from base to special ex class
59
59
  amount_is_fiat: bool = True
@@ -9,6 +9,7 @@ import websockets
9
9
  from asyncio import run, sleep
10
10
  from decimal import Decimal
11
11
 
12
+ from bybit_p2p import P2P
12
13
  from playwright.async_api import async_playwright
13
14
  from pydantic import ValidationError
14
15
  from pyro_client.client.file import FileClient
@@ -16,6 +17,7 @@ from tortoise.exceptions import IntegrityError
16
17
  from tortoise.timezone import now
17
18
  from tortoise.transactions import in_transaction
18
19
  from xync_bot import XyncBot
20
+ from xync_client.Bybit.ex import ExClient
19
21
 
20
22
  from xync_client.Abc.PmAgent import PmAgentClient
21
23
  from xync_schema import models
@@ -32,16 +34,17 @@ from xync_client.Bybit.etype.order import (
32
34
  )
33
35
  from xync_client.loader import NET_TOKEN, PAY_TOKEN
34
36
  from xync_client.Abc.InAgent import BaseInAgentClient
35
- from xync_client.Bybit.agent import AgentClient
36
37
 
37
38
 
38
39
  class InAgentClient(BaseInAgentClient):
39
- agent_client: AgentClient
40
+ actor: models.Actor
41
+ api: P2P
42
+ ex_client: ExClient
40
43
 
41
44
  async def start_listen(self):
42
- t = await self.agent_client.ott()
45
+ t = await self.ott()
43
46
  ts = int(float(t["time_now"]) * 1000)
44
- await self.ws_prv(self.agent_client.agent.auth["deviceId"], t["result"], ts)
47
+ await self.ws_prv(self.actor.agent.auth["deviceId"], t["result"], ts)
45
48
 
46
49
  # 3N: [T] - Уведомление об одобрении запроса на сделку
47
50
  async def request_accepted_notify(self) -> int: ... # id
@@ -87,11 +90,11 @@ class InAgentClient(BaseInAgentClient):
87
90
  except ValidationError as e:
88
91
  logging.error(e)
89
92
  logging.error(data["data"])
90
- order = self.agent_client.api.get_order_details(orderId=upd.id)
93
+ order = self.api.get_order_details(orderId=upd.id)
91
94
  order = OrderFull.model_validate(order["result"])
92
95
  order_db = await models.Order.get_or_none(
93
96
  exid=order.id, ad__exid=order.itemId
94
- ) or await self.agent_client.create_order(order)
97
+ ) or await self.create_order(order)
95
98
  match upd.status:
96
99
  case StatusApi.created:
97
100
  logging.info(f"Order {order.id} created at {order.createDate}")
@@ -136,7 +139,7 @@ class InAgentClient(BaseInAgentClient):
136
139
  continue
137
140
 
138
141
  # если висят незавершенные продажи с такой же суммой
139
- pos = (await self.agent_client.get_orders_active(1))["result"]
142
+ pos = (await self.get_orders_active(1))["result"]
140
143
  pos = [
141
144
  o
142
145
  for o in pos.get("items", [])
@@ -146,14 +149,14 @@ class InAgentClient(BaseInAgentClient):
146
149
  and int(order.createDate)
147
150
  < int(o["createDate"]) + 15 * 60 * 1000
148
151
  # get full_order from o, and cred or pm from full_order:
149
- and self.agent_client.api.get_order_details(orderId=o["id"])[
150
- "result"
151
- ]["paymentTermList"][0]["accountNo"]
152
+ and self.api.get_order_details(orderId=o["id"])["result"][
153
+ "paymentTermList"
154
+ ][0]["accountNo"]
152
155
  == order.paymentTermList[0].accountNo
153
156
  )
154
157
  ]
155
158
  curex = await models.CurEx.get(
156
- cur__ticker=order.currencyId, ex=self.agent_client.ex_client.ex
159
+ cur__ticker=order.currencyId, ex=self.ex_client.ex
157
160
  )
158
161
  pos_db = await models.Order.filter(
159
162
  exid__not=order.id,
@@ -163,16 +166,16 @@ class InAgentClient(BaseInAgentClient):
163
166
  created_at__gt=now() - timedelta(minutes=15),
164
167
  )
165
168
  if pos or pos_db:
166
- await self.agent_client.ex_client.bot.send(
169
+ await self.ex_client.bot.send(
167
170
  f"[Duplicate amount!]"
168
171
  f"(https://www.bybit.com/ru-RU/p2p/orderList/{order.id})",
169
- self.agent_client.actor.person.user.username_id,
172
+ self.actor.person.user.username_id,
170
173
  )
171
174
  logging.warning("Duplicate amount!")
172
175
  continue
173
176
 
174
177
  # !!! ОТПРАВЛЯЕМ ДЕНЬГИ !!!
175
- self.agent_client.api.release_assets(orderId=upd.id)
178
+ self.api.release_assets(orderId=upd.id)
176
179
  logging.info(
177
180
  f"Order {order.id} created, paid before #{tid}:{am} at {order.createDate}, and RELEASED at {now()}"
178
181
  )
@@ -236,14 +239,14 @@ class InAgentClient(BaseInAgentClient):
236
239
  case "RECEIVE":
237
240
  upd = Receive.model_validate(data["data"])
238
241
  if order_db := await models.Order.get_or_none(
239
- exid=upd.orderId, ad__maker__ex=self.agent_client.actor.ex
242
+ exid=upd.orderId, ad__maker__ex=self.actor.ex
240
243
  ).prefetch_related("ad__pair_side__pair", "cred__pmcur__cur"):
241
- im_taker = order_db.taker_id == self.agent_client.actor.id
244
+ im_taker = order_db.taker_id == self.actor.id
242
245
  im_buyer = order_db.ad.pair_side.is_sell == im_taker
243
246
  if order_db.ad.auto_msg != upd.message and upd.roleType == "user":
244
247
  msg, _ = await models.Msg.update_or_create(
245
248
  {
246
- "to_maker": upd.userId == self.agent_client.actor.exid and im_taker,
249
+ "to_maker": upd.userId == self.actor.exid and im_taker,
247
250
  "sent_at": datetime.fromtimestamp(float(upd.createDate) / 1000),
248
251
  },
249
252
  txt=upd.message,
@@ -262,7 +265,7 @@ class InAgentClient(BaseInAgentClient):
262
265
  if upd.orderStatus in (
263
266
  StatusApi.wait_for_buyer,
264
267
  ): # todo: тут приходит ордер.статус=10, хотя покупатель еще не нажал оплачено
265
- order = self.agent_client.api.get_order_details(orderId=upd.orderId)["result"]
268
+ order = self.api.get_order_details(orderId=upd.orderId)["result"]
266
269
  order = OrderFull.model_validate(order)
267
270
 
268
271
  case "CLEAR":
@@ -295,15 +298,13 @@ class InAgentClient(BaseInAgentClient):
295
298
  async def money_upd(self, order_db: models.Order):
296
299
  # обновляем остаток монеты
297
300
  await order_db.fetch_related("ad__pair_side__pair", "cred", "transfer")
298
- ass = await models.Asset.get(
299
- addr__coin_id=order_db.ad.pair_side.pair.coin_id, addr__actor=self.agent_client.actor
300
- )
301
+ ass = await models.Asset.get(addr__coin_id=order_db.ad.pair_side.pair.coin_id, addr__actor=self.actor)
301
302
  # обновляем остаток валюты
302
303
  fiat = await models.Fiat.get(
303
- cred__person_id=self.agent_client.actor.person_id, cred__pmcur_id=order_db.cred.pmcur_id
304
+ cred__person_id=self.actor.person_id, cred__pmcur_id=order_db.cred.pmcur_id
304
305
  ).prefetch_related("cred__pmcur__pm")
305
306
  fee = round(order_db.amount * (fiat.cred.pmcur.pm.fee or 0) * 0.0001)
306
- im_seller = order_db.ad.pair_side.is_sell == (_im_maker := order_db.ad.maker_id == self.agent_client.actor.id)
307
+ im_seller = order_db.ad.pair_side.is_sell == (_im_maker := order_db.ad.maker_id == self.actor.id)
307
308
  # k = int(im_seller) * 2 - 1 # im_seller: 1, im_buyer: -1
308
309
  if order_db.status == OrderStatus.created:
309
310
  if im_seller:
@@ -335,9 +336,9 @@ class InAgentClient(BaseInAgentClient):
335
336
  pma, cur = await self.get_pma_by_pmex(order_db)
336
337
  async with in_transaction():
337
338
  # отмечаем ордер на бирже "оплачен"
338
- pmex = await models.PmEx.get(pm_id=order_db.cred.pmcur.pm_id, ex=self.agent_client.actor.ex)
339
- credex = await models.CredEx.get(cred=order_db.cred, ex=self.agent_client.actor.ex)
340
- self.agent_client.api.mark_as_paid(
339
+ pmex = await models.PmEx.get(pm_id=order_db.cred.pmcur.pmex_exid, ex=self.actor.ex)
340
+ credex = await models.CredEx.get(cred=order_db.cred, ex=self.actor.ex)
341
+ self.api.mark_as_paid(
341
342
  orderId=str(order_db.exid),
342
343
  paymentType=pmex.exid, # pmex.exid
343
344
  paymentId=str(credex.exid), # credex.exid
@@ -346,7 +347,7 @@ class InAgentClient(BaseInAgentClient):
346
347
  if t := await models.Transfer.get_or_none(order=order_db, amount=order_db.amount):
347
348
  await pma.bot.send(
348
349
  f"Order# {order_db.exid}: Double send {fmt_am}{cur} to {order_db.cred.detail} #{t.pmid}!",
349
- self.agent_client.actor.person.user.username_id,
350
+ self.actor.person.user.username_id,
350
351
  )
351
352
  raise Exception(
352
353
  f"Order# {order_db.exid}: Double send {fmt_am}{cur} to {order_db.cred.detail} #{t.pmid}!"
@@ -367,38 +368,34 @@ class InAgentClient(BaseInAgentClient):
367
368
 
368
369
  async def send_receipt(self, oexid: str, tid: int) -> tuple[PmAgentClient | None, models.CredEx] | None:
369
370
  try:
370
- if res := self.agent_client.api.upload_chat_file(upload_file=f"tmp/{tid}.png").get("result"):
371
+ if res := self.api.upload_chat_file(upload_file=f"tmp/{tid}.png").get("result"):
371
372
  await sleep(0.5)
372
- self.agent_client.api.send_chat_message(
373
- orderId=oexid, contentType="pic", message=res["url"], msgUuid=uuid4().hex
374
- )
373
+ self.api.send_chat_message(orderId=oexid, contentType="pic", message=res["url"], msgUuid=uuid4().hex)
375
374
  except Exception as e:
376
375
  logging.error(e)
377
376
  await sleep(0.5)
378
- self.agent_client.api.send_chat_message(
379
- orderId=oexid, contentType="str", message=f"#{tid}", msgUuid=uuid4().hex
380
- )
377
+ self.api.send_chat_message(orderId=oexid, contentType="str", message=f"#{tid}", msgUuid=uuid4().hex)
381
378
 
382
379
  async def get_pma_by_cdex(self, order: OrderFull) -> tuple[PmAgentClient | None, models.CredEx] | None:
383
380
  cdxs = await models.CredEx.filter(
384
- ex=self.agent_client.ex_client.ex,
381
+ ex=self.ex_client.ex,
385
382
  exid__in=[ptl.id for ptl in order.paymentTermList],
386
- cred__person=self.agent_client.actor.person,
383
+ cred__person=self.actor.person,
387
384
  ).prefetch_related("cred__pmcur__cur")
388
- pmas = [pma for cdx in cdxs if (pma := self.pmacs.get(cdx.cred.pmcur.pm_id))]
385
+ pmas = [pma for cdx in cdxs if (pma := self.pmacs.get(cdx.cred.pmcur.pmex_exid))]
389
386
  if not len(pmas):
390
387
  # raise ValueError(order.paymentTermList, f"No pm_agents for {order.paymentTermList[0].paymentType}")
391
388
  return None
392
389
  elif len(pmas) > 1:
393
- logging.error(order.paymentTermList, f">1 pm_agents for {cdxs[0].cred.pmcur.pm_id}")
390
+ logging.error(order.paymentTermList, f">1 pm_agents for {cdxs[0].cred.pmcur.pmex_exid}")
394
391
  else:
395
392
  return pmas[0], cdxs[0]
396
393
 
397
394
  async def get_pma_by_pmex(self, order_db: models.Order) -> tuple[PmAgentClient, str]:
398
- pma = self.pmacs.get(order_db.cred.pmcur.pm_id)
395
+ pma = self.pmacs.get(order_db.cred.pmcur.pmex_exid)
399
396
  if pma:
400
397
  return pma, order_db.cred.pmcur.cur.ticker
401
- logging.error(f"No pm_agents for {order_db.cred.pmcur.pm_id}")
398
+ logging.error(f"No pm_agents for {order_db.cred.pmcur.pmex_exid}")
402
399
 
403
400
  @staticmethod
404
401
  def listen(data: dict | None):
@@ -445,7 +442,7 @@ async def main():
445
442
  except Exception as e:
446
443
  await b.send("😱Bybit InAgent CRASHED!!!😱", agent.actor.person.user.username_id)
447
444
  await b.send(f"```\n{''.join(traceback.format_exception(e))}\n```", agent.actor.person.user.username_id)
448
- await cl.agent_client.close()
445
+ await cl.close()
449
446
 
450
447
 
451
448
  if __name__ == "__main__":
@@ -22,17 +22,19 @@ from tortoise.expressions import Q
22
22
  from tortoise.functions import Count
23
23
  from tortoise.signals import post_save
24
24
  from urllib3.exceptions import ReadTimeoutError
25
+ from x_client import df_hdrs
25
26
  from x_model import init_db
26
27
  from x_model.func import ArrayAgg
27
28
  from xync_bot import XyncBot
29
+ from xync_client.Bybit.ex import ExClient
28
30
  from xync_schema import models
29
- from xync_schema.enums import OrderStatus
31
+ from xync_schema.enums import OrderStatus, AgentStatus
30
32
 
31
33
  from xync_schema.models import Actor, PmCur, Agent
32
34
 
33
35
  from xync_client.Abc.Agent import BaseAgentClient
34
36
  from xync_client.Abc.xtype import FlatDict, BaseOrderReq
35
- from xync_client.Bybit.etype.ad import AdPostRequest, AdUpdateRequest, Ad, AdStatus
37
+ from xync_client.Bybit.etype.ad import AdPostRequest, AdUpdateRequest, Ad, AdStatus, MyAd
36
38
  from xync_client.Bybit.etype.cred import CredEpyd
37
39
  from xync_client.Bybit.etype.order import (
38
40
  OrderRequest,
@@ -54,10 +56,8 @@ class NoMakerException(Exception):
54
56
 
55
57
 
56
58
  class AgentClient(BaseAgentClient): # Bybit client
57
- headers = {
58
- # "accept": "application/json",
59
- "Cookie": ";",
60
- }
59
+ headers = df_hdrs | {"accept-language": "ru-RU"}
60
+ sec_hdrs: dict[str, str]
61
61
  # rewrite token for public methods
62
62
  api: P2P
63
63
  last_ad_id: list[str] = []
@@ -89,8 +89,13 @@ class AgentClient(BaseAgentClient): # Bybit client
89
89
  "securityRiskToken": "",
90
90
  }
91
91
 
92
- def __init__(self, agent: Agent, fbot: FileClient, bbot: XyncBot, **kwargs):
93
- super().__init__(agent, fbot, bbot, **kwargs)
92
+ def __init__(self, agent: Agent, ex_client: ExClient, fbot: FileClient, bbot: XyncBot, **kwargs):
93
+ super().__init__(agent, ex_client, fbot, bbot, **kwargs)
94
+ self.sec_hdrs = {
95
+ "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
96
+ "gdfp": agent.auth["Risktoken"],
97
+ "tx-id": agent.auth["Risktoken"],
98
+ }
94
99
  self.api = P2P(testnet=False, api_key=agent.auth["key"], api_secret=agent.auth["sec"])
95
100
  self.hist: dict | None = None
96
101
  self.completed_orders: list[int] | None = None
@@ -150,15 +155,24 @@ class AgentClient(BaseAgentClient): # Bybit client
150
155
  raise Exception(f"Set default cur for {pmex.name}")
151
156
  if not (pmcur := await models.PmCur.get_or_none(cur_id=cur_id, pm_id=pmex.pm_id)):
152
157
  raise HTTPException(f"No PmCur with cur#{ecdx.currencyBalance} and pm#{ecdx.paymentType}", 404)
153
- dct = {
154
- "pmcur_id": pmcur.id,
155
- "name": ecdx.realName,
156
- "person_id": pers_id or self.actor.person_id,
157
- "detail": ecdx.accountNo,
158
- "extra": ecdx.branchName or ecdx.bankName or ecdx.qrcode or ecdx.payMessage or ecdx.paymentExt1,
159
- } # todo: WTD with multicur pms?
160
- cred_in = models.Cred.validate(dct, False)
161
- cred_db, _ = await models.Cred.update_or_create(**cred_in.df_unq())
158
+ xtr = ecdx.branchName
159
+ if ecdx.bankName:
160
+ xtr += (" | " if xtr else "") + ecdx.bankName
161
+ elif ecdx.payMessage:
162
+ xtr += (" | " if xtr else "") + ecdx.payMessage
163
+ elif ecdx.qrcode:
164
+ xtr += (" | " if xtr else "") + ecdx.qrcode
165
+ elif ecdx.paymentExt1:
166
+ xtr += (" | " if xtr else "") + ecdx.paymentExt1
167
+ cred_db, _ = await models.Cred.update_or_create(
168
+ {
169
+ "name": ecdx.realName,
170
+ "extra": xtr,
171
+ },
172
+ pmcur=pmcur,
173
+ person_id=pers_id or self.actor.person_id,
174
+ detail=ecdx.accountNo,
175
+ )
162
176
  credex_in = models.CredEx.validate({"exid": ecdx.id, "cred_id": cred_db.id, "ex_id": self.actor.ex.id})
163
177
  credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
164
178
  return credex_db
@@ -245,9 +259,9 @@ class AgentClient(BaseAgentClient): # Bybit client
245
259
  ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
246
260
  return float(ads[0]["price"])
247
261
 
248
- def my_ads(self, active: bool = True, page: int = 1) -> list[Ad]:
262
+ def my_ads(self, active: bool = True, page: int = 1) -> list[MyAd]:
249
263
  resp = self.api.get_ads_list(size="30", page=str(page), status=AdStatus.active if active else AdStatus.sold_out)
250
- ads = [Ad.model_validate(ad) for ad in resp["result"]["items"]]
264
+ ads = [MyAd.model_validate(ad) for ad in resp["result"]["items"]]
251
265
  if resp["result"]["count"] > 30 * page:
252
266
  ads.extend(self.my_ads(active, page + 1))
253
267
  return ads
@@ -256,9 +270,13 @@ class AgentClient(BaseAgentClient): # Bybit client
256
270
  ads = self.my_ads(True)
257
271
  if not active:
258
272
  ads += self.my_ads(False)
259
- res = [await self.ex_client.ad_load(ad, maker=self.actor) for ad in ads]
260
- res = [await models.MyAd.update_or_create(ad=ad) for ad in res]
261
- return len(res)
273
+ for ad in ads:
274
+ ad_db = await self.ex_client.ad_load(ad, maker=self.actor)
275
+ mad_db, _ = await models.MyAd.update_or_create(ad=ad_db)
276
+ exids = [pt.id for pt in ad.paymentTerms]
277
+ credexs = await models.CredEx.filter(ex_id=self.actor.ex_id, exid__in=exids)
278
+ await mad_db.creds.add(*credexs)
279
+ return len(ads)
262
280
 
263
281
  def get_security_token_create(self):
264
282
  data = self._post("/x-api/fiat/otc/item/create", self.create_ad_body)
@@ -268,46 +286,29 @@ class AgentClient(BaseAgentClient): # Bybit client
268
286
  return security_risk_token
269
287
 
270
288
  async def _check_2fa(self, risk_token) -> int:
271
- res = await self._post(
272
- "/x-api/user/public/risk/components",
273
- {"risk_token": risk_token},
274
- hdrs={
275
- # "Accept-Language": "ru,en;q=0.9",
276
- },
277
- )
289
+ data = {"risk_token": risk_token}
290
+ res = await self._post("/x-api/user/public/risk/components", data, hdrs=self.sec_hdrs)
278
291
  if res["ret_msg"] != "success":
279
292
  raise HTTPException("get")
280
293
  cres = sorted(res["result"]["component_list"], key=lambda c: c["component_id"], reverse=True)
281
- # cres = [{"component_id": "payment_password_verify"}]
282
294
  vdata = {
283
295
  "risk_token": risk_token,
284
296
  "component_list": {c["component_id"]: await self.__get_2fa(c["component_id"], risk_token) for c in cres},
285
297
  }
286
- res = await self._post(
287
- "/x-api/user/public/risk/verify",
288
- vdata,
289
- hdrs={
290
- "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
291
- "accept-language": "ru,en;q=0.9",
292
- # "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
293
- "accept-encoding": "gzip, deflate, br, zstd",
294
- "accept": "application/json",
295
- },
296
- )
297
- if res["ret_msg"] != "success":
298
+ res = await self._post("/x-api/user/public/risk/verify", vdata, hdrs=self.sec_hdrs)
299
+ if er_code := res["ret_code"] or res["result"]["ret_code"]: # если код не 0, значит ошибка
298
300
  logging.error("Wrong 2fa, wait 5 secs and retry..")
299
301
  await sleep(5)
300
- await self._check_2fa(risk_token)
301
- return res["ret_code"]
302
+ return await self._check_2fa(risk_token)
303
+ return er_code
302
304
 
303
305
  async def __get_2fa(
304
306
  self, typ: Literal["google2fa", "email_verify", "payment_password_verify", "phone_verify"], rt: str = None
305
307
  ):
306
308
  res = {"ret_msg": "success"}
307
309
  if typ != "google2fa":
308
- # "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
309
- # "accept": "application/json"
310
- res = await self._post("/x-api/user/public/risk/send/code", {"risk_token": rt, "component_id": typ})
310
+ data = {"risk_token": rt, "component_id": typ}
311
+ res = await self._post("/x-api/user/public/risk/send/code", data, hdrs=self.sec_hdrs)
311
312
  if res["ret_msg"] == "success":
312
313
  if typ == "google2fa":
313
314
  bybit_secret = self.agent.auth["2fa"]
@@ -381,36 +382,33 @@ class AgentClient(BaseAgentClient): # Bybit client
381
382
  res = res["result"]
382
383
  return PreOrderResp.model_validate(res)
383
384
 
384
- async def __order_request_build(self, por: PreOrderResp, br: BaseOrderReq) -> OrderRequest:
385
+ async def _order_request(self, bor: BaseOrderReq) -> OrderResp:
386
+ por: PreOrderResp = await self.__preorder_request(bor.ad_id)
385
387
  req = OrderRequest(
386
388
  itemId=por.id,
387
- tokenId=br.coin_exid,
388
- currencyId=br.cur_exid,
389
- side="1" if br.is_sell else "0",
390
- amount=f"{br.fiat_amount:.2f}".rstrip("0").rstrip("."),
389
+ tokenId=bor.coin_exid,
390
+ currencyId=bor.cur_exid,
391
+ side="1" if bor.is_sell else "0",
392
+ amount=f"{bor.fiat_amount:.2f}".rstrip("0").rstrip("."),
391
393
  curPrice=por.curPrice,
392
- quantity=str(round(br.fiat_amount / float(por.price), br.coin_scale)),
394
+ quantity=str(round(bor.fiat_amount / float(por.price), bor.coin_scale)),
393
395
  flag="amount",
394
396
  # online="0"
395
397
  )
396
- if br.is_sell:
398
+ if bor.is_sell:
397
399
  credex = await models.CredEx.get(
398
400
  cred__person_id=self.actor.person_id,
399
- cred__pmcur__pm__pmexs__exid=por.payments[0],
401
+ cred__pmcur__pm__pmexs__exid=[pp for pp in por.payments if pp == bor.pmex_exid][0], # bor.pmex_exid
400
402
  cred__pmcur__pm__pmexs__ex_id=self.ex_client.ex.id,
401
- cred__pmcur__cur__ticker=br.cur_exid,
403
+ cred__pmcur__cur__ticker=bor.cur_exid,
402
404
  )
403
- req = OrderSellRequest(**req.model_dump(), paymentType=por.payments[0], paymentId=str(credex.exid))
404
- return req
405
-
406
- async def _order_request(self, bor: BaseOrderReq) -> OrderResp:
407
- por: PreOrderResp = await self.__preorder_request(bor.ad_id)
408
- req: OrderRequest | OrderSellRequest = await self.__order_request_build(por, bor)
405
+ req = OrderSellRequest(**req.model_dump(), paymentType=bor.pmex_exid, paymentId=str(credex.exid))
409
406
  # вот непосредственно сам запрос на ордер
410
407
  return await self.__order_create(req, bor)
411
408
 
412
409
  async def __order_create(self, req: OrderRequest | OrderSellRequest, bor: BaseOrderReq) -> OrderResp:
413
- res: dict = await self._post("/x-api/fiat/otc/order/create", json=req.model_dump())
410
+ hdrs = {"Risktoken": self.sec_hdrs["gdfp"]}
411
+ res: dict = await self._post("/x-api/fiat/otc/order/create", json=req.model_dump(), hdrs=hdrs)
414
412
  if res["ret_code"] == 0:
415
413
  resp = OrderResp.model_validate(res["result"])
416
414
  elif res["ret_code"] == 10001:
@@ -757,10 +755,15 @@ class AgentClient(BaseAgentClient): # Bybit client
757
755
  # if round(cpc * new_premium / cpm, 2) == m
758
756
  # mad.premium = new_premium.to_eng_string()
759
757
 
760
- async def racing(
761
- self,
762
- race: models.Race,
763
- ):
758
+ async def start_race(self):
759
+ races = await models.Race.filter(started=True, road__ad__maker_id=self.actor.id).prefetch_related(
760
+ "road__ad__pair_side__pair__cur",
761
+ "road__ad__pms",
762
+ )
763
+ tasks = [asyncio.create_task(self.racing(race), name=f"Rc{race.id}") for race in races]
764
+ return await gather(*tasks)
765
+
766
+ async def racing(self, race: models.Race):
764
767
  coinex: models.CoinEx = await models.CoinEx.get(
765
768
  coin_id=race.road.ad.pair_side.pair.coin_id, ex=self.actor.ex
766
769
  ).prefetch_related("coin")
@@ -972,9 +975,25 @@ class AgentClient(BaseAgentClient): # Bybit client
972
975
  bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
973
976
  return (bc, sc), hp, vmf, zplace
974
977
 
975
- async def _take_ad(self, req: TakeAdReq):
978
+ async def take_ad(self, req: TakeAdReq):
979
+ if req.price and req.is_sell and req.cur_:
980
+ ... # todo call the get_ad_details() only if lack of data
976
981
  res = self.api.get_ad_details(itemId=req.ad_id)["result"]
977
982
  ad: Ad = Ad.model_validate(res)
983
+ pmexs = await models.PmEx.filter(ex_id=self.actor.ex_id, pm_id=req.pm_id)
984
+ if len(pmexs) > 1:
985
+ pmexs = [p for p in pmexs if p.exid in ad.payments]
986
+ # if ad.side: # продажа, я (тейкер) покупатель
987
+ # pmexs = await models.PmEx.filter(ex_id=self.actor.ex_id, pm_id=req.pm_id)
988
+ # if len(pmexs) > 1:
989
+ # pmexs = [p for p in pmexs if p.name.endswith(f" ({ad.currencyId})")]
990
+ # else:
991
+ # pmexs = await models.CredEx.filter(
992
+ # ex_id=self.actor.ex_id, cred__person_id=self.actor.person_id,
993
+ # cred__pmcur__pm_id=req.pm_id, cred__pmcur__cur__ticker=ad.currencyId
994
+ # )
995
+ # req.pm_id = pmexs[0].exid
996
+ # req.quantity = round(req.amount / float(ad.price) - 0.00005, 4) # todo: to get the scale from coinEx
978
997
 
979
998
  bor = BaseOrderReq(
980
999
  ad_id=str(ad.id),
@@ -983,7 +1002,7 @@ class AgentClient(BaseAgentClient): # Bybit client
983
1002
  cur_exid=ad.currencyId,
984
1003
  coin_exid=ad.tokenId,
985
1004
  coin_scale=ad.symbolInfo.token.scale,
986
- pm_id=req.pm_id,
1005
+ pmex_exid=pmexs[0].exid,
987
1006
  )
988
1007
  resp: OrderResp = await self._order_request(bor)
989
1008
  return resp
@@ -1099,36 +1118,56 @@ class ExcCode(IntEnum):
1099
1118
  Unknown = 912300014
1100
1119
 
1101
1120
 
1121
+ @post_save(models.Race)
1122
+ async def race_upserted(
1123
+ _cls: type[models.Race], race: models.Race, created: bool, _db: BaseDBAsyncClient, _updated: list[str]
1124
+ ):
1125
+ logging.warning(f"Race {race.id} is now upserted")
1126
+ asyncio.all_tasks()
1127
+ if created:
1128
+ ...
1129
+ else: # параметры гонки изменены
1130
+ ...
1131
+
1132
+
1102
1133
  async def main():
1103
1134
  logging.basicConfig(level=logging.INFO)
1104
1135
  cn = await init_db(TORM)
1105
1136
 
1106
- @post_save(models.Race)
1107
- async def race_upserted(
1108
- _cls: type[models.Race], race: models.Race, created: bool, _db: BaseDBAsyncClient, _updated: list[str]
1109
- ):
1110
- logging.warning(f"Race {race.id} is now upserted")
1111
- asyncio.all_tasks()
1112
- if created:
1113
- ...
1114
- else: # параметры гонки изменены
1115
- ...
1116
-
1117
1137
  agent = (
1118
- await models.Agent.filter(actor__ex_id=4, auth__isnull=False, active=True)
1119
- .prefetch_related("actor__ex", "actor__person__user__gmail")
1138
+ await models.Agent.filter(
1139
+ actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, actor__person__user__id=1
1140
+ )
1141
+ .prefetch_related(
1142
+ "actor__ex",
1143
+ "actor__person__user__gmail",
1144
+ "actor__my_ads__my_ad__race",
1145
+ "actor__my_ads__pair_side__pair__cur",
1146
+ "actor__my_ads__pms",
1147
+ )
1120
1148
  .first()
1121
1149
  )
1122
1150
  filebot = FileClient(NET_TOKEN)
1123
- await filebot.start()
1151
+ # await filebot.start()
1124
1152
  # b.add_handler(MessageHandler(cond_start_handler, command("cond")))
1125
- cl: AgentClient = agent.client(filebot, XyncBot(PAY_TOKEN, cn))
1153
+ ex = await models.Ex.get(name="Bybit")
1154
+ ecl: ExClient = ex.client(filebot)
1155
+ cl: AgentClient = agent.client(ecl, filebot, XyncBot(PAY_TOKEN, cn))
1156
+
1157
+ # req = TakeAdReq(ad_id=1955696985964089344, amount=504, pm_id=128)
1158
+ # await cl.take_ad(req)
1159
+
1160
+ # await cl.actual_cond()
1161
+ # cl.get_api_orders(), # 10, 1738357200000, 1742504399999
1126
1162
 
1127
1163
  # await cl.ex_client.set_pairs()
1128
1164
  # await cl.ex_client.set_pms()
1129
- await cl.set_creds()
1165
+
1166
+ # await cl.set_creds()
1130
1167
  await cl.export_my_ads()
1131
1168
 
1169
+ await cl.start()
1170
+
1132
1171
  # создание гонок по мои активным объявам:
1133
1172
  # for ma in cl.my_ads():
1134
1173
  # my_ad = await models.MyAd.get(ad__exid=ma.id).prefetch_related('ad__pms', 'ad__pair_side__pair')
@@ -1153,22 +1192,6 @@ async def main():
1153
1192
  # )
1154
1193
  # await cl.get_api_orders() # 43, 1741294800000, 1749157199999)
1155
1194
 
1156
- races = await models.Race.filter(started=True, road__ad__maker_id=agent.actor_id).prefetch_related(
1157
- "road__ad__pair_side__pair__cur",
1158
- "road__ad__pms",
1159
- )
1160
- tasks = [asyncio.create_task(cl.racing(race), name=f"Rc{race.id}") for race in races]
1161
- # await cl.actual_cond()
1162
- try:
1163
- await gather(
1164
- *tasks
1165
- # cl.get_api_orders(), # 10, 1738357200000, 1742504399999
1166
- )
1167
- except Exception as e:
1168
- await filebot.send("🤬Bybit agent CRASHED!!!🤬", agent.actor.person.user.username_id)
1169
- await filebot.send(e.__repr__(), agent.actor.person.user.username_id)
1170
- raise e
1171
-
1172
1195
  # await cl.cancel_order(res.orderId)
1173
1196
  await filebot.stop()
1174
1197
  await cl.close()
@@ -1,7 +1,7 @@
1
1
  from enum import StrEnum
2
2
  from typing import List, Optional, Any, Literal
3
- from pydantic import BaseModel, Field, field_serializer
4
- from xync_schema import xtype
3
+ from pydantic import BaseModel, Field
4
+ from xync_client.Bybit.etype.cred import MyPaymentTerm
5
5
  from xync_schema.xtype import BaseAd
6
6
 
7
7
  from xync_client.Abc.xtype import BaseAdUpdate
@@ -126,59 +126,14 @@ class Ad(BaseAd):
126
126
  verificationOrderLabels: List[Any] = None # for initial actualize
127
127
  verificationOrderSwitch: bool = None # for initial actualize
128
128
  version: int = None # for initial actualize
129
- #
130
- #
131
- # class Ad(BaseAd):
132
- # accountId: str = None # for initial actualize
133
- # authStatus: int = None # for initial actualize
134
- # authTag: List[str] = None # for initial actualize
135
- # ban: bool = None # for initial actualize
136
- # baned: bool = None # for initial actualize
137
- # blocked: str = None # for initial actualize
138
- # createDate: str = None # for initial actualize
139
- # currencyId: str = None # for initial actualize
140
- # executedQuantity: str = None # for initial actualize
141
- # fee: str = None # for initial actualize
142
- # finishNum: int = None # for initial actualize
143
- # frozenQuantity: str = None # for initial actualize
144
- # exid: str = Field(serialization_alias="id")
145
- # isOnline: bool = None # for initial actualize
146
- # itemType: str = None # for initial actualize
147
- # lastLogoutTime: str = None # for initial actualize
148
- # quantity: str = Field(serialization_alias="lastQuantity")
149
- # makerContact: bool = None # for initial actualize
150
- # max_fiat: str = Field(serialization_alias="maxAmount")
151
- # min_fiat: str = Field(serialization_alias="minAmount")
152
- # nickName: str = None # for initial actualize
153
- # orderNum: int = None # for initial actualize
154
- # paymentPeriod: int = None # for initial actualize
155
- # payments: List[str] = None # for initial actualize
156
- # premium: str = None # for initial actualize
157
- # price: str = None # for initial actualize
158
- # priceType: Literal[0, 1] = None # for initial actualize # 0 - fix rate, 1 - floating
159
- # allQuantity: str = Field(serialization_alias="quantity") # for initial actualize
160
- # recentExecuteRate: int = None # for initial actualize
161
- # recentOrderNum: int = None # for initial actualize
162
- # recommend: bool = None # for initial actualize
163
- # recommendTag: str = None # for initial actualize
164
- # auto_msg: str = Field(serialization_alias="remark")
165
- # is_sell: Literal[0, 1] = Field(serialization_alias="side") # for initial actualize # 0 - покупка, 1 - продажа (для мейкера, т.е КАКАЯ объява)
166
- # status: Literal[10, 20, 30] # 10: online; 20: offline; 30: completed
167
- # symbolInfo: SymbolInfo = None # for initial actualize
168
- # tokenId: str = None # for initial actualize
169
- # tokenName: str = None # for initial actualize
170
- # tradingPreferenceSet: TradingPreferenceSet | None = None # for initial actualize
171
- # userId: str = Field(serialization_alias="maker__exid")
172
- # userMaskId: str = None # for initial actualize
173
- # userType: str = None # for initial actualize
174
- # verificationOrderAmount: str = None # for initial actualize
175
- # verificationOrderLabels: List[Any] = None # for initial actualize
176
- # verificationOrderSwitch: bool = None # for initial actualize
177
- # version: int = None # for initial actualize
178
-
179
- @field_serializer("status")
180
- def status(self, status, _info) -> xtype.AdStatus:
181
- return {10: xtype.AdStatus.active, 20: xtype.AdStatus.defActive, 30: xtype.AdStatus.soldOut}[status]
129
+
130
+ # @field_serializer("status")
131
+ # def status(self, status, _info) -> xtype.AdStatus:
132
+ # return {10: xtype.AdStatus.active, 20: xtype.AdStatus.defActive, 30: xtype.AdStatus.soldOut}[status]
133
+
134
+
135
+ class MyAd(Ad):
136
+ paymentTerms: List[MyPaymentTerm]
182
137
 
183
138
 
184
139
  class AdPostRequest(BaseModel):
@@ -1,5 +1,3 @@
1
- from typing import Literal
2
-
3
1
  from pydantic import BaseModel
4
2
 
5
3
  from xync_client.Abc.xtype import CredExOut
@@ -15,18 +13,31 @@ class PaymentItem(BaseModel):
15
13
  required: bool
16
14
 
17
15
 
18
- class PaymentConfigVo(BaseModel):
19
- paymentType: str
16
+ class BasePaymentConf(BaseModel):
17
+ paymentType: int
18
+ paymentName: str
19
+
20
+
21
+ class PaymentConfig(BasePaymentConf):
22
+ class PaymentTemplateItem(BaseModel):
23
+ labelDialect: str
24
+ placeholderDialect: str
25
+ fieldName: str
26
+
27
+ paymentDialect: str
28
+ paymentTemplateItem: list[PaymentTemplateItem]
29
+
30
+
31
+ class PaymentConfigVo(BasePaymentConf):
20
32
  checkType: int
21
33
  sort: int
22
- paymentName: str
23
34
  addTips: str
24
35
  itemTips: str
25
- online: Literal[0, 1] # Non-balance coin purchase (0 Offline), balance coin purchase (1 Online)
26
- items: list[PaymentItem]
36
+ online: int
37
+ items: list[dict[str, str | bool]]
27
38
 
28
39
 
29
- class CredEpyd(CredExOut):
40
+ class PaymentTerm(CredExOut):
30
41
  id: str # int
31
42
  realName: str
32
43
  paymentType: int # int
@@ -44,7 +55,7 @@ class CredEpyd(CredExOut):
44
55
  mobile: str
45
56
  businessName: str
46
57
  concept: str
47
- online: str
58
+ online: str = None
48
59
  paymentExt1: str
49
60
  paymentExt2: str
50
61
  paymentExt3: str
@@ -52,6 +63,14 @@ class CredEpyd(CredExOut):
52
63
  paymentExt5: str
53
64
  paymentExt6: str
54
65
  paymentTemplateVersion: int
66
+
67
+
68
+ class MyPaymentTerm(PaymentTerm):
69
+ paymentConfig: PaymentConfig
70
+ realNameVerified: bool
71
+
72
+
73
+ class CredEpyd(PaymentTerm):
55
74
  securityRiskToken: str = ""
56
75
 
57
76
 
@@ -3,7 +3,7 @@ from typing import Literal
3
3
 
4
4
  from pydantic import BaseModel
5
5
 
6
- from xync_client.Bybit.etype.cred import CredEpyd
6
+ from xync_client.Bybit.etype.cred import CredEpyd, PaymentTerm as CredPaymentTerm, PaymentConfigVo
7
7
 
8
8
 
9
9
  class Topic(IntEnum):
@@ -47,9 +47,9 @@ class StatusApi(IntEnum):
47
47
  class TakeAdReq(BaseModel):
48
48
  ad_id: int | str
49
49
  amount: float
50
- quantity: float = None
51
- is_sell: bool
52
- price: float
50
+ quantity: float | None = None
51
+ is_sell: bool | None = None
52
+ price: float | None = None
53
53
  pm_id: int | str = None
54
54
  cur_: str | None = None
55
55
 
@@ -106,8 +106,8 @@ class OrderResp(BaseModel):
106
106
  confirmId: str = ""
107
107
  success: bool
108
108
  securityRiskToken: str = ""
109
- riskTokenType: Literal["challenge"] = None
110
- riskVersion: Literal["1", "2"] = None
109
+ riskTokenType: Literal["challenge", ""] = ""
110
+ riskVersion: Literal["1", "2", ""] = ""
111
111
  needSecurityRisk: bool
112
112
  isBulkOrder: bool
113
113
  confirmed: str = None
@@ -143,43 +143,7 @@ class AppraiseInfo(BaseModel):
143
143
  updateDate: str
144
144
 
145
145
 
146
- class PaymentConfigVo(BaseModel):
147
- paymentType: str
148
- checkType: int
149
- sort: int
150
- paymentName: str
151
- addTips: str
152
- itemTips: str
153
- online: int
154
- items: list[dict[str, str | bool]]
155
-
156
-
157
- class PaymentTerm(BaseModel):
158
- id: str
159
- realName: str
160
- paymentType: int
161
- bankName: str
162
- branchName: str
163
- accountNo: str
164
- qrcode: str
165
- visible: int
166
- payMessage: str
167
- firstName: str
168
- lastName: str
169
- secondLastName: str
170
- clabe: str
171
- debitCardNumber: str
172
- mobile: str
173
- businessName: str
174
- concept: str
175
- online: str
176
- paymentExt1: str
177
- paymentExt2: str
178
- paymentExt3: str
179
- paymentExt4: str
180
- paymentExt5: str
181
- paymentExt6: str
182
- paymentTemplateVersion: int
146
+ class PaymentTerm(CredPaymentTerm):
183
147
  paymentConfigVo: PaymentConfigVo
184
148
  ruPaymentPrompt: bool
185
149
 
xync_client/Bybit/ex.py CHANGED
@@ -2,8 +2,10 @@ import json
2
2
  from asyncio import run
3
3
 
4
4
  from pyro_client.client.file import FileClient
5
+ from x_client import df_hdrs
5
6
  from x_model import init_db
6
7
  from xync_schema import models, xtype
8
+ from xync_schema.enums import AdStatus
7
9
  from xync_schema.models import Ex, Agent
8
10
 
9
11
  from xync_client.Abc.Ex import BaseExClient
@@ -14,7 +16,8 @@ from xync_client.loader import TORM
14
16
 
15
17
 
16
18
  class ExClient(BaseExClient): # Bybit client
17
- headers = {"cookie": ";"} # rewrite token for public methods
19
+ host = "api2.bybit.com"
20
+ headers = df_hdrs # rewrite token for public methods
18
21
  agent: Agent = None
19
22
 
20
23
  async def _get_auth_cks(self) -> dict[str, str]:
@@ -22,6 +25,14 @@ class ExClient(BaseExClient): # Bybit client
22
25
  self.agent = await Agent.get(actor__ex=self.ex).prefetch_related("actor")
23
26
  return self.agent.auth["cookies"]
24
27
 
28
+ @staticmethod
29
+ def ad_status(status: int) -> AdStatus:
30
+ return {
31
+ 10: AdStatus.active,
32
+ 20: AdStatus.defActive,
33
+ 30: AdStatus.soldOut,
34
+ }[status]
35
+
25
36
  async def _get_config(self):
26
37
  resp = await self._get("/fiat/p2p/config/initial")
27
38
  return resp["result"] # todo: tokens, pairs, ...
xync_client/Htx/agent.py CHANGED
@@ -46,7 +46,7 @@ class AgentClient(BaseAgentClient):
46
46
 
47
47
  async def cred_new(self, cred: models.Cred) -> models.CredEx:
48
48
  pmcur = await cred.pmcur
49
- exid = str(await models.PmEx.get(pm_id=pmcur.pm_id, ex=self.ex_client.ex).values_list("exid", flat=True))
49
+ exid = str(await models.PmEx.get(pm_id=pmcur.pmex_exid, ex=self.ex_client.ex).values_list("exid", flat=True))
50
50
  field_map = {
51
51
  "payee": "name",
52
52
  "bank": "extra",
@@ -71,7 +71,7 @@ class AgentClient(BaseAgentClient):
71
71
 
72
72
  async def cred_upd(self, cred: models.Cred, exid: int) -> models.CredEx:
73
73
  pmcur = await cred.pmcur
74
- _exid = str(await models.PmEx.get(pm_id=pmcur.pm_id, ex=self.ex_client.ex).values_list("exid", flat=True))
74
+ _exid = str(await models.PmEx.get(pm_id=pmcur.pmex_exid, ex=self.ex_client.ex).values_list("exid", flat=True))
75
75
  field_map = {
76
76
  "payee": "name",
77
77
  "bank": "extra",
xync_client/Mexc/agent.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from asyncio import run
2
+ from hashlib import md5
2
3
  from uuid import uuid4
3
4
 
4
5
  from pyro_client.client.file import FileClient
@@ -24,11 +25,11 @@ class AgentClient(BaseAgentClient):
24
25
  self.i = 33 if self.i > 9998 else self.i + 2
25
26
  hdrs = self.headers | {"trochilus-trace-id": f"{uuid4()}-{self.i:04d}"}
26
27
  auth = {
27
- "p0": "hzE/loX7MBr0j8vnx7n5qY72DCChDHOiNG/ZAXbc0BrKIiwLc7cqg0vDdK15x/qArCO1xCX2jNqmtGO0aUxa0yrspnh2xX8tJnZ1oDbvkqPjcJuKdnvehVL2rMHVXOtC0ImfcZ++zfmIXrNFchhC+u2O9LqyjiHw8F5XNtdkMVWzcgs2tNAZmZiyliHDQso3WslCuRyp0iAogxT99DdP2A5bNoqOFvcurk0+/mMFskoeGwykq7OBVAGKhHwr4jbFFURGE5DYN1tKHUtIYkDaul5b+wpLn83IEYSEhwwxfSE+cy3VvKE7xPiAOf/ptmZa9s0FyALNb8jCeTLwa8Wh4stO0qM/flL0oOHXXA+dxiQtQIDOdFqOIKoDhPrZ9nnqq0V/UyhACk4Omf7dc9ElVtbNuX4Q/bgZefAE674y+IXvBHl9ss36kVOImui2xpT0lH+sc35pR8xht5SndOTz6+oiHLIr+z850DYSVpj06i343sSjTfQxNj1bKATpRTXgOVwPTUO67hMFSFFpNLQ7Mxl5IeKEXI7dZjud1qlxIVSPJAYe6m3vomY6jm4U50C11Nh9CXC9p9TcD0e7QPfchzoSiFjzkwCxfOjAsxWzKkSpSnoaQTHO58c6RieHszMsahazVqCQ9rtLJV4kJ65lKLPegKrBY/yI4gXQs0NdvtdFjdGd5EBTC1inr3g7PeSvNZc9PzN5y/x0oC5r2KGBY4CdxqWxzAnr7Tvnl2sL8MPZ6WDcizCnK6aegfl0Kk976MOlC221ZfPutfYTuyB4d1utADE82g2X63idNtF/h6iUl9bIsAKisoNzgUz26MCzkG/K++Cm/0/Sip40znh4lmT0z6XNhA4GiXmjbkxrhUsI4M8HiVRjuNWvrdq7D2l81j5K+JYHFWOaAUQuDNx+bB4eB9KJnHX03hxkJYfhYQtxr+X1LAPITWWfb+qmFy8x4+mWP1TVTBl27j7FAqWXnCL8FeJQ4sSP7Xphj3t7Fd62RtQewiq5L/BYegJGD3c9NvQBvC2gOXMuhTIE9RcQAUdXDsKKizZ4mXpXTvcGYXwednrVwz1SaLe8WhEe54e6tSLRf5Or3pce/7epsDqrKQXDeKugo6so//SN8y7wPsd8xpGeBtUjhvrESwNcRp305pYm4f+2A4lF71a92P6PHSOQm5ruGT7qB+9uwvzXIoFY985dI8aRq7g7GbAyQ1z7LhhjJzS11xUEpekunxdAxySl6OOFcAlTjnx8FgGBl2xiP+KtTJeSVB4b07OsqoUmAS54I0Sj19Tm8WQz+FKbKZ0eReApT+gyyqFJBSRcJYIyA3dLL/fYSNfNmNUu76KGR+o3xMHTSb8V/kVHmgWs6qmE98NE1BcXWnABiHVkqZU0lU/R0b9jhuUaYXB0md0VjyY61MztgfEk6VQnWfPQT/POuic6lBf4UJ3IWolsGttYlLo9sa9mAUqLXuDeSo+mTs7nDECVyYGZK/E+BCG+eEnhmwKB8dvY500kE/0Megf4i4Ymi0GG0jjy3z8VLsjP2cnUGrQHfe8d/etqgPN0CFI7crxEFoAeo8fl9VfEyr+ug61MWt+jcFtU2wfK66A75iPHobQpZVxW1tOv72PhiKTDWjgsLifJlYmFG1Eoadq8kiSEgkldsSCEYPTSjj4anXGSVBicRiaNliyQTuDT8DOjKmv3jGgu7opv/wKQ8Lz1FZDwL6i9WJExFzebdgJn+RNRZjpjWWKH0A9c0ZTd0Xa9q9WZyxEe8bycEkf4e4jnoalL4w==",
28
- "k0": "Dt/l/MGcXIAOoCeR1L1VW5vTgqRcc4qqXzXrb6O+/a/2c9pHywRAVhPZZm46Us91VyNi2zg3S6Dzpe3FiwnC/NC1zwFAfKLIcKYgnDxTHesv5jUEYghDFlDsZFzCeY6b0TJ6ZlNr7+/NOQ4Hx1gbCsOlO0BrcMJ+DlqJlR7KM0od2SBWmbmJO1Dh25H/PzKnPhzq4NDuzHGcsDMrlkqmsKFHvkF01IiPVOCMFMdOWfCy3O4HGsSu3r9b/JvhxsC8hdfOZg1JKKDtKOGaHo8Fmajqozp39akG8EKk4C27hf2qDT2zh0LLrb3ZL0Gnd0y33LJTvUbYBSfFK1b7xv0i0A==",
29
- "chash": "ccef0ebde038ce0e7cb086851c51781c498a429be65ab70bf4f46671c637516e",
30
- "mtoken": "9482d04a3235e3090e954d3b6a8871e1",
31
- "mhash": "06cabb6939e0262495aa5d55e44dfc27",
28
+ "p0": self.actor.agent.auth["p0"],
29
+ "k0": self.actor.agent.auth["k0"],
30
+ "chash": self.actor.agent.auth["chash"],
31
+ "mtoken": self.actor.agent.auth["deviceId"],
32
+ "mhash": md5(self.actor.agent.auth["deviceId"].encode()).hexdigest(),
32
33
  }
33
34
  data = {
34
35
  "scene": "TRADE_BUY",
@@ -273,7 +273,7 @@ async def _test():
273
273
  pma = await models.PmAgent.get(
274
274
  active=True,
275
275
  auth__isnull=False,
276
- pm_id=o.cred.pmcur.pm_id,
276
+ pm_id=o.cred.pmcur.pmex_exid,
277
277
  user__person__actors=o.ad.maker_id,
278
278
  user__status=UserStatus.ACTIVE,
279
279
  ).prefetch_related("pm", "user__gmail", "user__username__session")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.150
3
+ Version: 0.0.152
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -2,18 +2,18 @@ xync_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  xync_client/details.py,sha256=21itVPCgAtaYRR1H9J9oYudj95gafcFjExUN6QL17OI,1330
3
3
  xync_client/loader.py,sha256=hxf8ob50DO7r_qjr2qBoO7IyjkXeHHzVQ63YjXerjoU,600
4
4
  xync_client/pm_unifier.py,sha256=T2Xh-tvcu114P2YBI6RK_XDiaIhyq6ABMrXDuXPlx7A,6541
5
- xync_client/Abc/AdLoader.py,sha256=VgT6y1b2icFSm4-pjpA2H5WUXjlRf7acBxBR9t9Tips,13701
6
- xync_client/Abc/Agent.py,sha256=IiDjtm5UckYIr6HTPEvSq9b_hbWjR8GCsfYlwthgJ9s,6591
5
+ xync_client/Abc/AdLoader.py,sha256=fUHYwa8U0sCV3hTq2DjREt6RclxJelHB9b-mCD4HSnE,13500
6
+ xync_client/Abc/Agent.py,sha256=bvD3lGJMcOLY14dyz8in6PqNuTkz_MAdHinTUYvTePs,6421
7
7
  xync_client/Abc/Asset.py,sha256=hlgyFaU9byr2N2r8Heh-_ICx49SKuKxfRTUA4yQWmEw,454
8
8
  xync_client/Abc/Auth.py,sha256=OPQXN7_XYQZP9431ylFksd6JDusbKG8N_1g6CXTZ6yY,1495
9
9
  xync_client/Abc/BaseTest.py,sha256=vaAs5Z4HYV7k_C3zQz6JKO75s2hXtVbBI3-0Srkzv5Q,2388
10
- xync_client/Abc/Ex.py,sha256=6i78hduLVULyaTYlKbu7hsSrCIWVGrFB0HMll0TeSxM,13091
10
+ xync_client/Abc/Ex.py,sha256=PxB_s4pGSAcR5oraZxml749NH4sHS07VMv6eIq2ivt8,13125
11
11
  xync_client/Abc/Exception.py,sha256=Sts7RpP370NBdjaH_cyXDdHtjge8zXNUGWCrKw49Zyk,482
12
12
  xync_client/Abc/HasAbotUid.py,sha256=LsTHHjMHBauCwJoqgDa9Lx4R6xsDOHfsN4jM539Bpqg,279
13
- xync_client/Abc/InAgent.py,sha256=XLf5czbxxEimsIIe653buoP7OsWZD6mc2w37q4TkNd0,703
13
+ xync_client/Abc/InAgent.py,sha256=8BnZ7VzWLIJY93xnNTqlpY3JdarQkkpRRjDDEALaVAA,303
14
14
  xync_client/Abc/Order.py,sha256=7-FGIJu5z9aYi0A_eJV4F-cp_6Mz_izNpefexDQZvHw,2428
15
15
  xync_client/Abc/PmAgent.py,sha256=8ozQDxriAwtU2cNsJleuWcZ2ZdNeZPhgwO6l6jvi0MY,4350
16
- xync_client/Abc/xtype.py,sha256=FRvYm_VeQiCNOzjw2Ey1iwl9PC8hfjcAqKEEpU5_7Fc,2607
16
+ xync_client/Abc/xtype.py,sha256=SnzcFm6muyaNXc2qRKub9nRnkaslD19wU-eAK3HbRMA,2615
17
17
  xync_client/Binance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  xync_client/Binance/binance_async.py,sha256=LP2DZaHwkfsp_4Tjvetb-1ntjQtJfODF0OgZpoPx4KU,2688
19
19
  xync_client/Binance/earn_api.py,sha256=hvk0MaVTLszIglQXVhbUjGcaHfbF9Ul7FFXmy94U2so,4411
@@ -36,21 +36,21 @@ xync_client/BitGet/agent.py,sha256=YVs3bDY0OcEJGU7m2A8chzO6PFhWDnQQrA-E6MVkBBg,3
36
36
  xync_client/BitGet/ex.py,sha256=uEvvXuLaJv8o8BFi0bMA3XyBuTfVDWagAjLOHZl-xlE,3765
37
37
  xync_client/BitGet/etype/ad.py,sha256=fysSW47wGYjSOPUqY864z857AJz4gjN-nOkI1Jxd27U,1838
38
38
  xync_client/BitPapa/ex.py,sha256=U-RRB_RSOtErfRgxOZYWegZ_td_uZO37YKo3Jxchf_w,912
39
- xync_client/Bybit/InAgent.py,sha256=1Y4ZyxqAY8xbAflku48fJjjlSs4pOz2mFFJSO9iWg8w,26405
40
- xync_client/Bybit/agent.py,sha256=gejZk59WhhBOPPdzmGk2UIoNyKj-bfsJnz18jCa2Pto,53407
41
- xync_client/Bybit/ex.py,sha256=3oARvReBoDs90FzQY31-L-q_YU-TIRbvWB7z4lwESsA,4715
39
+ xync_client/Bybit/InAgent.py,sha256=X-35twM8kftkFFB1fBSbU2aWGBkU1wrkMQ0tejX84S0,26049
40
+ xync_client/Bybit/agent.py,sha256=En7hYrMbIqHZJYnncrX0EhjKXlO6sQBF_lytWA8jaKs,54632
41
+ xync_client/Bybit/ex.py,sha256=UgtTE42nmJ2y5fMB2xwsr90wXOS_0qzBSPGdjo4z1pI,5004
42
42
  xync_client/Bybit/order.py,sha256=H4UIb8hxFGnw1hZuSbr0yZ4qeaCOIZOMc6jEst0ycBs,1713
43
43
  xync_client/Bybit/web_earn.py,sha256=qjqS10xlFc8r40IhDdPZ0LxA2dFEGbvBGXdsrUUJCMo,3019
44
44
  xync_client/Bybit/web_p2p.py,sha256=sAXzK03t6jwDnz4rrvP2IzI0KxfKa7C_5GuzH1HwLuA,11768
45
45
  xync_client/Bybit/ws.py,sha256=OQjZHo_MiAH1dlOs3c-aUZBKyqToNTmH560udh6RYDE,1431
46
- xync_client/Bybit/etype/ad.py,sha256=pCD0I9SL4Paaegs85fHGtvZ-7Cm917AQXYel0k1MbY0,8065
47
- xync_client/Bybit/etype/cred.py,sha256=qDQUsMqLV4XtXKYWZV4f805kLDf7AdcPYscHRA-IMBo,1386
48
- xync_client/Bybit/etype/order.py,sha256=EuBZPS_mkGgoEF9kSne3g-BpopBD6io8XPs5Uxbyx_U,8970
46
+ xync_client/Bybit/etype/ad.py,sha256=r356t4Kmho5Q6BAS0JWyRmsxui427W9O2Y1glUU6l3g,5091
47
+ xync_client/Bybit/etype/cred.py,sha256=CH6xqHh1214bLhHy_K9eVBb1SJVhWBfGb0l3LtBf3fU,1701
48
+ xync_client/Bybit/etype/order.py,sha256=wkePjjMXZcc2Nqbp8RU-HVruIV3qD1Ki4YrT4VOlBZc,8372
49
49
  xync_client/Gate/ex.py,sha256=QbhB3u7TWnvVGD-AknB2nay6KZjEXQ-1JT9UacX4sWI,3735
50
50
  xync_client/Gate/premarket.py,sha256=IW-CgkmNJePJR2j_NRfULNKTePMX35XlhldqdiO76zY,2138
51
51
  xync_client/Gate/etype/ad.py,sha256=-EwtFcOWWvtE6UjaOdsuXWDTCVjAIRK0kSEsqPP4Yls,1296
52
52
  xync_client/Gmail/__init__.py,sha256=9JGT8PyzJaOTVvaFV0Gki3Fdo6Bp6m6DnWOPGZJ-eAA,5436
53
- xync_client/Htx/agent.py,sha256=rOURgTeY9TsA-IzT78l5-Ze91i0x1PY683mrX38MSgs,7356
53
+ xync_client/Htx/agent.py,sha256=RzDgs5HSIoyoCsPjNcbmI1GyXjq8AzTXbUpi5jcyBZY,7364
54
54
  xync_client/Htx/earn.py,sha256=jL6eRwytZEMRom_3bFm1DYthi_GFg-E1Mm3ZDXENHSg,2386
55
55
  xync_client/Htx/ex.py,sha256=GuWK5lA_MvtSd-0DhKf2MAstKvZMHhc3BIiZSgdwZv4,6074
56
56
  xync_client/Htx/etype/__init__.py,sha256=sZIhFOxj2dRQRmMe86-y9vlzOGAPo1qoOi6u1qVxWr0,123
@@ -62,7 +62,7 @@ xync_client/KuCoin/ex.py,sha256=w-6-aedlC1mYf8LShMv6pOrQzqMR9E6yIyXGUHQP888,3237
62
62
  xync_client/KuCoin/web.py,sha256=--OHS0Z29xjfNUjdTL7K0EDmU4dwej95OJ8Sv4PsxLI,920
63
63
  xync_client/KuCoin/etype/ad.py,sha256=MTx90Qo2xFKvfgIr4_qMowjwO23HVpFCD6J7INNFDuQ,1223
64
64
  xync_client/KuCoin/etype/pm.py,sha256=S50S5fyY5YeWlcPwO66o-GsPcdqgoeXuxvmEIy6Zqvs,130
65
- xync_client/Mexc/agent.py,sha256=htJm-FSrKGJ0i3E169Ji901yxUItI6QtjalgRqHR3rA,4905
65
+ xync_client/Mexc/agent.py,sha256=7xhT-UH3aLFAVAfnGUhHqOauNeADNt84ifsT-x3ydq4,2843
66
66
  xync_client/Mexc/ex.py,sha256=jpITGa2GTeYayMVStQOomBW-P0YQoXjKExKZi_kS-2A,4295
67
67
  xync_client/Mexc/etype/ad.py,sha256=GUgvylx_z64CXNcw0YejUQJHg9F59eRo5v0zU7DRrAM,1434
68
68
  xync_client/Mexc/etype/pm.py,sha256=m5kCoMx9IEKUPB-z7YwwymQhASkv2npC4-Z_ePYeeRY,453
@@ -81,7 +81,7 @@ xync_client/Pms/Payeer/login.py,sha256=GyNwB-GKE_1nlkbZJ0KNI-EnCT0j_S9ogFdn-ufb-
81
81
  xync_client/Pms/Sber/__init__.py,sha256=dxQfd9ZPhFTc_C4xrwaxrV6p0SijDCLNzBeUv3oQG38,4926
82
82
  xync_client/Pms/Sber/utils.py,sha256=gIeJspwvoBbOBt-fjxwW4WDHPoL2Evs8LVufsjrFOfo,1870
83
83
  xync_client/Pms/Tinkoff/__init__.py,sha256=ZyLvBEUn-vh-85oPUUDS586AHgvx3c-mkQE3yBQtbw8,5580
84
- xync_client/Pms/Volet/__init__.py,sha256=JGd1QDn_H-tqck932cbARGLSOCHmnHKIns05Ll8dowA,12048
84
+ xync_client/Pms/Volet/__init__.py,sha256=lAvGjcdL7xpUmXYRaNqZP7MWvVnmzcJ_frEQaedJMJ8,12052
85
85
  xync_client/Pms/Volet/api.py,sha256=6_dH2rzmyyvha3PeoiZdSltiAzKDWn8roSUJOAErX4M,3673
86
86
  xync_client/Pms/Volet/pl.py,sha256=l7lvUrpjFoObXPHaseOIAcSbkNqJdpy6OLDutxYJH3U,2451
87
87
  xync_client/Pms/Volet/_todo_req/req.mjs,sha256=ut3Jw37rL5lY7SskjZ9f1l0VE33tuP-PZEYUTcJMc2I,817
@@ -98,7 +98,7 @@ xync_client/TgWallet/order.py,sha256=BOmBx5WWfJv0-_-A8DcR-Xd8utqO_VTmSqSegm0cteQ
98
98
  xync_client/TgWallet/pyd.py,sha256=Ys3E8b3RLuyQ26frWT0F0BorkNxVpxnd18tY4Gp9dik,5636
99
99
  xync_client/TgWallet/pyro.py,sha256=2K7QWdo48k4MbbgQt90gdz_HiPck69Njm4xaMjIVgoo,1440
100
100
  xync_client/TgWallet/web.py,sha256=kDcv9SKKQPe91mw1qJBpbuyKYCAmZdfdHJylHumLBVU,1608
101
- xync_client-0.0.150.dist-info/METADATA,sha256=MYF6WFaa4ISVIDcRTVfwr4fLGEWSmFz-ZnqLbGOH6DI,1149
102
- xync_client-0.0.150.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
103
- xync_client-0.0.150.dist-info/top_level.txt,sha256=bmYEVIIrD3v7yFwH-X15pEfRvzhuAdfsAZ2igvNI4O8,12
104
- xync_client-0.0.150.dist-info/RECORD,,
101
+ xync_client-0.0.152.dist-info/METADATA,sha256=cv_7YQL73atQmcBt1w7E4VY-6ZI8lOkMrmZwxDMF_6M,1149
102
+ xync_client-0.0.152.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
103
+ xync_client-0.0.152.dist-info/top_level.txt,sha256=bmYEVIIrD3v7yFwH-X15pEfRvzhuAdfsAZ2igvNI4O8,12
104
+ xync_client-0.0.152.dist-info/RECORD,,