charli3_dendrite 1.4.8.dev0__tar.gz → 1.4.9.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 (41) hide show
  1. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/PKG-INFO +1 -1
  2. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/pyproject.toml +2 -2
  3. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/dano.py +90 -22
  4. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/splash.py +7 -0
  5. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/LICENSE +0 -0
  6. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/README.md +0 -0
  7. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/__init__.py +0 -0
  8. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
  9. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
  10. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
  11. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
  12. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
  13. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
  14. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
  15. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
  16. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
  17. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
  18. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
  19. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
  20. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
  21. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
  22. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
  23. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
  24. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
  25. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
  26. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
  27. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
  28. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
  29. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
  30. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
  31. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
  32. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
  33. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
  34. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
  35. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
  36. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
  37. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
  38. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
  39. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
  40. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +0 -0
  41. {charli3_dendrite-1.4.8.dev0 → charli3_dendrite-1.4.9.dev0}/src/charli3_dendrite/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: charli3_dendrite
3
- Version: 1.4.8.dev0
3
+ Version: 1.4.9.dev0
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: Elder Millenial
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "charli3_dendrite"
3
- version = "1.4.8-dev0"
3
+ version = "1.4.9-dev0"
4
4
  description = ""
5
5
  authors = ["Elder Millenial <eldermillenial@protonmail.com>"]
6
6
  readme = "README.md"
@@ -49,7 +49,7 @@ module = ["pycardano", "pycardano.*", "dotenv", "nox"]
49
49
  ignore_missing_imports = true
50
50
 
51
51
  [tool.bumpversion]
52
- current_version = "1.4.8-dev0"
52
+ current_version = "1.4.9-dev0"
53
53
  parse = """(?x)
54
54
  (?P<major>\\d+)\\.
55
55
  (?P<minor>\\d+)\\.
@@ -548,27 +548,57 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
548
548
  """Return tokenY's asset unit (the canonical b-side)."""
549
549
  return self._datum.unit_y
550
550
 
551
+ @property
552
+ def _x_carve(self) -> int:
553
+ """Carve netted off the gross tokenX balance to get the active reserve.
554
+
555
+ The platform fee, plus min-UTxO + swap-fee on the ADA (tokenX) side.
556
+ """
557
+ d = self._datum
558
+ excluded_ada = ADA_MIN_UTXO + d.total_swap_fee if d.unit_x == "lovelace" else 0
559
+ return d.platform_fee_x + excluded_ada
560
+
551
561
  @property
552
562
  def raw_x(self) -> int:
553
- """Return the raw tokenX balance held in the pool UTxO."""
554
- return self.assets[self._datum.unit_x]
563
+ """Return the raw (gross) tokenX balance held in the pool UTxO.
564
+
565
+ ``assets`` stores the *active* (carve-netted) reserves — see
566
+ ``post_init``/``skip_init`` — so the gross balance is reconstructed by
567
+ adding the carve back. The tx-build path needs gross (platform fees +
568
+ min-ADA stay in the pool output).
569
+ """
570
+ return self.assets[self._datum.unit_x] + self._x_carve
555
571
 
556
572
  @property
557
573
  def raw_y(self) -> int:
558
- """Return the raw tokenY balance held in the pool UTxO."""
559
- return self.assets[self._datum.unit_y]
574
+ """Return the raw (gross) tokenY balance held in the pool UTxO."""
575
+ return self.assets[self._datum.unit_y] + self._datum.platform_fee_y
560
576
 
561
577
  @property
562
578
  def reserve_a(self) -> int:
563
- """Active reserve of tokenX, net of platform fees and ADA carve-out."""
564
- d = self._datum
565
- excluded_ada = ADA_MIN_UTXO + d.total_swap_fee if d.unit_x == "lovelace" else 0
566
- return self.raw_x - d.platform_fee_x - excluded_ada
579
+ """Active reserve of tokenX (read directly ``assets`` is carve-netted).
580
+
581
+ See ``post_init`` / ``skip_init`` for the round-trip-safe representation.
582
+ """
583
+ return self.assets[self._datum.unit_x]
567
584
 
568
585
  @property
569
586
  def reserve_b(self) -> int:
570
- """Active reserve of tokenY, net of platform fees."""
571
- return self.raw_y - self._datum.platform_fee_y
587
+ """Active reserve of tokenY (``assets`` is carve-netted at parse time)."""
588
+ return self.assets[self._datum.unit_y]
589
+
590
+ def _gross_assets(self) -> Assets:
591
+ """The raw on-chain UTxO value bag (carve added back to the reserves).
592
+
593
+ ``assets`` stores the carve-netted reserves; the tx-build path needs the
594
+ true gross bag so the new pool output preserves the platform fees +
595
+ min-ADA that stay in the pool.
596
+ """
597
+ d = self._datum
598
+ g = Assets(root=dict(self.assets.root))
599
+ g.root[d.unit_x] = g.root.get(d.unit_x, 0) + self._x_carve
600
+ g.root[d.unit_y] = g.root.get(d.unit_y, 0) + d.platform_fee_y
601
+ return g
572
602
 
573
603
  # --- math (single-band CLMM curve inherited from the base) -------------
574
604
  # ``virtual_reserves()`` + ``get_amount_out()``/``get_amount_in()`` + the
@@ -596,15 +626,10 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
596
626
  withdrawn into the pool as part of the same tx (see docs/05-04-swap.md
597
627
  "If token_x is ADA AND curEpoch > last_withdraw_epoch").
598
628
  """
599
- d = self._datum
600
- x_raw = self.raw_x + staking_reward
601
- y_raw = self.raw_y
602
- if d.unit_x == "lovelace":
603
- pool_in_lp_x = x_raw - d.platform_fee_x - d.total_swap_fee - ADA_MIN_UTXO
604
- else:
605
- pool_in_lp_x = x_raw - d.platform_fee_x
606
- pool_in_lp_y = y_raw - d.platform_fee_y
607
- return pool_in_lp_x, pool_in_lp_y
629
+ # The active liquidity IS the carve-netted reserve (reserve_a/reserve_b),
630
+ # plus any in-tx ADA staking_reward withdrawn into the pool on the X side.
631
+ # Equivalent to the old gross-minus-carve form, expressed in net terms.
632
+ return self.reserve_a + staking_reward, self.reserve_b
608
633
 
609
634
  def compute_pool_change(
610
635
  self,
@@ -713,7 +738,9 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
713
738
  staking_reward: int = 0,
714
739
  ) -> Assets:
715
740
  d = self._datum
716
- new = Assets(root=dict(self.assets.root))
741
+ # Build the new output from the GROSS bag — the on-chain UTxO must keep
742
+ # the platform fees + min-ADA that ``assets`` (net) no longer carries.
743
+ new = self._gross_assets()
717
744
  if self.dex_nft is not None:
718
745
  new.root[self.dex_nft.unit()] = 1
719
746
  new.root[d.unit_x] = new.root.get(d.unit_x, 0) + pool_change_x
@@ -793,7 +820,8 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
793
820
  # Rebuild the pool input UTxO. Address is fetched from the pool tx so we
794
821
  # pick up the correct form (addr1x… or addr1w…); the addr1x delegation
795
822
  # part also carries the per-pool staking credential used below.
796
- pool_in_assets = Assets(root=dict(self.assets.root))
823
+ # The spent pool input value is the GROSS on-chain bag (assets is net).
824
+ pool_in_assets = self._gross_assets()
797
825
  if self.dex_nft is not None:
798
826
  pool_in_assets.root[self.dex_nft.unit()] = 1
799
827
 
@@ -955,13 +983,53 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
955
983
 
956
984
  # --- post-init ---------------------------------------------------------
957
985
 
986
+ @classmethod
987
+ def skip_init(cls, values: dict[str, Any]) -> bool:
988
+ """Skip parsing when re-ingesting an already-parsed (dumped) pool.
989
+
990
+ A parsed Dano pool exposes its ``dex_nft`` as a separate field and stores
991
+ the *active* (carve-netted) reserves in ``assets`` (see ``post_init``). On
992
+ re-ingest the carve must NOT be applied again, so the presence of
993
+ ``dex_nft`` in the construction values is the "already parsed" signal:
994
+ surface the derived ``fee`` and skip ``post_init`` (which would re-net).
995
+ A fresh chain parse carries the dex NFT *inside* the assets bag (extracted
996
+ later), not as a ``dex_nft`` key, so it takes the full parse path. Mirrors
997
+ VyFi / WingRiders V2; makes the serialize→reingest round-trip idempotent
998
+ for both the dendrite model_dump form and steelswap's net silver.
999
+ """
1000
+ if "dex_nft" in values:
1001
+ if not isinstance(values["assets"], Assets):
1002
+ values["assets"] = Assets.model_validate(values["assets"])
1003
+ datum = cls.pool_datum_class().from_cbor(values["datum_cbor"])
1004
+ values["fee"] = datum.lp_fee_rate
1005
+ return True
1006
+ return False
1007
+
958
1008
  @classmethod
959
1009
  def post_init(cls, values: dict[str, Any]) -> dict[str, Any]:
960
- """Post-initialization processing: surface lp_fee_rate on the model."""
1010
+ """Post-initialization: surface ``lp_fee_rate`` and carve-net the reserves.
1011
+
1012
+ Subtracts the platform fee (+ ADA min-utxo + swap-fee on the ADA side)
1013
+ from ``assets`` so the stored balances are the *active* reserves
1014
+ (``reserve_a``/``reserve_b`` read them directly). This is the derive-once
1015
+ step that ``skip_init`` skips on re-ingest, so the round-trip is
1016
+ idempotent; ``raw_x``/``_gross_assets`` add the carve back for tx-build.
1017
+ """
961
1018
  values = super().post_init(values)
962
1019
  # Surface lp_fee_rate on the model so `volume_fee` works out of the box.
963
1020
  datum = cls.pool_datum_class().from_cbor(values["datum_cbor"])
964
1021
  values["fee"] = datum.lp_fee_rate
1022
+ # Carve-net the reserves in place (skipped on re-ingest via skip_init).
1023
+ assets = values["assets"]
1024
+ excluded_ada = (
1025
+ ADA_MIN_UTXO + datum.total_swap_fee if datum.unit_x == "lovelace" else 0
1026
+ )
1027
+ assets.root[datum.unit_x] = (
1028
+ assets.root.get(datum.unit_x, 0) - datum.platform_fee_x - excluded_ada
1029
+ )
1030
+ assets.root[datum.unit_y] = (
1031
+ assets.root.get(datum.unit_y, 0) - datum.platform_fee_y
1032
+ )
965
1033
  return values
966
1034
 
967
1035
  @property
@@ -269,6 +269,13 @@ class CPPoolRedeemer(PlutusData):
269
269
  class SplashBaseState(AbstractPairState):
270
270
  """Base state class for Splash DEX pools."""
271
271
 
272
+ # Off-chain executor fee a Splash ORDER must pay to be picked up:
273
+ # SplashOrderDatum.fee (2 ADA) + cost_per_ex_step (1 ADA) = 3 ADA. This is the
274
+ # order/executor fee (used for fillability), DISTINCT from _batcher/_deposit
275
+ # (=0) which the direct pool-spend swap path uses. Do NOT fold this into
276
+ # _batcher — downstream consumers read _batcher as the direct-swap cost.
277
+ _executor_fee = Assets(lovelace=3_000_000)
278
+
272
279
  @classmethod
273
280
  def dex(cls) -> str:
274
281
  """Return the name of the DEX."""