xync-client 0.0.25.dev105__tar.gz → 0.0.25.dev110__tar.gz

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.
Files changed (96) hide show
  1. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/.env.sample +1 -0
  2. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/.gitignore +2 -1
  3. {xync_client-0.0.25.dev105/xync_client.egg-info → xync_client-0.0.25.dev110}/PKG-INFO +1 -1
  4. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/Agent.py +21 -24
  5. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/AuthTrait.py +3 -2
  6. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/Ex.py +20 -23
  7. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/types.py +4 -0
  8. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/etype/ad.py +4 -1
  9. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Gate/ex.py +8 -0
  10. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Okx/ex.py +8 -0
  11. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/agent.py +79 -71
  12. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/auth.py +3 -1
  13. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/pyd.py +8 -2
  14. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110/xync_client.egg-info}/PKG-INFO +1 -1
  15. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client.egg-info/SOURCES.txt +0 -1
  16. xync_client-0.0.25.dev105/tests/res.js +0 -26953
  17. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/.pre-commit-config.yaml +0 -0
  18. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/README.md +0 -0
  19. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/makefile +0 -0
  20. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/pyproject.toml +0 -0
  21. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/setup.cfg +0 -0
  22. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/TestAgent.py +0 -0
  23. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/TestAsset.py +0 -0
  24. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/TestEx.py +0 -0
  25. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/TestOrder.py +0 -0
  26. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Binance/test_binance.py +0 -0
  27. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  28. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  29. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Gate/test_gate.py +0 -0
  30. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  31. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  32. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  33. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/__init__.py +0 -0
  34. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/tests/_todo_refact/_test_ex.py +0 -0
  35. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/Asset.py +0 -0
  36. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/Base.py +0 -0
  37. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/BaseTest.py +0 -0
  38. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/InAgent.py +0 -0
  39. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Abc/Order.py +0 -0
  40. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/__init__.py +0 -0
  41. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/binance_async.py +0 -0
  42. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/earn_api.py +0 -0
  43. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/etype/pm.py +0 -0
  44. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/ex.py +0 -0
  45. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/exceptions.py +0 -0
  46. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/sapi.py +0 -0
  47. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Binance/web_c2c.py +0 -0
  48. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/__init__.py +0 -0
  49. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/agent.py +0 -0
  50. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/base.py +0 -0
  51. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/etype/ad.py +0 -0
  52. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/etype/pm.py +0 -0
  53. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/ex.py +0 -0
  54. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/req.mjs +0 -0
  55. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BingX/sign.js +0 -0
  56. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitGet/__init__.py +0 -0
  57. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitGet/agent.py +0 -0
  58. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitGet/etype/ad.py +0 -0
  59. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitGet/ex.py +0 -0
  60. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitGet/req.mjs +0 -0
  61. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/BitPapa/ex.py +0 -0
  62. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Bybit/agent.py +0 -0
  63. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Bybit/etype/ad.py +0 -0
  64. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Bybit/ex.py +0 -0
  65. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Bybit/web_earn.py +0 -0
  66. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Bybit/web_p2p.py +0 -0
  67. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Gate/etype/ad.py +0 -0
  68. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Gate/premarket.py +0 -0
  69. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/agent.py +0 -0
  70. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/earn.py +0 -0
  71. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/etype/__init__.py +0 -0
  72. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/etype/ad.py +0 -0
  73. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/etype/cred.py +0 -0
  74. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/etype/pm.py +0 -0
  75. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Htx/ex.py +0 -0
  76. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/KuCoin/etype/ad.py +0 -0
  77. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/KuCoin/etype/pm.py +0 -0
  78. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/KuCoin/ex.py +0 -0
  79. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/KuCoin/web.py +0 -0
  80. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Mexc/etype/ad.py +0 -0
  81. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Mexc/etype/pm.py +0 -0
  82. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Mexc/ex.py +0 -0
  83. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Okx/etype/ad.py +0 -0
  84. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/Okx/etype/pm.py +0 -0
  85. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/asset.py +0 -0
  86. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/ex.py +0 -0
  87. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/inAgent.py +0 -0
  88. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/order.py +0 -0
  89. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/pyro.py +0 -0
  90. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/TgWallet/web.py +0 -0
  91. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/__init__.py +0 -0
  92. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/loader.py +0 -0
  93. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client/pm_unifier.py +0 -0
  94. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client.egg-info/dependency_links.txt +0 -0
  95. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client.egg-info/requires.txt +0 -0
  96. {xync_client-0.0.25.dev105 → xync_client-0.0.25.dev110}/xync_client.egg-info/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ TOKEN=your:bottoken
1
2
  POSTGRES_HOST=127.0.0.1
2
3
  POSTGRES_PORT=5433
3
4
  POSTGRES_USER=xync
@@ -7,4 +7,5 @@ __pycache__
7
7
  /*.egg-info
8
8
  /build
9
9
  .vscode
10
- /xync_client/Gate/res.js
10
+ /xync_client/Gate/res.js
11
+ /tests/res.js
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.25.dev105
3
+ Version: 0.0.25.dev110
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,11 +2,12 @@ from abc import abstractmethod
2
2
 
3
3
  from pydantic import BaseModel
4
4
  from xync_schema import models
5
- from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Agent, Cred, PmexBank
5
+ from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Agent, Cred
6
6
  from xync_schema.types import BaseAd, AdSaleIn, AdBuyIn, BaseOrder
7
7
 
8
8
  from xync_client.Abc.Ex import BaseExClient
9
9
  from xync_client.Abc.Base import BaseClient
10
+ from xync_client.Abc.types import CredExOut
10
11
 
11
12
 
12
13
  class BaseAgentClient(BaseClient):
@@ -48,24 +49,24 @@ class BaseAgentClient(BaseClient):
48
49
 
49
50
  # 25: Список реквизитов моих платежных методов
50
51
  @abstractmethod
51
- async def creds(self) -> list: ... # {fiat.exid: {fiat}}
52
+ async def creds(self) -> list: ... # {credex.exid: {cred}}
52
53
 
53
54
  # Создание реквизита на бирже
54
- async def fiat_new(self, cred: models.Cred) -> models.Cred:
55
- await models.Actor.get_or_create({"name": cred.exid}, ex=self.ex_client.ex, exid=self.agent.actor.exid)
56
- CredIn()
57
- fiat_db: Cred = (await self.fiat_pyd2db(fiat, self.agent.user_id))[0]
58
- if not (fiatex := models.CredEx.get_or_none(fiat=fiat_db, ex=self.agent.ex)):
59
- fiatex, _ = models.CredEx.update_or_create({}, fiat=fiat_db, ex=self.agent.ex)
60
- return fiatex
55
+ async def cred_new(self, cred: models.Cred) -> CredExOut: ...
56
+
57
+ # await models.Actor.get_or_create({"name": cred.exid}, ex=self.ex_client.ex, exid=self.agent.actor.exid)
58
+ # cred_db: Cred = (await self.cred_pyd2db(cred, self.agent.user_id))[0]
59
+ # if not (credex := models.CredEx.get_or_none(cred=cred_db, ex=self.agent.ex)):
60
+ # credex, _ = models.CredEx.update_or_create({}, cred=cred_db, ex=self.agent.ex)
61
+ # return credex
61
62
 
62
63
  # 27: Редактирование реквизита моего платежного метода
63
64
  @abstractmethod
64
- async def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> Cred: ...
65
+ async def cred_upd(self, cred: models.Cred, exid: int) -> CredExOut: ...
65
66
 
66
67
  # 28: Удаление реквизита моего платежного метода
67
68
  @abstractmethod
68
- async def fiat_del(self, fiat_id: int) -> bool: ...
69
+ async def cred_del(self, exid: int) -> int: ...
69
70
 
70
71
  # # # Ad
71
72
  # 29: Список моих объявлений
@@ -82,7 +83,7 @@ class BaseAgentClient(BaseClient):
82
83
  self,
83
84
  offer_id: int,
84
85
  amount: int,
85
- fiats: list[Cred] = None,
86
+ creds: list[Cred] = None,
86
87
  price: float = None,
87
88
  is_float: bool = None,
88
89
  min_fiat: int = None,
@@ -130,15 +131,11 @@ class BaseAgentClient(BaseClient):
130
131
  await ad_db.creds.add(*getattr(ad_pydin, "creds_", []))
131
132
  return ad_db
132
133
 
133
- @staticmethod
134
- async def cred_pydin2db(cred: CredIn) -> Cred:
135
- df, unq = cred.args()
136
- cred_db, _ = await Cred.update_or_create(df, **unq)
137
- if cred.banks:
138
- await cred_db.banks.add(*[await PmexBank.get(exid=b) for b in cred.banks])
139
- return cred_db
140
-
141
- @staticmethod
142
- async def fiat_cred2db(cred: Cred) -> Cred:
143
- fiat, _ = await Cred.get_or_create(cred=cred)
144
- return fiat
134
+ # @staticmethod
135
+ # async def cred_e2db(cred_in: BaseUpd, banks: list[str] = None) -> bool:
136
+ # cred_db, _ = await models.Cred.update_or_create(**cred_in.df_unq())
137
+ # credex_in = models.CredEx.validate({"exid": cred_in.id, "cred_id": cred_db.id})
138
+ # credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
139
+ # if banks: # only for SBP
140
+ # await cred_db.banks.add(*[await PmexBank.get(exid=b) for b in banks])
141
+ # return True
@@ -18,10 +18,11 @@ class BaseAuthTrait(Client):
18
18
  # noinspection PyUnresolvedReferences
19
19
  self.session.headers.update(auth_hdrs)
20
20
 
21
- async def _post(self, url: str, data: dict = None, data_key: str = None):
21
+ async def _post(self, url: str, data: dict = None, data_key: str = None, headers: dict = None):
22
22
  dt = {"json" if isinstance(data, dict) else "data": data}
23
23
  # noinspection PyUnresolvedReferences
24
- resp = await self.session.post(url, **dt, headers=self._prehook(data))
24
+ hdrs = {**self._prehook(data), **(headers or {})}
25
+ resp = await self.session.post(url, **dt, headers=hdrs)
25
26
  return await self._proc(resp, data_key, data)
26
27
 
27
28
  async def _proc(self, resp: ClientResponse, data_key: str = None, body: dict | str = None) -> dict | str:
@@ -1,13 +1,10 @@
1
1
  import logging
2
2
  from abc import abstractmethod
3
- from asyncio import sleep
4
3
 
5
4
  import msgspec
6
- from aiohttp import ClientSession
7
5
  from msgspec import Struct
8
6
  from tortoise.exceptions import MultipleObjectsReturned, IntegrityError
9
7
  from xync_schema import models
10
- from xync_schema.enums import FileType
11
8
  from xync_schema.types import CurEx, CoinEx, BaseAd, BaseAdIn
12
9
 
13
10
  from xync_client.Abc.Base import BaseClient, MapOfIdsList
@@ -69,7 +66,7 @@ class BaseExClient(BaseClient):
69
66
 
70
67
  # Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
71
68
  async def set_pmcurexs(self):
72
- pyro = PyroClient(bot)
69
+ PyroClient(bot)
73
70
  # Curs
74
71
  cur_pyds: dict[str, CurEx] = await self.curs()
75
72
  curs: dict[int | str, models.Cur] = {
@@ -157,25 +154,25 @@ class BaseExClient(BaseClient):
157
154
  await models.Pmex.update_or_create({"pm": pm_}, ex=self.ex, exid=k, name=pm.name)
158
155
  else:
159
156
  pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ": pm.typ})
160
- # logo
161
- if pm.logo and not await models.File.exists(name=pm.logo):
162
- if not pm.logo.startswith("https:"):
163
- if not pm.logo.startswith("/"):
164
- pm.logo = "/" + pm.logo
165
- pm.logo = "https://" + pm.logo
166
- async with ClientSession() as ss:
167
- resp = await ss.get(pm.logo)
168
- if resp.ok:
169
- byts = await resp.read()
170
- upf, ref = await pyro.save_file(byts, resp.content_type)
171
- await sleep(1)
172
- typ = FileType[resp.content_type.split("/")[-1]]
173
- file, _ = await models.File.update_or_create(
174
- {"ref": ref, "size": len(byts), "typ": typ}, name=pm.logo
175
- )
176
- # fil = await pyro.get_file(file.ref) # check
177
- pmin.logo_id = file.id
178
- # /logo
157
+ # # logo
158
+ # if pm.logo and not await models.File.exists(name=pm.logo):
159
+ # if not pm.logo.startswith("https:"):
160
+ # if not pm.logo.startswith("/"):
161
+ # pm.logo = "/" + pm.logo
162
+ # pm.logo = "https://" + pm.logo
163
+ # async with ClientSession() as ss:
164
+ # resp = await ss.get(pm.logo)
165
+ # if resp.ok:
166
+ # byts = await resp.read()
167
+ # upf, ref = await pyro.save_file(byts, resp.content_type)
168
+ # await sleep(1)
169
+ # typ = FileType[resp.content_type.split("/")[-1]]
170
+ # file, _ = await models.File.update_or_create(
171
+ # {"ref": ref, "size": len(byts), "typ": typ}, name=pm.logo
172
+ # )
173
+ # # fil = await pyro.get_file(file.ref) # check
174
+ # pmin.logo_id = file.id
175
+ # # /logo
179
176
  try:
180
177
  pms[k], _ = await models.Pm.update_or_create(**pmin.df_unq())
181
178
  except (MultipleObjectsReturned, IntegrityError) as e:
@@ -34,3 +34,7 @@ class PmExIn(BaseModel):
34
34
 
35
35
  class Config:
36
36
  arbitrary_types_allowed = True
37
+
38
+
39
+ class CredExOut(BaseModel):
40
+ id: int
@@ -16,6 +16,7 @@ class TradeMethod(BaseModel):
16
16
  tradeMethodName: str
17
17
  tradeMethodShortName: Optional[str] = None
18
18
 
19
+
19
20
  class Adv(BaseModel):
20
21
  abnormalStatusList: Optional[List[str]] = None
21
22
  adAdditionalKycVerifyItems: Optional[List[Any]] = None
@@ -91,6 +92,7 @@ class Adv(BaseModel):
91
92
  userTradeVolumeMax: Optional[str] = None
92
93
  userTradeVolumeMin: Optional[str] = None
93
94
 
95
+
94
96
  class Advertiser(BaseModel):
95
97
  activeTimeInSecond: int
96
98
  advConfirmTime: Optional[str] = None
@@ -115,8 +117,9 @@ class Advertiser(BaseModel):
115
117
  userType: str
116
118
  vipLevel: Optional[int] = None
117
119
 
120
+
118
121
  class Ad(BaseAd):
119
122
  adv: Adv
120
123
  advertiser: Advertiser
121
124
  privilegeDesc: Optional[str] = None
122
- privilegeType: int
125
+ privilegeType: int | None = None
@@ -15,9 +15,17 @@ from xync_client.Abc.Ex import BaseExClient
15
15
  from xync_client.loader import PG_DSN
16
16
  from xync_client.Abc.types import PmEx
17
17
  from xync_client.Gate.etype import ad
18
+ from xync_client.pm_unifier import PmUnifier
18
19
 
19
20
 
20
21
  class ExClient(BaseExClient):
22
+ class GateUnifier(PmUnifier):
23
+ pm_map = {
24
+ "SBP - Fast Bank Transfer": "SBP"
25
+ }
26
+
27
+ unifier_class = GateUnifier
28
+
21
29
  # Данные для р2р из html Gate.io
22
30
  async def c2c_data(self) -> dict:
23
31
  await sleep(1)
@@ -9,9 +9,17 @@ from xync_client.Abc.Ex import BaseExClient
9
9
  from xync_client.loader import PG_DSN
10
10
  from xync_client.Okx.etype import ad, pm
11
11
  from xync_client.Abc.types import PmEx
12
+ from xync_client.pm_unifier import PmUnifier
12
13
 
13
14
 
14
15
  class ExClient(BaseExClient):
16
+ class OkxUnifier(PmUnifier):
17
+ pm_map = {
18
+ "SBP Fast Bank Transfer": "SBP"
19
+ }
20
+
21
+ unifier_class = OkxUnifier
22
+
15
23
  async def _pms(self, cur) -> list[pm.PmE]:
16
24
  params = {
17
25
  "quoteCurrency": cur,
@@ -4,6 +4,7 @@ from enum import StrEnum
4
4
  from http.client import HTTPException
5
5
 
6
6
  from x_model import init_db
7
+
7
8
  from xync_client.TgWallet.ex import ExClient
8
9
  from xync_schema import models
9
10
 
@@ -17,13 +18,14 @@ from xync_client.TgWallet.pyd import (
17
18
  AdMakerSale,
18
19
  AdMakerNewSale,
19
20
  _AdNew,
20
- FiatEpydIn,
21
21
  _PmsTrait,
22
22
  OneAdTakerBuy,
23
23
  OrderEpyd,
24
24
  AdMakerNewBuy,
25
25
  OrderEpydIn,
26
26
  AvailableVolume,
27
+ CredEpydNew,
28
+ CredEpydUpd,
27
29
  )
28
30
  from xync_client.loader import PG_DSN
29
31
  from xync_schema.enums import AdStatus, UserStatus, OrderStatus
@@ -176,7 +178,7 @@ class AgentClient(BaseAgentClient, AuthClient):
176
178
  resp = await self._post("/p2p/public-api/v3/payment-details/get/by-user-id")
177
179
  return [CredEpyd(**cred) for cred in resp["data"]]
178
180
 
179
- async def cred_epyd2pydin(self, cred: CredEpyd): # models.Cred.in_type():
181
+ async def cred_epyd2db(self, cred: CredEpyd) -> models.CredEx:
180
182
  if not (pmex := await models.Pmex.get_or_none(exid=cred.paymentMethod.code, ex=self.ex_client.ex)):
181
183
  raise HTTPException(f"No Pmex {cred.paymentMethod.code} on ex#{self.ex_client.ex.name}", 404)
182
184
  if not (pmcur := await models.Pmcur.get_or_none(cur__ticker=cred.currency, pm_id=pmex.pm_id)):
@@ -184,90 +186,96 @@ class AgentClient(BaseAgentClient, AuthClient):
184
186
  if not (person := await models.Person.get_or_none(actors__exid=cred.userId)):
185
187
  raise HTTPException(f"No Pmcur with cur#{cred.currency} and pm#{cred.paymentMethod.code}", 404)
186
188
  dct = {"pmcur_id": pmcur.id, "name": cred.name, "person_id": person.id}
189
+ banks: list[str] | None = None
187
190
  for val in cred.attributes.values:
188
191
  if val.name == "BANKS":
189
- dct["banks"] = [b.code for b in val.value]
192
+ banks = [b.code for b in val.value]
190
193
  else:
191
194
  dct["detail"] = val.value
192
- cred_in = models.Cred.in_type().validate(dct)
193
-
194
- # todo: move to common base
195
- models.Cred.in_type().validate(
196
- {
197
- "exid": cred.id,
198
- "cred_id": cred.name,
199
- }
200
- )
201
- return cred_in
195
+ cred_in = models.Cred.validate(dct, False)
196
+ cred_db, _ = await models.Cred.update_or_create(**cred_in.df_unq())
197
+ credex_in = models.CredEx.validate({"exid": cred.id, "cred_id": cred_db.id, "ex_id": self.ex.id})
198
+ if banks: # only for SBP
199
+ await cred_db.banks.add(*[await models.PmexBank.get(exid=b) for b in banks])
200
+ credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
201
+ return credex_db
202
202
 
203
203
  # 25: Список реквизитов моих платежных методов
204
- async def set_fiats(self) -> list[models.Cred]:
204
+ async def set_fiats(self) -> list[models.CredEx]:
205
205
  creds_epyd: list[CredEpyd] = await self.creds()
206
- creds_pyd_in: list[CredIn] = [await self.cred_epyd2pydin(f) for f in creds_epyd]
207
- creds_db = [await self.cred_pydin2db(crd) for crd in creds_pyd_in]
208
- fiats_db = [await self.fiat_cred2db(cd) for cd in creds_db]
209
- return fiats_db
206
+ credexs: list[models.CredEx] = [await self.cred_epyd2db(f) for f in creds_epyd]
207
+ return credexs
208
+
209
+ async def challenge(self, name: str, payload: dict):
210
+ req = {
211
+ "deviceSerial": self.agent.auth["ds"],
212
+ "passcode": "0909",
213
+ "language": "en",
214
+ "operation": {"name": name, "payload": payload},
215
+ }
216
+ return await self._post("/v2api/challenges", req)
210
217
 
211
218
  # 26: Создание реквизита моего платежного метода
212
- async def cred_new(self, cred: CredIn) -> models.Cred:
213
- pmex = await models.Pmex.get(pm_id=cred.pm_id, ex=self.ex_client.ex).prefetch_related("pm")
214
- cur = await models.Cur[cred.cur_id]
219
+ async def cred_new(self, cred: models.Cred) -> models.CredEx:
220
+ pmcur: models.Pmcur = await cred.pmcur
221
+ exid = await models.Pmex.get(pm_id=pmcur.pm_id, ex=self.ex_client.ex).values_list("exid", flat=True)
222
+ cur = await models.Cur[pmcur.cur_id]
215
223
  vals = (
216
- [{"name": "PAYMENT_DETAILS_NUMBER", "value": cred.detail}]
217
- if cred.banks
218
- else [{"name": "PHONE", "value": cred.detail}, {"name": "BANKS", "value": cred.banks}]
224
+ [
225
+ {"name": "PHONE", "value": cred.detail.replace(" ", "")},
226
+ {"name": "BANKS", "value": [b.exid for b in banks]},
227
+ ]
228
+ if (banks := await cred.banks)
229
+ else [{"name": "PAYMENT_DETAILS_NUMBER", "value": cred.detail}]
219
230
  )
220
- cred_in = FiatEpydIn(
221
- paymentMethodCode=pmex.exid,
231
+ cred_new = CredEpydNew(
232
+ paymentMethodCode=exid,
222
233
  currencyCode=cur.ticker,
223
234
  name=cred.name,
224
- attributes={"values": vals},
225
- )
226
- add_cred = await self._post("/p2p/public-api/v3/payment-details/create", cred_in.model_dump())
227
- CredEpyd(**add_cred["data"])
228
- cred, _ = await models.Cred.update_or_create(
229
- {"name": cred.name, "detail": cred.detail}, ex=self.ex_client.ex, exid=add_cred["data"]["id"]
230
- )
231
- cred_db, _ = await models.Cred.update_or_create({"amount": cred.amount, "target": cred.target}, cred=cred)
232
-
233
- pmex = await models.Pmex.get(exid=add_cred["data"]["paymentMethod"]["code"], ex=self.ex_client.ex)
234
- cur = await models.Cur.get(ticker=add_cred["data"]["currency"])
235
- pmcur, _ = await models.Pmcur.get_or_create(cur=cur, pm_id=pmex.pm_id)
236
- attrs = {a["name"]: a["value"] for a in add_cred["data"]["attributes"]["values"]}
237
- f, _ = await models.Cred.update_or_create(
238
- {"detail": attrs["PAYMENT_DETAILS_NUMBER"]}, pmcur=pmcur, user_id=self.agent.user_id
239
- )
240
- return f
235
+ attributes={"version": "V2" if banks else "V1", "values": vals},
236
+ ).model_dump()
237
+ challenge = await self.challenge("p2p/create-payment-details", cred_new)
238
+ hdrs = {
239
+ "x-wallet-operation-token": challenge["operationToken"],
240
+ "x-wallet-device-serial": self.agent.auth["ds"],
241
+ }
242
+ add_cred = await self._post("/p2p/public-api/v3/payment-details/create", cred_new, headers=hdrs)
243
+ cred_epyd = CredEpyd(**add_cred["data"])
244
+ return await self.cred_epyd2db(cred_epyd)
241
245
 
242
246
  # 27: Редактирование реквизита моего платежного метода
243
- async def cred_upd(self, cred_id: int, detail: str, name: str = None) -> models.Cred:
244
- cred = await models.Cred.get(credexs__exid=cred_id, credexs__ex=self.ex_client.ex).prefetch_related("pmcur")
245
- pmex = await models.Pmex.get(pm_id=cred.pmcur.pm_id, ex=self.ex_client.ex)
246
- cur = await models.Cur[cred.pmcur.cur_id]
247
- edit_cred = await self._post(
248
- "/p2p/public-api/v3/payment-details/edit",
249
- {
250
- "id": cred_id,
251
- "paymentMethodCode": pmex.exid,
252
- "currencyCode": cur.ticker,
253
- "name": name,
254
- "attributes": {"version": "V1", "values": [{"name": "PAYMENT_DETAILS_NUMBER", "value": detail}]},
255
- },
256
- )
257
- pmex = await models.Pmex.get(exid=edit_cred["data"]["paymentMethod"]["code"], ex=self.ex_client.ex)
258
- cur = await models.Cur.get(ticker=edit_cred["data"]["currency"])
259
- pmcur, _ = await models.Pmcur.get_or_create(cur=cur, pm_id=pmex.pm_id)
260
- attrs = {a["name"]: a["value"] for a in edit_cred["data"]["attributes"]["values"]}
261
- f, _ = await models.Cred.update_or_create(
262
- {"detail": attrs["PAYMENT_DETAILS_NUMBER"]}, pmcur=pmcur, user_id=self.agent.user_id
247
+ async def cred_upd(self, cred: models.Cred, exid: int) -> models.CredEx:
248
+ pmcur: models.Pmcur = await cred.pmcur
249
+ pmex = await models.Pmex.get(pm_id=pmcur.pm_id, ex=self.ex_client.ex)
250
+ cur = await models.Cur[pmcur.cur_id]
251
+ vals = (
252
+ [{"name": "PHONE", "value": cred.detail}, {"name": "BANKS", "value": [b.exid for b in banks]}]
253
+ if (banks := await cred.banks)
254
+ else [{"name": "PAYMENT_DETAILS_NUMBER", "value": cred.detail}]
263
255
  )
264
- await models.Cred.update_or_create({"exid": edit_cred["data"]["id"]}, ex=self.ex_client.ex, cred=f)
265
- return f
256
+ cred_upd = CredEpydUpd(
257
+ id=exid,
258
+ paymentMethodCode=pmex.exid,
259
+ currencyCode=cur.ticker,
260
+ name=cred.name,
261
+ attributes={"version": "V2" if banks else "V1", "values": vals},
262
+ ).model_dump()
263
+ challenge = await self.challenge("p2p/edit-payment-details", cred_upd)
264
+ hdrs = {
265
+ "x-wallet-operation-token": challenge["operationToken"],
266
+ "x-wallet-device-serial": self.agent.auth["ds"],
267
+ }
268
+ edit_cred = await self._post("/p2p/public-api/v3/payment-details/edit", cred_upd, headers=hdrs)
269
+ cred_epyd = CredEpyd(**edit_cred["data"])
270
+ return await self.cred_epyd2db(cred_epyd)
266
271
 
267
272
  # 28: Удаление реквизита моего платежного метода
268
- async def cred_del(self, cred_id: int) -> bool:
269
- del_cred = await self._post("/p2p/public-api/v3/payment-details/delete", {"id": cred_id})
270
- return del_cred
273
+ async def cred_del(self, cred_id: int) -> int: # exid
274
+ res: dict = await self._post("/p2p/public-api/v3/payment-details/delete", {"id": cred_id})
275
+ if res.get("status") == "SUCCESS":
276
+ return res["data"]["id"]
277
+ else:
278
+ logging.error(res)
271
279
 
272
280
  async def ad_epyd2pydin(self, ad_: OneAdTakerMakerSale | OneAdMakerBuy | OneAdTakerBuy) -> AdBuyIn | AdSaleIn:
273
281
  ad_in: BaseAdIn = await self.ex_client.ad_common_epyd2pydin(ad_)
@@ -279,7 +287,7 @@ class AgentClient(BaseAgentClient, AuthClient):
279
287
  pmexs__ex=self.ex_client.ex, pmexs__exid__in=[p.code for p in ad_.paymentMethods]
280
288
  ),
281
289
  )
282
- creds_pin: list[CredIn] = [await self.cred_epyd2pydin(c) for c in ad_.paymentDetails]
290
+ creds_pin: list[models.Cred.in_type()] = [await self.cred_epyd2db(c) for c in ad_.paymentDetails]
283
291
  creds_ = [(await models.Cred.update_or_create((a := cp.args())[0], **a[1]))[0] for cp in creds_pin]
284
292
  return AdSaleIn(**ad_in.model_dump(), creds_=creds_)
285
293
 
@@ -308,7 +316,7 @@ class AgentClient(BaseAgentClient, AuthClient):
308
316
  ) -> AdMakerNewSale | AdMakerNewBuy:
309
317
  coinex = await models.Coinex.get(coin=coin, ex=self.ex)
310
318
  curex = await models.Curex.get(ex=self.ex, cur=cur)
311
- creds = await models.Cred.filter(ch__actor__agent__user_id=self.agent.user_id, pmcur__cur=cur).limit(5)
319
+ creds = await models.Cred.filter(ch__actor__agent__user_id=self.agent.ac.user_id, pmcur__cur=cur).limit(5)
312
320
  # todo: ordering and filtering by fiat.amount-target
313
321
  ad_ein = _AdNew(
314
322
  type="SALE" if is_sell else "PURCHASE",
@@ -437,8 +445,8 @@ async def main():
437
445
  )
438
446
  mcl: AgentClient = maker.client()
439
447
  tcl: AgentClient = taker.client()
440
- await tcl.set_fiats()
441
448
  await mcl.set_fiats()
449
+ await tcl.set_fiats()
442
450
  my_ads = await mcl.my_ads()
443
451
  my_ads_in = [await mcl.ad_epyd2pydin(ma) for ma in my_ads]
444
452
  _my_ads_db = [await mcl.ad_pydin2db(ma) for ma in my_ads_in]
@@ -1,5 +1,5 @@
1
1
  from x_client.http import Client as HttpClient
2
- from xync_schema.models import Agent
2
+ from xync_schema.models import Agent, User, Person
3
3
 
4
4
  from xync_client.Abc.AuthTrait import BaseAuthTrait
5
5
  from xync_client.Abc.Base import BaseClient
@@ -14,6 +14,8 @@ class AuthClient(BaseAuthTrait, BaseClient):
14
14
  .prefetch_related("actor__person__user")
15
15
  .first()
16
16
  )
17
+ elif not isinstance(self.agent.actor.person, Person) or not isinstance(self.agent.actor.person.user, User):
18
+ await self.agent.fetch_related("actor__person__user")
17
19
  pyro = PyroClient(self.agent)
18
20
  init_data = await pyro.get_init_data()
19
21
  tokens = HttpClient("walletbot.me")._post("/api/v1/users/auth/", init_data)
@@ -2,6 +2,8 @@ from typing import Literal
2
2
  from pydantic import BaseModel, computed_field
3
3
  from xync_schema.types import BaseAd, BaseOrder
4
4
 
5
+ from xync_client.Abc.types import CredExOut
6
+
5
7
 
6
8
  # Модели для вложенных структур
7
9
  class UserStatistics(BaseModel):
@@ -113,14 +115,18 @@ class PmEpydRoot(PmEpyd):
113
115
  banks: list[PmEpyd] | None = None
114
116
 
115
117
 
116
- class FiatEpydIn(BaseModel):
118
+ class CredEpydNew(BaseModel):
117
119
  paymentMethodCode: str
118
120
  currencyCode: str
119
121
  name: str
120
122
  attributes: Attrs | AttrsV2In
121
123
 
122
124
 
123
- class CredEpyd(BaseModel):
125
+ class CredEpydUpd(CredEpydNew):
126
+ id: int
127
+
128
+
129
+ class CredEpyd(CredExOut):
124
130
  id: int
125
131
  userId: int
126
132
  paymentMethod: PmEpydRoot
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.25.dev105
3
+ Version: 0.0.25.dev110
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
@@ -8,7 +8,6 @@ tests/TestAgent.py
8
8
  tests/TestAsset.py
9
9
  tests/TestEx.py
10
10
  tests/TestOrder.py
11
- tests/res.js
12
11
  tests/_todo_refact/__init__.py
13
12
  tests/_todo_refact/_test_ex.py
14
13
  tests/_todo_refact/Binance/test_binance.py