charli3_dendrite 1.0.0.dev0__tar.gz → 1.1.0.dev0__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 (32) hide show
  1. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/PKG-INFO +1 -1
  2. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/pyproject.toml +1 -1
  3. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +80 -65
  4. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/dbsync/models.py +28 -10
  5. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +14 -8
  6. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +13 -7
  7. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +7 -4
  8. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +7 -6
  9. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +8 -2
  10. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/LICENSE +0 -0
  11. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/README.md +0 -0
  12. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/__init__.py +0 -0
  13. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
  14. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
  15. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/blockfrost.py +0 -0
  16. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
  17. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
  18. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
  19. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
  20. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
  21. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
  22. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
  23. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
  24. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
  25. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
  26. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
  27. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
  28. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
  29. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
  30. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
  31. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
  32. {charli3_dendrite-1.0.0.dev0 → charli3_dendrite-1.1.0.dev0}/src/charli3_dendrite/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: charli3_dendrite
3
- Version: 1.0.0.dev0
3
+ Version: 1.1.0.dev0
4
4
  Summary:
5
5
  Author: Elder Millenial
6
6
  Author-email: eldermillenial@protonmail.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "charli3_dendrite"
3
- version = "1.0.0-dev0"
3
+ version = "1.1.0-dev0"
4
4
  description = ""
5
5
  authors = ["Elder Millenial <eldermillenial@protonmail.com>"]
6
6
  readme = "README.md"
@@ -3,14 +3,12 @@ import logging
3
3
  import os
4
4
  from datetime import datetime
5
5
  from threading import Lock
6
- from typing import List
7
- from typing import Optional
8
6
 
9
- import psycopg_pool
10
- from dotenv import load_dotenv
11
- from psycopg.rows import dict_row
7
+ import psycopg_pool # type: ignore
8
+ from dotenv import load_dotenv # type: ignore
9
+ from psycopg.rows import dict_row # type: ignore
12
10
  from psycopg_pool import PoolTimeout
13
- from pycardano import Address
11
+ from pycardano import Address # type: ignore
14
12
 
15
13
  from charli3_dendrite.backend.backend_base import AbstractBackend
16
14
  from charli3_dendrite.backend.dbsync.models import OrderSelector
@@ -32,7 +30,7 @@ class DbsyncBackend(AbstractBackend):
32
30
  for retrieving blockchain data.
33
31
  """
34
32
 
35
- def __init__(self):
33
+ def __init__(self) -> None:
36
34
  """Initialize the DbsyncBackend with database connection details."""
37
35
  self.lock = Lock()
38
36
  self.POOL = None
@@ -51,8 +49,11 @@ class DbsyncBackend(AbstractBackend):
51
49
  with self.lock:
52
50
  if self.POOL is None:
53
51
  conninfo = (
54
- f"host={self.DBSYNC_HOST} port={self.DBSYNC_PORT} dbname={self.DBSYNC_DB_NAME} "
55
- f"user={self.DBSYNC_USER} password={self.DBSYNC_PASS}"
52
+ f"host={self.DBSYNC_HOST} "
53
+ + f"port={self.DBSYNC_PORT} "
54
+ + f"dbname={self.DBSYNC_DB_NAME} "
55
+ + f"user={self.DBSYNC_USER} "
56
+ + f"password={self.DBSYNC_PASS}"
56
57
  )
57
58
  self.POOL = psycopg_pool.ConnectionPool(
58
59
  conninfo=conninfo,
@@ -65,6 +66,9 @@ class DbsyncBackend(AbstractBackend):
65
66
  check=psycopg_pool.ConnectionPool.check_connection,
66
67
  )
67
68
  try:
69
+ if self.POOL is None:
70
+ raise ValueError("Connection pool has not been initialized.")
71
+
68
72
  self.POOL.open()
69
73
  self.POOL.wait(timeout=60.0) # Increased from 30 to 60 seconds
70
74
  except PoolTimeout as e:
@@ -72,7 +76,9 @@ class DbsyncBackend(AbstractBackend):
72
76
  f"Database connection pool initialization timed out: {e}",
73
77
  )
74
78
  logging.error(
75
- f"Connection info: host={self.DBSYNC_HOST}, port={self.DBSYNC_PORT}, user={self.DBSYNC_USER}",
79
+ f"Connection info: host={self.DBSYNC_HOST}, "
80
+ + f"port={self.DBSYNC_PORT}, "
81
+ + f"user={self.DBSYNC_USER}",
76
82
  )
77
83
  raise
78
84
  except Exception as e:
@@ -80,7 +86,7 @@ class DbsyncBackend(AbstractBackend):
80
86
  raise
81
87
  return self.POOL
82
88
 
83
- def db_query(self, query: str, args: Optional[tuple] = None) -> List[tuple]:
89
+ def db_query(self, query: str, args: dict | None = None) -> list[dict]:
84
90
  """Execute a database query using the connection pool.
85
91
 
86
92
  Args:
@@ -90,15 +96,16 @@ class DbsyncBackend(AbstractBackend):
90
96
  Returns:
91
97
  List[tuple]: The query results.
92
98
  """
93
- with self.get_dbsync_pool().connection() as conn:
94
- with conn.cursor(row_factory=dict_row) as cursor:
95
- cursor.execute(query, args)
96
- return cursor.fetchall()
99
+ with self.get_dbsync_pool().connection() as conn, conn.cursor(
100
+ row_factory=dict_row,
101
+ ) as cursor:
102
+ cursor.execute(query, args)
103
+ return cursor.fetchall()
97
104
 
98
105
  def get_pool_utxos(
99
106
  self,
107
+ addresses: list[str],
100
108
  assets: list[str] | None = None,
101
- addresses: list[str] | None = None,
102
109
  limit: int = 1000,
103
110
  page: int = 0,
104
111
  historical: bool = True,
@@ -135,12 +142,11 @@ LEFT JOIN multi_asset ma ON ma.id = mtxo.ident"""
135
142
  LEFT JOIN tx ON txo.tx_id = tx.id
136
143
  LEFT JOIN datum ON txo.data_hash = datum.hash
137
144
  LEFT JOIN block ON tx.block_id = block.id
138
- LEFT JOIN tx_in ON tx_in.tx_out_id = txo.tx_id AND tx_in.tx_out_index = txo.index
139
145
  WHERE datum.hash IS NOT NULL"""
140
146
 
141
147
  if not historical:
142
148
  datum_selector += """
143
- AND tx_in.tx_in_id IS NULL"""
149
+ AND txo.consumed_by_tx_id IS NULL"""
144
150
 
145
151
  if assets is not None:
146
152
  datum_selector += """
@@ -166,8 +172,8 @@ OFFSET %(offset)s"""
166
172
  def get_pool_in_tx(
167
173
  self,
168
174
  tx_hash: str,
175
+ addresses: list[str],
169
176
  assets: list[str] | None = None,
170
- addresses: list[str] | None = None,
171
177
  ) -> PoolStateList:
172
178
  """Get transactions by policy or address."""
173
179
  # Use the pool selector to format the output
@@ -244,20 +250,20 @@ AND ma.policy = ANY(%(policies)b) AND ma.name = ANY(%(names)b)"""
244
250
  return PoolSelector.parse(r)
245
251
 
246
252
  def get_script_from_address(self, address: Address) -> ScriptReference:
247
- SCRIPT_SELECTOR = UTxOSelector.select()
253
+ """Get a reference script from an address."""
254
+ query = UTxOSelector.select()
248
255
 
249
- SCRIPT_SELECTOR += """
256
+ query += """
250
257
  FROM script s
251
258
  LEFT JOIN tx_out ON s.id = tx_out.reference_script_id
252
259
  LEFT JOIN tx ON tx.id = tx_out.tx_id
253
260
  LEFT JOIN datum ON tx_out.inline_datum_id = datum.id
254
261
  LEFT JOIN block on block.id = tx.block_id
255
- LEFT JOIN tx_in ON tx_in.tx_out_id = tx_out.tx_id AND tx_in.tx_out_index = tx_out.index
256
- WHERE s.hash = %(address)b AND tx_in.tx_in_id IS NULL
262
+ WHERE s.hash = %(address)b AND tx_out.consumed_by_tx_id IS NULL
257
263
  ORDER BY block.time DESC
258
264
  LIMIT 1
259
265
  """
260
- r = self.db_query(SCRIPT_SELECTOR, {"address": address.payment_part.payload})
266
+ r = self.db_query(query, {"address": address.payment_part.payload})
261
267
 
262
268
  if r[0]["assets"] is not None and r[0]["assets"][0]["lovelace"] is None:
263
269
  r[0]["assets"] = None
@@ -269,6 +275,7 @@ LIMIT 1
269
275
  address: Address,
270
276
  asset: str | None = None,
271
277
  ) -> ScriptReference | None:
278
+ """Get a reference datum from an address."""
272
279
  kwargs = {"address": address.payment_part.payload}
273
280
 
274
281
  if asset is not None:
@@ -279,9 +286,9 @@ LIMIT 1
279
286
  },
280
287
  )
281
288
 
282
- SCRIPT_SELECTOR = UTxOSelector.select()
289
+ query = UTxOSelector.select()
283
290
 
284
- SCRIPT_SELECTOR += """
291
+ query += """
285
292
  FROM tx_out
286
293
  LEFT JOIN ma_tx_out mtxo ON mtxo.tx_out_id = tx_out.id
287
294
  LEFT JOIN multi_asset ma ON ma.id = mtxo.ident
@@ -289,20 +296,19 @@ LEFT JOIN tx ON tx.id = tx_out.tx_id
289
296
  LEFT JOIN datum ON tx_out.inline_datum_id = datum.id
290
297
  LEFT JOIN block on block.id = tx.block_id
291
298
  LEFT JOIN script s ON s.id = tx_out.reference_script_id
292
- LEFT JOIN tx_in txi ON tx_out.tx_id = txi.tx_out_id AND tx_out.index = txi.tx_out_index
293
- WHERE tx_out.payment_cred = %(address)b AND txi.tx_in_id IS NULL"""
299
+ WHERE tx_out.payment_cred = %(address)b AND tx_out.consumed_by_tx_id IS NULL"""
294
300
 
295
301
  if asset is not None:
296
- SCRIPT_SELECTOR += """
302
+ query += """
297
303
  AND policy = %(policy)b AND name = %(name)b
298
304
  """
299
305
 
300
- SCRIPT_SELECTOR += """
306
+ query += """
301
307
  AND tx_out.inline_datum_id IS NOT NULL
302
308
  ORDER BY block.time DESC
303
309
  LIMIT 1
304
310
  """
305
- r = self.db_query(SCRIPT_SELECTOR, kwargs)
311
+ r = self.db_query(query, kwargs)
306
312
 
307
313
  if r[0]["assets"] is not None and r[0]["assets"][0]["lovelace"] is None:
308
314
  r[0]["assets"] = None
@@ -315,7 +321,8 @@ LIMIT 1
315
321
  after_time: datetime | int | None = None,
316
322
  limit: int = 1000,
317
323
  page: int = 0,
318
- ):
324
+ ) -> SwapTransactionList:
325
+ """Get historical orders at an order submission address."""
319
326
  if isinstance(after_time, int):
320
327
  after_time = datetime.fromtimestamp(after_time)
321
328
 
@@ -338,19 +345,20 @@ LEFT JOIN (
338
345
  block.time AS "block_time",
339
346
  block.block_no,
340
347
  tx.block_index AS "block_index",
341
- tx_in.tx_out_id,
342
- tx_in.tx_out_index,
348
+ tx_in.tx_id as "tx_out_id",
349
+ tx_in.index as "tx_out_index",
343
350
  txo.inline_datum_id,
344
351
  txo.reference_script_id,
345
352
  txo.address,
346
353
  datum.hash as "datum_hash",
347
354
  datum.bytes as "datum_bytes"
348
- FROM tx_in
349
- LEFT JOIN tx ON tx.id = tx_in.tx_in_id
355
+ FROM tx_out tx_in
356
+ LEFT JOIN tx ON tx.id = tx_in.consumed_by_tx_id
350
357
  LEFT JOIN tx_out txo ON tx.id = txo.tx_id
351
358
  LEFT JOIN block ON tx.block_id = block.id
352
359
  LEFT JOIN datum ON txo.data_hash = datum.hash
353
- ) txo_output ON txo_output.tx_out_id = txo_stake.tx_id AND txo_output.tx_out_index = txo_stake.index
360
+ ) txo_output ON txo_output.tx_out_id = txo_stake.tx_id
361
+ AND txo_output.tx_out_index = txo_stake.index
354
362
  WHERE datum.hash IS NOT NULL"""
355
363
 
356
364
  if after_time is not None:
@@ -390,12 +398,12 @@ OFFSET %(offset)s"""
390
398
  limit: int = 1000,
391
399
  page: int = 0,
392
400
  ) -> SwapTransactionList:
401
+ """Get order UTxOs by either block number or tx hash."""
393
402
  utxo_selector = """
394
403
  SELECT (
395
404
  SELECT array_agg(DISTINCT txo.address)
396
405
  FROM tx_out txo
397
- LEFT JOIN tx_in txi ON txo.tx_id = txi.tx_out_id AND txo.index = txi.tx_out_index
398
- WHERE txi.tx_in_id = txo_stake.tx_id
406
+ WHERE txo.consumed_by_tx_id = txo_stake.tx_id
399
407
  ) AS "submit_address_inputs",
400
408
  txo_stake.address as "submit_address_stake",
401
409
  ENCODE(txo_stake.tx_hash, 'hex') as "submit_tx_hash",
@@ -452,7 +460,10 @@ OFFSET %(offset)s"""
452
460
  )::jsonb,
453
461
  jsonb_build_array(json_build_object('lovelace',txo_output.value::TEXT)::jsonb)
454
462
  ) AS "assets",
455
- (txo_output.inline_datum_id IS NOT NULL OR txo_output.reference_script_id IS NOT NULL) as "plutus_v2"
463
+ (
464
+ txo_output.inline_datum_id IS NOT NULL OR
465
+ txo_output.reference_script_id IS NOT NULL
466
+ ) as "plutus_v2"
456
467
  """
457
468
 
458
469
  utxo_selector += """FROM (
@@ -472,8 +483,7 @@ OFFSET %(offset)s"""
472
483
  LEFT JOIN tx ON tx.id = txo.tx_id
473
484
  LEFT JOIN block ON tx.block_id = block.id
474
485
  LEFT JOIN datum ON txo.data_hash = datum.hash
475
- LEFT JOIN tx_in ON tx_in.tx_out_id = tx.id AND tx_in.tx_out_index = txo.index
476
- LEFT JOIN tx tx_in_ref ON tx_in.tx_in_id = tx_in_ref.id
486
+ LEFT JOIN tx tx_in_ref ON txo.consumed_by_tx_id = tx_in_ref.id
477
487
  WHERE txo.payment_cred = ANY(%(addresses)b) AND txo.data_hash IS NOT NULL"""
478
488
 
479
489
  if out_tx_hash is not None:
@@ -501,19 +511,20 @@ OFFSET %(offset)s"""
501
511
  block.time AS "block_time",
502
512
  block.block_no,
503
513
  tx.block_index AS "block_index",
504
- tx_in.tx_out_id,
505
- tx_in.tx_out_index,
514
+ tx_in.tx_id as "tx_out_id",
515
+ tx_in.index as "tx_out_index",
506
516
  txo.inline_datum_id,
507
517
  txo.reference_script_id,
508
518
  txo.address,
509
519
  datum.hash as "datum_hash",
510
520
  datum.bytes as "datum_bytes"
511
- FROM tx_in
512
- LEFT JOIN tx ON tx.id = tx_in.tx_in_id
521
+ FROM tx_out tx_in
522
+ LEFT JOIN tx ON tx.id = tx_in.consumed_by_tx_id
513
523
  LEFT JOIN tx_out txo ON tx.id = txo.tx_id
514
524
  LEFT JOIN block ON tx.block_id = block.id
515
525
  LEFT JOIN datum ON txo.data_hash = datum.hash
516
- ) txo_output ON txo_output.tx_out_id = txo_stake.tx_id AND txo_output.tx_out_index = txo_stake.index
526
+ ) txo_output ON txo_output.tx_out_id = txo_stake.tx_id
527
+ AND txo_output.tx_out_index = txo_stake.index
517
528
  WHERE txo_stake.datum_hash IS NOT NULL
518
529
  ORDER BY txo_stake.tx_id ASC
519
530
  LIMIT %(limit)s
@@ -551,7 +562,8 @@ OFFSET %(offset)s"""
551
562
  after_time: datetime | int | None = None,
552
563
  limit: int = 1000,
553
564
  page: int = 0,
554
- ):
565
+ ) -> SwapTransactionList:
566
+ """Get order cancel UTxOs."""
555
567
  if isinstance(after_time, int):
556
568
  after_time = datetime.fromtimestamp(after_time)
557
569
 
@@ -559,8 +571,7 @@ OFFSET %(offset)s"""
559
571
  SELECT (
560
572
  SELECT array_agg(DISTINCT tx_out.address)
561
573
  FROM tx_out
562
- LEFT JOIN tx_in txi ON tx_out.tx_id = txi.tx_out_id AND tx_out.index = txi.tx_out_index
563
- WHERE txi.tx_in_id = txo.tx_id
574
+ WHERE tx_out.consumed_by_tx_id = txo.tx_id
564
575
  ) AS "submit_address_inputs",
565
576
  txo.address as "submit_address_stake",
566
577
  ENCODE(tx.hash, 'hex') as "submit_tx_hash",
@@ -617,7 +628,8 @@ COALESCE(
617
628
  )::jsonb,
618
629
  jsonb_build_array(json_build_object('lovelace',txo_output.value::TEXT)::jsonb)
619
630
  ) AS "assets",
620
- (txo_output.inline_datum_id IS NOT NULL OR txo_output.reference_script_id IS NOT NULL) as "plutus_v2"
631
+ (txo_output.inline_datum_id IS NOT NULL OR txo_output.reference_script_id IS NOT NULL)
632
+ AS "plutus_v2"
621
633
  """
622
634
 
623
635
  utxo_selector += """FROM (
@@ -629,15 +641,15 @@ COALESCE(
629
641
  block.time AS "block_time",
630
642
  block.block_no,
631
643
  tx.block_index AS "block_index",
632
- tx_in.tx_out_id,
633
- tx_in.tx_out_index,
644
+ tx_in.tx_id as "tx_out_id",
645
+ tx_in.index as "tx_index",
634
646
  txo.inline_datum_id,
635
647
  txo.reference_script_id,
636
648
  txo.address,
637
649
  datum.hash as "datum_hash",
638
650
  datum.bytes as "datum_bytes"
639
- FROM tx_in
640
- LEFT JOIN tx ON tx.id = tx_in.tx_in_id
651
+ FROM tx_out tx_in
652
+ LEFT JOIN tx ON tx.id = tx_in.tx_id
641
653
  LEFT JOIN tx_out txo ON tx.id = txo.tx_id
642
654
  LEFT JOIN block ON tx.block_id = block.id
643
655
  LEFT JOIN datum ON txo.data_hash = datum.hash"""
@@ -653,8 +665,8 @@ COALESCE(
653
665
 
654
666
  utxo_selector += """
655
667
  GROUP BY tx.hash, txo.value, txo.id, block.hash, block.time, block.block_no,
656
- tx.block_index, tx_in.tx_out_id, tx_in.tx_out_index, txo.inline_datum_id, txo.reference_script_id,
657
- txo.address, datum.hash, datum.bytes
668
+ tx.block_index, tx_in.tx_id, tx_in.index, txo.inline_datum_id,
669
+ txo.reference_script_id, txo.address, datum.hash, datum.bytes
658
670
  HAVING COUNT(DISTINCT txo.address) = 1
659
671
  ) txo_output
660
672
  LEFT JOIN tx_out txo ON txo.tx_id = txo_output.tx_out_id
@@ -664,8 +676,7 @@ LEFT JOIN tx_out txo ON txo.tx_id = txo_output.tx_out_id
664
676
  LEFT JOIN tx ON tx.id = txo.tx_id
665
677
  LEFT JOIN block ON tx.block_id = block.id
666
678
  LEFT JOIN datum ON txo.data_hash = datum.hash
667
- LEFT JOIN tx_in ON tx_in.tx_out_id = tx.id AND tx_in.tx_out_index = txo.index
668
- LEFT JOIN tx tx_in_ref ON tx_in.tx_in_id = tx_in_ref.id
679
+ LEFT JOIN tx tx_in_ref ON txo.tx_id = tx_in_ref.id
669
680
  WHERE txo.id IS NOT NULL
670
681
  ORDER BY txo.tx_id ASC
671
682
  LIMIT %(limit)s
@@ -696,32 +707,36 @@ OFFSET %(offset)s"""
696
707
  block_time: datetime | None = None,
697
708
  ) -> str | None:
698
709
  """Get the target address for the given asset."""
699
- SELECTOR = """
710
+ query = """
700
711
  SELECT DISTINCT txo.address, block.time
701
712
  FROM (
702
713
  SELECT tx.id, tx.block_id
703
714
  FROM tx_out txo
704
715
  LEFT JOIN tx ON tx.id = txo.tx_id
705
- WHERE txo.payment_cred = DECODE('55ff0e63efa0694e8065122c552e80c7b51768b7f20917af25752a7c', 'hex')
716
+ WHERE txo.payment_cred = DECODE(
717
+ '55ff0e63efa0694e8065122c552e80c7b51768b7f20917af25752a7c', 'hex'
718
+ )
706
719
  ) as tx
707
720
  LEFT JOIN block ON block.id = tx.block_id
708
721
  LEFT JOIN tx_out txo ON tx.id = txo.tx_id
709
722
  LEFT JOIN ma_tx_out mtxo on txo.id = mtxo.tx_out_id
710
723
  LEFT JOIN multi_asset ma ON ma.id = mtxo.ident
711
724
  WHERE ma.policy = %(policy)b AND ma.name = %(name)b
712
- AND txo.payment_cred != DECODE('55ff0e63efa0694e8065122c552e80c7b51768b7f20917af25752a7c', 'hex')"""
725
+ AND txo.payment_cred != DECODE(
726
+ '55ff0e63efa0694e8065122c552e80c7b51768b7f20917af25752a7c', 'hex'
727
+ )"""
713
728
 
714
729
  if block_time is not None:
715
- SELECTOR += """
730
+ query += """
716
731
  AND block.time <= %(block_time)s"""
717
732
 
718
- SELECTOR += """
733
+ query += """
719
734
  ORDER BY block.time DESC"""
720
735
 
721
736
  policy = bytes.fromhex(assets.unit()[:56])
722
737
  name = bytes.fromhex(assets.unit()[56:])
723
738
  r = self.db_query(
724
- SELECTOR,
739
+ query,
725
740
  {
726
741
  "policy": policy,
727
742
  "name": name,
@@ -1,5 +1,6 @@
1
+ """Methods for abstracting SQL selections and parsing results."""
1
2
  from abc import ABC
2
- from abc import abstractclassmethod
3
+ from abc import abstractmethod
3
4
 
4
5
  from charli3_dendrite.dataclasses.models import DendriteBaseModel
5
6
  from charli3_dendrite.dataclasses.models import PoolStateList
@@ -8,20 +9,27 @@ from charli3_dendrite.dataclasses.models import SwapTransactionList
8
9
 
9
10
 
10
11
  class AbstractDBSyncStructure(ABC):
11
- @abstractclassmethod
12
+ """Abstract class with required methods for SQL queries."""
13
+
14
+ @classmethod
15
+ @abstractmethod
12
16
  def select(cls) -> str:
13
17
  """The selectin part of a DBSync query."""
14
18
  raise NotImplementedError
15
19
 
16
- @abstractclassmethod
17
- def parse(cls, data: dict) -> DendriteBaseModel:
20
+ @classmethod
21
+ @abstractmethod
22
+ def parse(cls, data: dict | list[dict]) -> DendriteBaseModel:
18
23
  """Parse data returned from a dbsync query."""
19
24
  raise NotImplementedError
20
25
 
21
26
 
22
27
  class PoolSelector(AbstractDBSyncStructure):
28
+ """Query selections and parsing classes for AMM pools."""
29
+
23
30
  @classmethod
24
31
  def select(cls) -> str:
32
+ """Select SQL query for swap pools."""
25
33
  return """
26
34
  SELECT txo.address,
27
35
  ENCODE(tx.hash, 'hex') as "tx_hash",
@@ -52,13 +60,17 @@ COALESCE (
52
60
  """
53
61
 
54
62
  @classmethod
55
- def parse(cls, data: dict) -> PoolStateList:
63
+ def parse(cls, data: dict | list[dict]) -> PoolStateList:
64
+ """Parse pools from a query."""
56
65
  return PoolStateList.model_validate(data)
57
66
 
58
67
 
59
68
  class UTxOSelector(AbstractDBSyncStructure):
69
+ """Selection queries and parsing classes for reference scripts and datums."""
70
+
60
71
  @classmethod
61
72
  def select(cls) -> str:
73
+ """Selection SQL query for reference scripts and datums."""
62
74
  return """
63
75
  SELECT ENCODE(tx.hash, 'hex') as "tx_hash",
64
76
  tx_out.index as "tx_index",
@@ -82,19 +94,22 @@ COALESCE (
82
94
  ENCODE(s.bytes, 'hex') as "script" """
83
95
 
84
96
  @classmethod
85
- def parse(cls, data: dict) -> ScriptReference:
97
+ def parse(cls, data: dict | list[dict]) -> ScriptReference:
98
+ """Parsing class for UTxOs containing a reference script or datum."""
86
99
  return ScriptReference.model_validate(data)
87
100
 
88
101
 
89
102
  class OrderSelector(AbstractDBSyncStructure):
103
+ """SQL query for orders and the associated pydantic parsing class."""
104
+
90
105
  @classmethod
91
106
  def select(cls) -> str:
107
+ """The SQL select statement for orders."""
92
108
  return """
93
109
  SELECT (
94
110
  SELECT array_agg(DISTINCT txo.address)
95
111
  FROM tx_out txo
96
- LEFT JOIN tx_in txi ON txo.tx_id = txi.tx_out_id AND txo.index = txi.tx_out_index
97
- WHERE txi.tx_in_id = txo_stake.tx_id
112
+ WHERE txo.consumed_by_tx_id = txo_stake.tx_id
98
113
  ) AS "submit_address_inputs",
99
114
  txo_stake.address as "submit_address_stake",
100
115
  ENCODE(tx.hash, 'hex') as "submit_tx_hash",
@@ -151,9 +166,12 @@ COALESCE(
151
166
  )::jsonb,
152
167
  jsonb_build_array(json_build_object('lovelace',txo_output.value::TEXT)::jsonb)
153
168
  ) AS "assets",
154
- (txo_output.inline_datum_id IS NOT NULL OR txo_output.reference_script_id IS NOT NULL) as "plutus_v2"
169
+ (
170
+ txo_output.inline_datum_id IS NOT NULL OR txo_output.reference_script_id IS NOT NULL
171
+ ) as "plutus_v2"
155
172
  """
156
173
 
157
174
  @classmethod
158
- def parse(cls, data: dict) -> SwapTransactionList:
175
+ def parse(cls, data: dict | list[dict]) -> SwapTransactionList:
176
+ """Parse and validate orders."""
159
177
  return SwapTransactionList.model_validate(data)
@@ -252,17 +252,20 @@ class MinswapOrderDatum(OrderDatum):
252
252
  elif isinstance(self.step, ZapIn):
253
253
  return Assets({self.step.desired_coin.assets.unit(): self.step.minimum_lp})
254
254
 
255
- def order_type(self) -> OrderType:
255
+ def order_type(self) -> OrderType | None:
256
256
  """The order type."""
257
+ order_type = None
257
258
  if isinstance(self.step, (SwapExactIn, SwapExactOut, StableSwapExactIn)):
258
- return OrderType.swap
259
+ order_type = OrderType.swap
259
260
  elif isinstance(self.step, (Deposit, StableSwapDeposit, ZapIn)):
260
- return OrderType.deposit
261
+ order_type = OrderType.deposit
261
262
  elif isinstance(
262
263
  self.step,
263
264
  (Withdraw, StableSwapWithdraw, StableSwapWithdrawOneCoin),
264
265
  ):
265
- return OrderType.withdraw
266
+ order_type = OrderType.withdraw
267
+
268
+ return order_type
266
269
 
267
270
 
268
271
  @dataclass
@@ -598,8 +601,9 @@ class MinswapV2OrderDatum(OrderDatum):
598
601
  else:
599
602
  return Assets({})
600
603
 
601
- def order_type(self) -> OrderType:
604
+ def order_type(self) -> OrderType | None:
602
605
  """The order type."""
606
+ order_type = None
603
607
  if isinstance(
604
608
  self.step,
605
609
  (
@@ -611,11 +615,13 @@ class MinswapV2OrderDatum(OrderDatum):
611
615
  SwapMultiRoutingV2,
612
616
  ),
613
617
  ):
614
- return OrderType.swap
618
+ order_type = OrderType.swap
615
619
  elif isinstance(self.step, (DepositV2, DonationV2)):
616
- return OrderType.deposit
620
+ order_type = OrderType.deposit
617
621
  elif isinstance(self.step, (WithdrawV2, ZapOutV2, WithdrawImbalanceV2)):
618
- return OrderType.withdraw
622
+ order_type = OrderType.withdraw
623
+
624
+ return order_type
619
625
 
620
626
 
621
627
  @dataclass
@@ -218,14 +218,17 @@ class SundaeOrderDatum(OrderDatum):
218
218
  else:
219
219
  return Assets({})
220
220
 
221
- def order_type(self) -> OrderType:
221
+ def order_type(self) -> OrderType | None:
222
222
  """Get the order type."""
223
+ order_type = None
223
224
  if isinstance(self.swap, SwapConfig):
224
- return OrderType.swap
225
+ order_type = OrderType.swap
225
226
  elif isinstance(self.swap, DepositConfig):
226
- return OrderType.deposit
227
+ order_type = OrderType.deposit
227
228
  elif isinstance(self.swap, WithdrawConfig):
228
- return OrderType.withdraw
229
+ order_type = OrderType.withdraw
230
+
231
+ return order_type
229
232
 
230
233
 
231
234
  @dataclass
@@ -361,12 +364,15 @@ class SundaeV3OrderDatum(OrderDatum):
361
364
  return Assets({})
362
365
 
363
366
  def order_type(self) -> OrderType:
367
+ order_type = None
364
368
  if isinstance(self.swap, SwapV3Config):
365
- return OrderType.swap
369
+ order_type = OrderType.swap
366
370
  elif isinstance(self.swap, DepositV3Config):
367
- return OrderType.deposit
371
+ order_type = OrderType.deposit
368
372
  elif isinstance(self.swap, WithdrawV3Config):
369
- return OrderType.withdraw
373
+ order_type = OrderType.withdraw
374
+
375
+ return order_type
370
376
 
371
377
 
372
378
  @dataclass
@@ -167,13 +167,16 @@ class VyFiOrderDatum(OrderDatum):
167
167
  },
168
168
  )
169
169
 
170
- def order_type(self) -> OrderType:
170
+ def order_type(self) -> OrderType | None:
171
+ order_type = None
171
172
  if isinstance(self.order, (BtoA, AtoB, ZapInA, ZapInB)):
172
- return OrderType.swap
173
+ order_type = OrderType.swap
173
174
  elif isinstance(self.order, Deposit):
174
- return OrderType.deposit
175
+ order_type = OrderType.deposit
175
176
  elif isinstance(self.order, Withdraw):
176
- return OrderType.withdraw
177
+ order_type = OrderType.withdraw
178
+
179
+ return order_type
177
180
 
178
181
 
179
182
  class VyFiTokenDefinition(BaseModel):
@@ -228,15 +228,16 @@ class WingRidersOrderDatum(OrderDatum):
228
228
  elif isinstance(self.detail, WingRidersMaybeFeeClaimDetail):
229
229
  return Assets({})
230
230
 
231
- def order_type(self) -> OrderType:
231
+ def order_type(self) -> OrderType | None:
232
+ order_type = None
232
233
  if isinstance(self.detail, WingRidersOrderDetail):
233
- return OrderType.swap
234
+ order_type = OrderType.swap
234
235
  elif isinstance(self.detail, WingRidersDepositDetail):
235
- return OrderType.deposit
236
+ order_type = OrderType.deposit
236
237
  elif isinstance(self.detail, WingRidersWithdrawDetail):
237
- return OrderType.withdraw
238
- if isinstance(self.detail, WingRidersMaybeFeeClaimDetail):
239
- return OrderType.withdraw
238
+ order_type = OrderType.withdraw
239
+
240
+ return order_type
240
241
 
241
242
 
242
243
  @dataclass
@@ -120,8 +120,14 @@ class GeniusYieldOrder(OrderDatum):
120
120
  asset = self.offered_asset.assets
121
121
  return asset
122
122
 
123
- def order_type(self) -> OrderType:
124
- return OrderType.swap
123
+ def order_type(self) -> OrderType | None:
124
+ order_type = None
125
+ if self.offered_original_amount == self.offered_amount:
126
+ order_type = OrderType.deposit
127
+ else:
128
+ order_type = OrderType.swap
129
+
130
+ return order_type
125
131
 
126
132
 
127
133
  @dataclass