charli3_dendrite 1.4.12.dev0__tar.gz → 1.4.13.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 (42) hide show
  1. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/PKG-INFO +1 -1
  2. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/pyproject.toml +2 -2
  3. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/__init__.py +1 -0
  4. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +78 -10
  5. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +126 -48
  6. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/LICENSE +0 -0
  7. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/README.md +0 -0
  8. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
  9. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
  10. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
  11. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
  12. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
  13. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
  14. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
  15. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
  16. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
  17. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
  18. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
  19. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
  20. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
  21. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
  22. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
  23. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
  24. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
  25. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/dano.py +0 -0
  26. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
  27. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
  28. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
  29. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
  30. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
  31. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
  32. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
  33. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
  34. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
  35. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
  36. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
  37. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
  38. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
  39. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
  40. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
  41. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
  42. {charli3_dendrite-1.4.12.dev0 → charli3_dendrite-1.4.13.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.12.dev0
3
+ Version: 1.4.13.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.12-dev0"
3
+ version = "1.4.13-dev0"
4
4
  description = ""
5
5
  authors = ["Elder Millenial <eldermillenial@protonmail.com>"]
6
6
  readme = "README.md"
@@ -50,7 +50,7 @@ module = ["pycardano", "pycardano.*", "dotenv", "nox", "uplc", "uplc.*"]
50
50
  ignore_missing_imports = true
51
51
 
52
52
  [tool.bumpversion]
53
- current_version = "1.4.12-dev0"
53
+ current_version = "1.4.13-dev0"
54
54
  parse = """(?x)
55
55
  (?P<major>\\d+)\\.
56
56
  (?P<minor>\\d+)\\.
@@ -31,6 +31,7 @@ from charli3_dendrite.dexs.ob.djed import DjedOrderBook
31
31
  from charli3_dendrite.dexs.ob.djed import ShenOrderBook
32
32
  from charli3_dendrite.dexs.ob.geniusyield import GeniusYieldOrderBook
33
33
  from charli3_dendrite.dexs.ob.geniusyield import GeniusYieldOrderState
34
+ from charli3_dendrite.dexs.ob.saturnswap import SaturnSwapLegacyOrderState
34
35
  from charli3_dendrite.dexs.ob.saturnswap import SaturnSwapOrderBook
35
36
  from charli3_dendrite.dexs.ob.saturnswap import SaturnSwapOrderState
36
37
  from charli3_dendrite.utility import Assets
@@ -27,6 +27,7 @@ from pycardano import TransactionId
27
27
  from pycardano import TransactionInput
28
28
  from pycardano import TransactionOutput
29
29
  from pycardano import UTxO
30
+ from pycardano import plutus_script_hash
30
31
  from pycardano.utils import min_lovelace
31
32
 
32
33
  from charli3_dendrite.dataclasses.datums import OrderDatum
@@ -44,12 +45,14 @@ BEACON_POLICY_ID = "c4d7d117d9ebcde6db28db40837ff2b1401e9eaaa6eecea9e070e209"
44
45
  # v2 one-way swap spending validator hash.
45
46
  SWAP_VALIDATOR_HASH = "1d6cff26bcab91d2061aad0bd259cbb7d76d25ced2eeaed5926a42ad"
46
47
 
47
- # Compiled Plutus V2 scripts, inlined verbatim (no on-chain reference script, so
48
- # they are attached to the witness set directly). The swap validator is
48
+ # Compiled Plutus V2 scripts, inlined verbatim. The swap validator is
49
49
  # un-parameterized; the beacon minting policy is parameterized by ``dapp_hash``
50
50
  # (= the swap validator hash), applied here via the aiken blueprint, so
51
51
  # ``PlutusV2Script(bytes.fromhex(...))`` hashes to the constants above (swap
52
- # validator -> SWAP_VALIDATOR_HASH, beacon policy -> BEACON_POLICY_ID).
52
+ # validator -> SWAP_VALIDATOR_HASH, beacon policy -> BEACON_POLICY_ID). These are
53
+ # attached to the witness set by default; a builder caller may instead supply an
54
+ # on-chain reference-script UTxO per script (whose output carries the matching
55
+ # script) to keep the script off the witness set -- see the build_* methods.
53
56
  SWAP_VALIDATOR_SCRIPT_HEX = "591193010000323232323232323223232322322533300832323232323253233300f300c007132323232323232323253330183016301a3754010264a666032602c60366ea80044c94ccc068cc03d241225374616b696e672063726564656e7469616c20646964206e6f7420617070726f7665003330103020301d375460406042603a6ea8c080c074dd5001002001899807a4812c426561636f6e20736372697074206e6f74206578656375746564206173206d696e74696e6720706f6c6963790033301a3232533302000114a22940c94ccc070c068c078dd50008a5eb7bdb1804dd59811180f9baa001323300100100222533302100114c0103d87a8000132323253330203371e00e6eb8c08800c4c050cc094dd3000a5eb804cc014014008dd598110011812801181180099198008008039129998100008a5eb7bdb1804c8c8c8c94ccc080c048008400c4cc094cdd81ba9002374c0026600c00c0066eacc08800cdd7181000118120011811000a504a22940dd7180f980e1baa018163300b006301e301b37540102c6eb0c074c078c078008dd5980e000980e180e0011bab301a001301a301a301a301a0023758603000260286ea8c05c008c058c05c004c048dd50040a9998079806803899191919191919299980b180a180c1baa0061325333017301430193754002264a6660306601a921225374616b696e672063726564656e7469616c20646964206e6f7420617070726f76650033300e301e301b3754603c603e60366ea8c078c06cdd5001002001899806a4812c426561636f6e20736372697074206e6f74206578656375746564206173207374616b696e6720736372697074003300f004300c3301d3374a90011980e9ba90014bd7025eb805281bae301d301a375402c2c66012008603860326ea801858dd6180d980e180e0011bab301a001301a301a301a301a301a301a0023758603000260286ea8c05c008c058c05c004c048dd5004099191919191919299980b180a180c1baa0061323253330183015301a37540022646464646464646464646666666666666646464444444444444464646464a66606c6464a666070606c60746ea800452889919299981d181b981e1baa003132533303b3038303d3754006266030920127696e76616c69642d686572656166746572206d757374206265203c3d2065787069726174696f6e00337126eb4c104c0f8dd50018008011bad3040303d37540060022a66074920126696e76616c69642d68657265616674657220726571756972656420627574206e6f74207365740016303b00230390013376000a02026464646464646464a66607ca66607ca66607c606002829444c0c004452889980da49194164612063616e206f6e6c79206265206465706f73697465640033712900019b810030061533303e33033491264661696c3a206f666665725f74616b656e202a207072696365203c3d2061736b5f676976656e003371266e08004028cdc1001004899819a4812b5468652061736b2061737365742063616e6e6f742062652074616b656e2066726f6d207468652073776170003371290000010a5016337026eb4c10c01cdd6982180219b81375a60840046eb4c108014dd6982098210009820800991980080081311299981f8008a9981e248123436f72726573706f6e64696e672073776170206f7574707574206e6f7420666f756e6400161323232323253330403375e01c608c608e0042a66608066ebc06400c4ccccccccc07000406005c05805405004c0480444cc01c01c0144cc01c01c014dd5982280098228011821800981f9baa30420023042001375a607c607e002607c00266666666602402201c01a01801601401201000e2c6eb4c0ecc0f0008dd6981d000981b1baa0033374a90021981b98131981b9ba900a3303737520126606e6ea4020cc0dcdd48039981b9ba900633037375200a6606e6ea4010cc0dcdd48019981b8011981b98131981b80e25eb80cc0dc0052f5c097ae0222222222323232323232325333034300730363754607460760042660726ea0014cc0e4dd40019981c9ba80014bd700a9981aa49165554784f206861732077726f6e6720626561636f6e730016375a607200260720046eb4c0dc004c0dc008dd6981a80099980600525eb84101000081010000810100008103d879800011191919191919191929919981c980080a099191919299981e9808181f9baa30430041533303d0021533303d0031330423750016660846ea0024cc108dd40039982119981ea514c103d87a80004c0103d87980004bd7000080080088069807181e9baa30413042002300d303c375460806082608200266602e01097ae10103d87980008103d87980008103d8798000111919191929919199820980100d899823199820800a6103d87a80004c0103d8798000330463330410044c0103d87a80004c0103d8798000330463330410034c0103d87a80004c0103d87980004bd700a999820980100c09982319982080326103d87a80004c0103d8798000330463330410014c0103d87a80004c0103d8798000330463330410034c0103d87a80004c0103d87980004bd700a999820980100a89982319982080326103d87a80004c0103d8798000330463330410044c0103d87a80004c0103d8798000330463330410014c0103d87a80004c0103d87980004bd700a998212481165554784f206861732077726f6e6720626561636f6e730016303e375a608600e6e3cdd71820803180898201baa304430450023010303f375460860026086004601c607a6ea8c10400454c8c8c8c8ccc0f4c0bc0344c94ccc0f8c0ecc100dd50008992991998200028998229ba830070023304537500186608a6ea0004cc114ccc100025300103d87a80004c0103d87980004bd700a9998200020998229ba800e330453750600c0046608a6ea0004cc114ccc10002530103d87a80004c0103d87980004bd700998229ba800e3304537500186608a6ea0004cc114ccc100025300103d87a80004c0103d87980004bd7019b80009001375a608860826ea800458c8cc004004034894ccc10c004530103d87a8000132323253330423034375c60880062606c6608e6ea00052f5c026600a00a0046eb4c110008c11c008c11400454ccc0f54ccc0f400840045280a9998208060a9981f249284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161325333042001132323253330413371e00203226608c6ea0c020008cc118dd4006998231ba800b3304633304100a4c0103d87a80004c0103d87980004bd700a99982099b8f001016133046375001e6608c6ea0c01c008cc118dd400599823199820805260103d87a80004c0103d87980004bd700a998212481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375c60840046eb4c108004c11003454ccc108c1140044c8c8c8c8c8c94ccc110cdc780180e0a99982219b8f00101913304937506016008660926ea0c028008cc124dd400719824999822006a6103d87a80004c0103d87980004bd700a99822a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016153330443371e0060322a66608866e3c0040704cc124dd41805801198249ba8300a00433049375001c6609266608801a980103d87a80004c0103d87980004bd700a99822a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161533045491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375c608a0086eb4c11400cdd718218019bad30430023045002304400d153303f4901284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016304400c1533303d0021533304100c153303e4901284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f001615333041304400c13232533303f3371e6eb8c10400805c4cc110dd41803000998221ba800b3304437500126608866607e010980103d87a80004c0103d87980004bd700a998202481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375a608200260860182a6607c921284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161533303d0011533304100c153303e491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f001615333041304400c13232533303f3371e6eb8c1040080504cc110dd4006998221ba830050013304437500126608866607e010980103d87a80004c0103d87980004bd700a998202481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375a608200260860182a6607c921284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016153303e491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f001630040123003014370000c6e0001cdc78041805181c9baa303d303e002375a607800260780046eb4c0e8004c0e8010dd6981c0019bab3034003375c60640046e2120002253330253330250014a094454cc098008584004888c8ccc00400401000c8894ccc0b000840044ccc00c00cc0bc008cc010c0b8008004dd59814181480519192999812181118131baa0011301833029302a3027375400297ae014c103d87a800030293026375460526054604c6ea8038c090dd500698140051bae3028009375c60500106eb8c0a001cdd718140031bae3028005375c60500086eb8c0a000cdd71814001181400098141814981480098140009813800981300098128009812000981180098110009810800980e1baa018301b3754603c603e60366ea8c078c06cdd50008b19805002800980e180c9baa00616301b301c301c301c301c301c00237586034002603460340046eb0c060004c050dd5180b801180b180b80098091baa008371e9110022323300100100322533301500114c0103d87a80001323253330133375e6032602c6ea80080144c01ccc0600092f5c02660080080026032004602e0026e95200022533300d33300d0014a094454cc03800840044004888c8c94ccc03cc034004528899299980818068010992999808980718099baa0011325333012300f30143754002264646600200201044a66603200229404c94ccc058cdc79bae301c00200414a226600600600260380026eb8c060c054dd5000801980b980a1baa00100230163013375400600226600c008602a60246ea8008c040dd50009809980a18081baa00322323300100100322533301100114a0264a66601c66ebc010c040c050008528899801801800980a00098051baa00314984d958c94ccc01cc01000454ccc02cc028dd50010a4c2c2a66600e600a0022a66601660146ea800852616153330073370e90020008a99980598051baa00214985858c020dd5000a999802180098031baa003132323232323232323232323232323232323232323232533301e30210021323232498c94ccc074c0680044c8c94ccc08cc09800852616375a604800260406ea801054ccc074c06c00454ccc084c080dd50020a4c2c2c603c6ea800cc94ccc070c0640044c8c94ccc088c0940084c926533301e301b30203754002264646464a66604c6052004264932999811180f98121baa003132325333028302b002149858dd7181480098129baa0031616375a604e002604e004604a00260426ea80045858c08c004c07cdd50028a99980e180d0008a999810180f9baa00514985858c074dd5002299980d180b980e1baa00513232323253330223025002149858dd6981180098118011bad3021001301d375400a2c2c603e002603e004603a002603a004603600260360046eb8c064004c064008dd7180b800980b8011bae30150013015002375c602600260260046eb8c044004c044008dd7180780098078011bae300d001300d002375c6016002600e6ea800c58dc3a40006e1d20025734ae7155ceaab9e5573eae815d0aba201" # noqa: E501
54
57
  BEACON_POLICY_SCRIPT_HEX = "5911ed010000332323232323232322322323232322533300932533300a30060011323232533300d3370e900318079baa0011533300d3009300f3754602660206ea80045288010011809180998079baa004153300c4913c546869732072656465656d65722063616e206f6e6c79206265207573656420746f2072656769737465722074686520626561636f6e207363726970740016300c37540042646464646464646464a666026601c0142646464666600802864a66602e602600226eb8c074c068dd5001899299980c1809001099299980c980a980d9baa001132533301a3015301c375400226eb8c080c074dd5000801980f980e1baa001002301e301b37540080022a6603092012852656465656d6572206e6f7420757365642077697468206d696e74696e6720657865637574696f6e00163018375400460166038603a603a603a603a603a0026eb0c070004c070c070c060dd5180d801180d180d800980b1baa00b13232323333004014325333017301130193754006264a666030602860346ea80044c94ccc064c050c06cdd500089bae301f301c3754002006603c60366ea8004008c074c068dd50018008a9980ba4812852656465656d6572206e6f7420757365642077697468207374616b696e6720657865637574696f6e0016300b301c301d301d301d301d301d001375860380026038603860306ea8c06c008c068c06c004c058dd5005911119199800800801251222533301d00210011333003003302000232323232323232325333025001100913253330260011533023491364f6e652d776179207377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e730016132533302700115330244901364f6e652d776179207377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e73001615333027302a0011323232533302600e153330263301632330160014911a204441707020616464726573732077697468207374616b696e67003301549114426561636f6e206d75737420676f20746f2061200049010053330263375e01066e9520023302b375202897ae01533302630223028375400e29445280a50132323232323232323232323232323232323232323232323232533303f32325333041303c3043375400229444c8c94ccc10cc0fcc114dd50018992999822182018231baa00315333044330354912745787069726174696f6e206d757374206265203e3d20696e76616c69642d68657265616674657200337126eb4c128c11cdd500180089981aa481234d7573742075736520312d6d696e2065787069726174696f6e20696e74657276616c730030403370c002906054838a50002375a6092608c6ea800c00454cc10d240126696e76616c69642d68657265616674657220726571756972656420627574206e6f742073657400163044002304200133760608a608c608c0120562a66607e6605e92010f57726f6e6720626561636f6e5f6964003371e0580302a66607e6605e9201274f666665722061737365742063616e6e6f742062652073616d652061732061736b2061737365740033303f3375e01000e941288a99981f99817a491157726f6e6720706169725f626561636f6e003371e02c64646464646460706464660760020086607400200466072a66608a601200a291010100001005375c6096609800ca6660886010004291010100001002375c609260940046eb8c120004c110dd50049bae3046001304237540102a66607e6605e9211257726f6e67206f666665725f626561636f6e003371e020606466066911010100330330140121533303f3302f49011057726f6e672061736b5f626561636f6e003371e0146064660669110102003303300e00c1533303f3302f49011e737761705f70726963652064656e6f6d696e61746f72206e6f74203e20300030020041533303f3302f49011c737761705f7072696365206e756d657261746f72206e6f74203e203000300200513371290000008a5014a029405280a5014a0294058dd698221919191919192999822180398231baa304a304b002133049375000a660926ea000ccc124dd4000a5eb8054cc115241165554784f206861732077726f6e6720626561636f6e730016375a609200260920046eb4c11c004c11c008dd69822800999818011a5eb84101000081010000810100008103d8798000111919191919191919299199824980081b0991919192999826980818279baa30530041533304d0021533304d0031330523750016660a46ea0024cc148dd400399829199826a514c103d87a80004c0103d87980004bd700008008008806980718269baa30513052002300d304c375460a060a260a200266607601097ae10103d87980008103d87980008103d8798000111919191929919199828980101409982b199828800a6103d87a80004c0103d8798000330563330510044c0103d87a80004c0103d8798000330563330510034c0103d87a80004c0103d87980004bd700a999828980101109982b19982880326103d87a80004c0103d8798000330563330510014c0103d87a80004c0103d8798000330563330510034c0103d87a80004c0103d87980004bd700a999828980100e09982b19982880326103d87a80004c0103d8798000330563330510044c0103d87a80004c0103d8798000330563330510014c0103d87a80004c0103d87980004bd700a998292481165554784f206861732077726f6e6720626561636f6e730016304b375a60a600e6e3cdd71828803180898281baa305430550023010304f375460a600260a6004601c609a6ea8c14400454c8c8c8c8ccc134c0440344c94ccc138c128c140dd500089929919982800289982a9ba83007002330553750018660aa6ea0004cc154ccc140025300103d87a80004c0103d87980004bd700a99982800209982a9ba800e330553750600c004660aa6ea0004cc154ccc14002530103d87a80004c0103d87980004bd7009982a9ba800e330553750018660aa6ea0004cc154ccc140025300103d87a80004c0103d87980004bd7019b80009001375a60a860a26ea800458c8cc004004034894ccc14c004530103d87a8000132323253330523016375c60a800626090660ae6ea00052f5c026600a00a0046eb4c150008c15c008c15400454ccc1354ccc13400840045280a9998288060a99827249284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161325333052001132323253330513371e0020482660ac6ea0c020008cc158dd40069982b1ba800b3305633305100a4c0103d87a80004c0103d87980004bd700a99982899b8f00101e133056375001e660ac6ea0c01c008cc158dd40059982b199828805260103d87a80004c0103d87980004bd700a998292481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375c60a40046eb4c148004c15003454ccc148c1540044c8c8c8c8c8c94ccc150cdc78018138a99982a19b8f00102113305937506016008660b26ea0c028008cc164dd40071982c99982a006a6103d87a80004c0103d87980004bd700a9982aa481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016153330543371e0060422a6660a866e3c00409c4cc164dd418058011982c9ba8300a00433059375001c660b26660a801a980103d87a80004c0103d87980004bd700a9982aa481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161533055491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375c60aa0086eb4c15400cdd718298019bad30530023055002305400d153304f4901284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016305400c1533304d0021533305100c153304e4901284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f001615333051305400c13232533304f3371e6eb8c1440080884cc150dd418030009982a1ba800b330543750012660a866609e010980103d87a80004c0103d87980004bd700a998282481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375a60a200260a60182a6609c921284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f00161533304d0011533305100c153304e491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f001615333051305400c13232533304f3371e6eb8c1440080704cc150dd40069982a1ba83005001330543750012660a866609e010980103d87a80004c0103d87980004bd700a998282481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016375a60a200260a60182a6609c921284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016153304e491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554784f0016300401b3003020370000c6e0001cdc7804180518249baa304d304e002375a609800260980046eb4c128004c128010dd698240019bab3044003375c60840046e212000371e91100375a608260840046eb4c100004c0f0dd5181f80198171981e9ba90073303d375200a97ae0302d3303c3752018660786ea40292f5c0607a0046eb8c0ec004c0ec008dd7181c800981c8011bae30370013037002375c606a002606a0046eb8c0cc004c0cc008dd7181880098188011bae302f001302f002375c605a00260526ea94ccc098c080c0a0dd5005099190012999813981198149baa001132323232323232323232323232323232323232323232533304130440021323232498c94ccc100c0f00044c8c94ccc118c12400852616375a608e00260866ea801054ccc100c0ec00454ccc110c10cdd50020a4c2c2c60826ea800cc94ccc0fcc0ec0044c8c94ccc114c1200084c9265333041303d30433754002264646464a6660926098004264932999822982098239baa00313232533304b304e002149858dd7182600098241baa0031616375a60940026094004609000260886ea80045858c118004c108dd50028a99981f981d0008a99982198211baa00514985858c100dd5002299981e981c981f9baa00513232323253330453048002149858dd6982300098230011bad30440013040375400a2c2c6084002608400460800026080004607c002607c0046eb8c0f0004c0f0008dd7181d000981d0011bae30380013038002375c606c002606c0046eb8c0d0004c0d0008dd7181900098190011bae30300013030002375c605c00260546ea800458c0b0c0a4dd50050a99813a48125416c6c207377617020646174756d73206d75737420626520696e6c696e6520646174756d73001614a02940c0ac00cc0a800cc0a400c54cc0912401364f6e652d776179207377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e73001630290013028001325333021301c30233754002297adef6c6013756604e60486ea8004c8cc004004018894ccc098004530103d87a8000132323253330253371e0246eb8c09c00c4c06ccc0a8dd3000a5eb804cc014014008dd598138011815001181400098129813001181200098101baa30230043022302300237566042002604200260386ea8c07c00888cdcb001000912999809199809000a504a22a660260042002200244a666022666022002941288a998090010b080091119199800800802001911299980c00108008999801801980d80119802180d00100091b92001223371400400246464a66601c601260206ea80044c010cc04cc050c044dd5000a5eb80530103d87a80003013301037546026602860206ea8008c038dd50009ba548000c02cdd50030a4c26cac64a66601060080022a66601860166ea8014526161533300830030011533300c300b375400a2930b0a99980418010008a99980618059baa00514985858c024dd50021b8748010dc3a40046e1d2000375c002ae695ce2ab9d5573caae7d5d02ba157449811e581c1d6cff26bcab91d2061aad0bd259cbb7d76d25ced2eeaed5926a42ad0001" # noqa: E501
55
58
 
@@ -421,6 +424,58 @@ class CardanoSwapsOrderState(AbstractOrderState):
421
424
  """The (inline) beacon minting/staking policy."""
422
425
  return PlutusV2Script(bytes.fromhex(BEACON_POLICY_SCRIPT_HEX))
423
426
 
427
+ @staticmethod
428
+ def _verify_ref_script(ref_utxo: UTxO, expected_hash: str, label: str) -> None:
429
+ """Validate a caller-supplied reference-script UTxO.
430
+
431
+ The UTxO's output must carry a script and that script must hash to the
432
+ expected validator/policy hash; otherwise the tx would reference the
433
+ wrong script and fail only at on-chain evaluation. The spending path is
434
+ already hash-checked by pycardano against the input's payment credential,
435
+ but the minting path is not, so this guard applies to both for symmetry.
436
+ """
437
+ script = ref_utxo.output.script
438
+ if script is None:
439
+ raise ValueError(f"{label} reference UTxO has no output script.")
440
+ actual = plutus_script_hash(script)
441
+ if actual != ScriptHash(bytes.fromhex(expected_hash)):
442
+ raise ValueError(
443
+ f"{label} reference UTxO script hash {actual.payload.hex()} "
444
+ f"!= expected {expected_hash}.",
445
+ )
446
+
447
+ @classmethod
448
+ def _swap_script_arg(
449
+ cls,
450
+ swap_ref_utxo: UTxO | None,
451
+ ) -> UTxO | PlutusV2Script:
452
+ """The swap validator to attach to a builder.
453
+
454
+ A caller-supplied reference-script UTxO (referenced via a reference input)
455
+ when given, otherwise the inline swap validator (attached to the witness
456
+ set). pycardano dispatches on the argument type.
457
+ """
458
+ if swap_ref_utxo is None:
459
+ return cls._swap_script()
460
+ cls._verify_ref_script(swap_ref_utxo, SWAP_VALIDATOR_HASH, "swap validator")
461
+ return swap_ref_utxo
462
+
463
+ @classmethod
464
+ def _beacon_script_arg(
465
+ cls,
466
+ beacon_ref_utxo: UTxO | None,
467
+ ) -> UTxO | PlutusV2Script:
468
+ """The beacon policy to attach to a builder.
469
+
470
+ A caller-supplied reference-script UTxO (referenced via a reference input)
471
+ when given, otherwise the inline beacon policy (attached to the witness
472
+ set). pycardano dispatches on the argument type.
473
+ """
474
+ if beacon_ref_utxo is None:
475
+ return cls._beacon_script()
476
+ cls._verify_ref_script(beacon_ref_utxo, BEACON_POLICY_ID, "beacon policy")
477
+ return beacon_ref_utxo
478
+
424
479
  @staticmethod
425
480
  def beacon_address(owner_address: Address) -> Address:
426
481
  """The beacon-tagged swap address for an owner.
@@ -465,6 +520,8 @@ class CardanoSwapsOrderState(AbstractOrderState):
465
520
  price: tuple[int, int],
466
521
  tx_builder: TransactionBuilder,
467
522
  expiration: int | None = None,
523
+ *,
524
+ beacon_ref_utxo: UTxO | None = None,
468
525
  ) -> tuple[TransactionOutput, CardanoSwapsSwapDatum]:
469
526
  """Build a CREATE: mint the three beacons and emit the resting swap UTxO.
470
527
 
@@ -481,6 +538,9 @@ class CardanoSwapsOrderState(AbstractOrderState):
481
538
  price: ``(numerator, denominator)`` ask-per-offer rational.
482
539
  tx_builder: The builder to mutate.
483
540
  expiration: Optional POSIX-millis expiration (must be a 60000-multiple).
541
+ beacon_ref_utxo: Optional reference-script UTxO for the beacon policy;
542
+ when given, the policy is referenced via a reference input instead
543
+ of inlined into the witness set.
484
544
 
485
545
  Returns:
486
546
  The swap output and its inline ``SwapDatum``.
@@ -512,7 +572,7 @@ class CardanoSwapsOrderState(AbstractOrderState):
512
572
 
513
573
  # Mint the three beacons.
514
574
  tx_builder.add_minting_script(
515
- script=cls._beacon_script(),
575
+ script=cls._beacon_script_arg(beacon_ref_utxo),
516
576
  redeemer=Redeemer(CreateOrCloseSwaps()),
517
577
  )
518
578
  cls._accumulate_mint(tx_builder, cls._beacon_mint_assets(datum, 1))
@@ -570,11 +630,14 @@ class CardanoSwapsOrderState(AbstractOrderState):
570
630
  address_target: Address | None = None,
571
631
  datum_target: PlutusData | None = None,
572
632
  owner_address: Address | None = None,
633
+ *,
634
+ swap_ref_utxo: UTxO | None = None,
573
635
  ) -> tuple[TransactionOutput | None, PlutusData]:
574
636
  """Build a FILL: spend the resting swap UTxO and fill at price or better.
575
637
 
576
- Spends the resting UTxO with the ``Swap`` spending redeemer (inline
577
- script no on-chain reference) and emits the contract-mandated
638
+ Spends the resting UTxO with the ``Swap`` spending redeemer (the swap
639
+ validator is inlined by default, or referenced via a reference input when
640
+ the caller supplies ``swap_ref_utxo``) and emits the contract-mandated
578
641
  continuing output back to the same swap address: the three beacons are
579
642
  preserved, the offer balance is decremented by the amount taken, and the
580
643
  ask paid in (at price or better) accumulates into this same output. The
@@ -613,7 +676,7 @@ class CardanoSwapsOrderState(AbstractOrderState):
613
676
 
614
677
  tx_builder.add_script_input(
615
678
  utxo=input_utxo,
616
- script=self._swap_script(),
679
+ script=self._swap_script_arg(swap_ref_utxo),
617
680
  redeemer=Redeemer(Swap()),
618
681
  )
619
682
  tx_builder.datums.update({self.order_datum.hash(): self.order_datum})
@@ -668,6 +731,9 @@ class CardanoSwapsOrderState(AbstractOrderState):
668
731
  self,
669
732
  tx_builder: TransactionBuilder,
670
733
  owner_address: Address | None = None,
734
+ *,
735
+ swap_ref_utxo: UTxO | None = None,
736
+ beacon_ref_utxo: UTxO | None = None,
671
737
  ) -> CardanoSwapsSwapDatum:
672
738
  """Build a CLOSE: spend the swap UTxO and burn the three beacons.
673
739
 
@@ -675,7 +741,9 @@ class CardanoSwapsOrderState(AbstractOrderState):
675
741
  beacon under the beacon policy with ``CreateOrCloseSwaps``. The owner's
676
742
  stake credential must authorize the spend (sign with the stake key for a
677
743
  vkey stake credential, or run the stake script); reclaim of the offer
678
- asset to the owner is handled by change.
744
+ asset to the owner is handled by change. The swap validator and beacon
745
+ policy are inlined by default, or referenced via a reference input when
746
+ the caller supplies ``swap_ref_utxo`` / ``beacon_ref_utxo``.
679
747
 
680
748
  Returns:
681
749
  The spent (resting) ``SwapDatum``.
@@ -686,14 +754,14 @@ class CardanoSwapsOrderState(AbstractOrderState):
686
754
  input_utxo = self._input_utxo(owner_address)
687
755
  tx_builder.add_script_input(
688
756
  utxo=input_utxo,
689
- script=self._swap_script(),
757
+ script=self._swap_script_arg(swap_ref_utxo),
690
758
  redeemer=Redeemer(SpendWithMint()),
691
759
  )
692
760
  tx_builder.datums.update({self.order_datum.hash(): self.order_datum})
693
761
 
694
762
  # Burn the three beacons.
695
763
  tx_builder.add_minting_script(
696
- script=self._beacon_script(),
764
+ script=self._beacon_script_arg(beacon_ref_utxo),
697
765
  redeemer=Redeemer(CreateOrCloseSwaps()),
698
766
  )
699
767
  self._accumulate_mint(
@@ -9,6 +9,7 @@ from dataclasses import dataclass
9
9
  from decimal import Decimal
10
10
  from functools import lru_cache
11
11
  from typing import Any
12
+ from typing import ClassVar
12
13
  from typing import Union
13
14
 
14
15
  from pycardano import Address
@@ -40,12 +41,31 @@ from charli3_dendrite.dexs.ob.ob_base import OrderBookOrder
40
41
  from charli3_dendrite.dexs.ob.ob_base import SellOrderBook
41
42
  from charli3_dendrite.utility import asset_to_value
42
43
 
43
- SATURNSWAP_TAKER_FEE_BPS = 400
44
-
45
- # SaturnSwap charges a 4% on-chain taker fee on every fill that is NOT co-signed
46
- # by its authorized hot-key; co-signed (protocol-routed) fills are exempt via the
47
- # validator's ``fees_paid_or_auth``. When the protocol shares that hot-key, set
48
- # this env var to the signing key and dendrite builds the fee-free authorized fill.
44
+ # SaturnSwap charges an on-chain taker fee on every fill that is NOT co-signed by
45
+ # its authorized hot-key; co-signed (protocol-routed) fills are exempt via the
46
+ # validator's ``fees_paid_or_auth``. In 2026-06 the protocol redeployed the swap
47
+ # contract with the non-auth fee lowered 4% -> 1% (validator ``fee_percent``
48
+ # 400 -> 100); only that integer changed, so the contract kept the same stake
49
+ # credential but gained a new script hash/address. Dendrite tracks both the live
50
+ # 1% contract and the legacy 4% contract so in-flight legacy orders still fill at
51
+ # the correct rate (see SaturnSwapOrderState / SaturnSwapLegacyOrderState).
52
+ SATURNSWAP_TAKER_FEE_BPS = 100
53
+ SATURNSWAP_LEGACY_TAKER_FEE_BPS = 400
54
+
55
+ # Live 1% contract; script hash
56
+ # 73990b71041ceade6f867617f6ce9f187ab710ea2bf1ff8db7d0292f.
57
+ SATURNSWAP_ORDER_ADDRESS = (
58
+ "addr1z9eejzm3qsww4hn0semp0akwnuv84dcsag4lrludklgzjt"
59
+ "675jq4yvpskgayj55xegdp30g5rfynax66r8vgn9fldndsrfnae7"
60
+ )
61
+ # Legacy 4% contract (pre-2026-06 deployment).
62
+ SATURNSWAP_LEGACY_ORDER_ADDRESS = (
63
+ "addr1zyd0sj57d9lpu7cy9g9qdurpazqc9l4eaxk6j59nd2gkh4"
64
+ "275jq4yvpskgayj55xegdp30g5rfynax66r8vgn9fldndsqzf5tn"
65
+ )
66
+
67
+ # When the protocol shares its authorize hot-key, set this env var to the signing
68
+ # key and dendrite builds the fee-free authorized fill on either contract.
49
69
  SATURNSWAP_AUTHORIZE_KEY_ENV = "SATURNSWAP_AUTHORIZE_KEY"
50
70
 
51
71
 
@@ -63,9 +83,10 @@ def saturnswap_authorize_signing_key() -> PaymentSigningKey | None:
63
83
 
64
84
  Set ``SATURNSWAP_AUTHORIZE_KEY`` (the hot-key as ``sk.to_cbor_hex()`` or raw
65
85
  32-byte hex) to build fee-free authorized fills. ``swap_utxo`` then drops the
66
- 4% fee output and adds the key's hash as a required signer. The CALLER must
86
+ taker-fee output and adds the key's hash as a required signer. The CALLER must
67
87
  add this key when signing the transaction (e.g. ``build_and_sign([…, key])``).
68
- Returns ``None`` (default behaviour, 4% fee) when the env var is unset.
88
+ Returns ``None`` (default behaviour, on-chain taker fee) when the env var is
89
+ unset.
69
90
  """
70
91
  raw = os.environ.get(SATURNSWAP_AUTHORIZE_KEY_ENV)
71
92
  return _load_authorize_signing_key(raw) if raw else None
@@ -253,8 +274,14 @@ class SaturnSwapCancelAction(PlutusData):
253
274
  return
254
275
 
255
276
 
256
- class SaturnSwapOrderState(AbstractOrderState):
257
- """SaturnSwap order state for individual orders."""
277
+ class _SaturnSwapOrderStateBase(AbstractOrderState):
278
+ """Shared SaturnSwap order-state logic for both contract versions.
279
+
280
+ Concrete subclasses pin the contract-specific bits — the order script
281
+ ``order_selector()`` address and the non-auth ``TAKER_FEE_BPS`` — and supply
282
+ ``dex()``. The base intentionally leaves ``dex()`` unimplemented so the
283
+ subclass-discovery walk skips it and only registers the concrete leaves.
284
+ """
258
285
 
259
286
  tx_hash: str
260
287
  tx_index: int
@@ -262,29 +289,17 @@ class SaturnSwapOrderState(AbstractOrderState):
262
289
  datum_hash: str
263
290
  inactive: bool = False
264
291
 
292
+ # Non-auth taker fee in basis points; set by each concrete contract class.
293
+ TAKER_FEE_BPS: ClassVar[int]
294
+
265
295
  _batcher: Assets = Assets(lovelace=0)
266
296
  _datum_parsed: PlutusData | None = None
267
297
 
268
- @classmethod
269
- def dex(cls) -> str:
270
- """Return the DEX name."""
271
- return "SaturnSwap"
272
-
273
298
  @classmethod
274
299
  def dex_policy(cls) -> list[str] | None:
275
300
  """SaturnSwap uses parameterized scripts, no global dex NFT."""
276
301
  return None
277
302
 
278
- @classmethod
279
- def order_selector(cls) -> list[str]:
280
- """Return order script addresses."""
281
- return [
282
- (
283
- "addr1zyd0sj57d9lpu7cy9g9qdurpazqc9l4eaxk6j59nd2gkh4"
284
- "275jq4yvpskgayj55xegdp30g5rfynax66r8vgn9fldndsqzf5tn"
285
- ),
286
- ]
287
-
288
303
  @classmethod
289
304
  def pool_selector(cls) -> PoolSelector:
290
305
  """Return pool selector for order UTxOs."""
@@ -360,11 +375,12 @@ class SaturnSwapOrderState(AbstractOrderState):
360
375
  def volume_fee(self) -> int:
361
376
  """Taker fee in basis points (0 when the authorize hot-key co-signs).
362
377
 
363
- SaturnSwap waives the 4% on-chain taker fee for fills co-signed by its
378
+ SaturnSwap waives the on-chain taker fee for fills co-signed by its
364
379
  authorized hot-key, so the fee is 0 when ``SATURNSWAP_AUTHORIZE_KEY`` is
365
- configured (see :func:`saturnswap_authorize_signing_key`).
380
+ configured (see :func:`saturnswap_authorize_signing_key`); otherwise it
381
+ is the contract-specific ``TAKER_FEE_BPS``.
366
382
  """
367
- return 0 if _authorize_vkey_hash() is not None else SATURNSWAP_TAKER_FEE_BPS
383
+ return 0 if _authorize_vkey_hash() is not None else self.TAKER_FEE_BPS
368
384
 
369
385
  @property
370
386
  def swap_forward(self) -> bool:
@@ -450,7 +466,7 @@ class SaturnSwapOrderState(AbstractOrderState):
450
466
  new_amount_sell: int,
451
467
  payment_datum: "SaturnSwapPaymentDatum",
452
468
  ) -> None:
453
- """Add the 4% taker-fee output, or require the authorize hot-key signature.
469
+ """Add the taker-fee output, or require the authorize hot-key signature.
454
470
 
455
471
  SaturnSwap exempts fills co-signed by its authorized hot-key from the
456
472
  on-chain fee (``fees_paid_or_auth``). When ``SATURNSWAP_AUTHORIZE_KEY`` is
@@ -566,7 +582,7 @@ class SaturnSwapOrderState(AbstractOrderState):
566
582
  )
567
583
  tx_builder.add_output(owner_output)
568
584
 
569
- # Fee output (4%) for unauthorized fills, or require the hot-key
585
+ # Taker-fee output for unauthorized fills, or require the hot-key
570
586
  # signature for authorized (fee-free) fills.
571
587
  self._add_fee_or_authorize(
572
588
  tx_builder,
@@ -643,8 +659,60 @@ class SaturnSwapOrderState(AbstractOrderState):
643
659
  return None, self.order_datum
644
660
 
645
661
 
662
+ class SaturnSwapOrderState(_SaturnSwapOrderStateBase):
663
+ """Live SaturnSwap order state — current 1% taker-fee contract.
664
+
665
+ Orders resting at :data:`SATURNSWAP_ORDER_ADDRESS` (script hash
666
+ ``73990b71…``). New maker orders are created here.
667
+ """
668
+
669
+ TAKER_FEE_BPS: ClassVar[int] = SATURNSWAP_TAKER_FEE_BPS
670
+
671
+ @classmethod
672
+ def dex(cls) -> str:
673
+ """Return the DEX name."""
674
+ return "SaturnSwap"
675
+
676
+ @classmethod
677
+ def order_selector(cls) -> list[str]:
678
+ """Return order script addresses (live 1% contract)."""
679
+ return [SATURNSWAP_ORDER_ADDRESS]
680
+
681
+
682
+ class SaturnSwapLegacyOrderState(_SaturnSwapOrderStateBase):
683
+ """Legacy SaturnSwap order state — pre-2026-06 4% taker-fee contract.
684
+
685
+ Orders resting at :data:`SATURNSWAP_LEGACY_ORDER_ADDRESS`. Kept so in-flight
686
+ orders on the old contract still fill at their correct 4% fee.
687
+ """
688
+
689
+ TAKER_FEE_BPS: ClassVar[int] = SATURNSWAP_LEGACY_TAKER_FEE_BPS
690
+
691
+ @classmethod
692
+ def dex(cls) -> str:
693
+ """Return the DEX name."""
694
+ return "SaturnSwap"
695
+
696
+ @classmethod
697
+ def order_selector(cls) -> list[str]:
698
+ """Return order script addresses (legacy 4% contract)."""
699
+ return [SATURNSWAP_LEGACY_ORDER_ADDRESS]
700
+
701
+
702
+ # Concrete SaturnSwap contracts, newest first. The order book walks all of these
703
+ # so both the live 1% contract and the legacy 4% contract are aggregated.
704
+ _SATURNSWAP_ORDER_STATE_CLASSES: list[type[_SaturnSwapOrderStateBase]] = [
705
+ SaturnSwapOrderState,
706
+ SaturnSwapLegacyOrderState,
707
+ ]
708
+
709
+
646
710
  class SaturnSwapOrderBook(AbstractOrderBookState):
647
- """SaturnSwap order book aggregating individual orders."""
711
+ """SaturnSwap order book aggregating individual orders.
712
+
713
+ Aggregates orders from every contract version in
714
+ :data:`_SATURNSWAP_ORDER_STATE_CLASSES` (live 1% + legacy 4%).
715
+ """
648
716
 
649
717
  _deposit: Assets = Assets(lovelace=0)
650
718
 
@@ -652,25 +720,31 @@ class SaturnSwapOrderBook(AbstractOrderBookState):
652
720
  def get_book(
653
721
  cls,
654
722
  assets: Assets,
655
- orders: list[SaturnSwapOrderState] | None = None,
723
+ orders: list[_SaturnSwapOrderStateBase] | None = None,
656
724
  ) -> "SaturnSwapOrderBook":
657
- """Build an order book from provided orders or backend UTxOs."""
725
+ """Build an order book from provided orders or backend UTxOs.
726
+
727
+ When ``orders`` is not supplied, UTxOs are fetched for every contract
728
+ version (live 1% + legacy 4%) and validated with the matching order-state
729
+ class so each order carries the correct taker fee.
730
+ """
658
731
  min_pair_assets = 2
659
732
  utxo_limit = 10_000
660
733
  if orders is None:
661
- selector = SaturnSwapOrderState.pool_selector()
662
- result = get_backend().get_pool_utxos(
663
- limit=utxo_limit,
664
- historical=False,
665
- **selector.model_dump(),
666
- )
667
734
  # Skip invalid/non-order datums that fail deserialization
668
735
  orders = []
669
- for r in result:
670
- try:
671
- orders.append(SaturnSwapOrderState.model_validate(r.model_dump()))
672
- except NotAPoolError:
673
- continue
736
+ for state_cls in _SATURNSWAP_ORDER_STATE_CLASSES:
737
+ selector = state_cls.pool_selector()
738
+ result = get_backend().get_pool_utxos(
739
+ limit=utxo_limit,
740
+ historical=False,
741
+ **selector.model_dump(),
742
+ )
743
+ for r in result:
744
+ try:
745
+ orders.append(state_cls.model_validate(r.model_dump()))
746
+ except NotAPoolError:
747
+ continue
674
748
 
675
749
  buy_orders: list[OrderBookOrder] = []
676
750
  sell_orders: list[OrderBookOrder] = []
@@ -724,13 +798,17 @@ class SaturnSwapOrderBook(AbstractOrderBookState):
724
798
 
725
799
  @classmethod
726
800
  def order_selector(cls) -> list[str]:
727
- """Return order script addresses."""
728
- return SaturnSwapOrderState.order_selector()
801
+ """Return order script addresses for all contract versions."""
802
+ return [
803
+ address
804
+ for state_cls in _SATURNSWAP_ORDER_STATE_CLASSES
805
+ for address in state_cls.order_selector()
806
+ ]
729
807
 
730
808
  @classmethod
731
809
  def pool_selector(cls) -> PoolSelector:
732
- """Return pool selector for order UTxOs."""
733
- return SaturnSwapOrderState.pool_selector()
810
+ """Return pool selector for order UTxOs across all contract versions."""
811
+ return PoolSelector(addresses=cls.order_selector())
734
812
 
735
813
  @classmethod
736
814
  def default_script_class(cls) -> type[PlutusV2Script]: