charli3_dendrite 1.5.4.dev0__tar.gz → 1.5.5.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 (118) hide show
  1. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/PKG-INFO +1 -1
  2. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/pyproject.toml +2 -2
  3. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/dano.py +2 -1
  4. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/datums.py +1 -6
  5. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/redeemer.py +3 -8
  6. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/__init__.py +1 -0
  7. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/constants.py +207 -0
  8. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/datums.py +232 -0
  9. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/loader.py +237 -0
  10. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/market.py +53 -0
  11. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/math.py +166 -0
  12. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/oracles/__init__.py +1 -0
  13. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/oracles/feeds.py +35 -0
  14. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/oracles/fluid_api.py +329 -0
  15. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/oracles/witness.py +186 -0
  16. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/state.py +380 -0
  17. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/__init__.py +1 -0
  18. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/_common.py +198 -0
  19. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/borrow.py +333 -0
  20. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/builder.py +336 -0
  21. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/change_collateral.py +190 -0
  22. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/context.py +2654 -0
  23. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/datum_synth.py +391 -0
  24. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/lend.py +266 -0
  25. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/pool.py +193 -0
  26. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/recast.py +201 -0
  27. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/redeemers.py +474 -0
  28. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/repay.py +270 -0
  29. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/request.py +207 -0
  30. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/fluidtokens/transactions/resolve.py +220 -0
  31. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/registry.py +4 -0
  32. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/transactions/base.py +6 -0
  33. charli3_dendrite-1.5.5.dev0/src/charli3_dendrite/lending/units.py +48 -0
  34. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/utility.py +9 -0
  35. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/LICENSE +0 -0
  36. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/README.md +0 -0
  37. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/__init__.py +0 -0
  38. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
  39. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
  40. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
  41. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
  42. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
  43. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
  44. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
  45. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
  46. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
  47. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
  48. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
  49. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
  50. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
  51. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
  52. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
  53. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
  54. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
  55. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
  56. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
  57. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
  58. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
  59. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
  60. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
  61. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
  62. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
  63. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
  64. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
  65. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
  66. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
  67. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +0 -0
  68. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
  69. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
  70. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
  71. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
  72. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +0 -0
  73. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/__init__.py +0 -0
  74. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/base.py +0 -0
  75. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/__init__.py +0 -0
  76. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/constants.py +0 -0
  77. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/loader.py +0 -0
  78. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/market.py +0 -0
  79. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/math.py +0 -0
  80. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/__init__.py +0 -0
  81. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator.py +0 -0
  82. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator_datums.py +0 -0
  83. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/deployments.py +0 -0
  84. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/forward.py +0 -0
  85. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/leaves.py +0 -0
  86. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/locator.py +0 -0
  87. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/lp_pricing.py +0 -0
  88. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/recipes.json +0 -0
  89. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/reproduce.py +0 -0
  90. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/oracles/structured_datums.py +0 -0
  91. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/state.py +0 -0
  92. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/__init__.py +0 -0
  93. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/_common.py +0 -0
  94. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/build.py +0 -0
  95. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/builder.py +0 -0
  96. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/context.py +0 -0
  97. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/create_loan.py +0 -0
  98. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/datum_synth.py +0 -0
  99. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/increase_loan.py +0 -0
  100. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/loan_ids.py +0 -0
  101. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/modify_collateral.py +0 -0
  102. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_redeemer.py +0 -0
  103. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_synth.py +0 -0
  104. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/redeemers.py +0 -0
  105. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/repay.py +0 -0
  106. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/topup_withdraw.py +0 -0
  107. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/danogo/transactions/verify.py +0 -0
  108. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/math.py +0 -0
  109. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/__init__.py +0 -0
  110. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/charli3.py +0 -0
  111. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/dex_pooled.py +0 -0
  112. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/fluid.py +0 -0
  113. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/models.py +0 -0
  114. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/orcfax.py +0 -0
  115. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/oracles/qtoken.py +0 -0
  116. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/transactions/__init__.py +0 -0
  117. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/transactions/infra.py +0 -0
  118. {charli3_dendrite-1.5.4.dev0 → charli3_dendrite-1.5.5.dev0}/src/charli3_dendrite/lending/transactions/snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: charli3_dendrite
3
- Version: 1.5.4.dev0
3
+ Version: 1.5.5.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.5.4-dev0"
3
+ version = "1.5.5-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.5.4-dev0"
53
+ current_version = "1.5.5-dev0"
54
54
  parse = """(?x)
55
55
  (?P<major>\\d+)\\.
56
56
  (?P<minor>\\d+)\\.
@@ -994,7 +994,8 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
994
994
  A fresh chain parse carries the dex NFT *inside* the assets bag (extracted
995
995
  later), not as a ``dex_nft`` key, so it takes the full parse path. Mirrors
996
996
  VyFi / WingRiders V2; makes the serialize→reingest round-trip idempotent
997
- for both the dendrite model_dump form and steelswap's net silver.
997
+ for both the dendrite model_dump form and a downstream consumer's
998
+ net-reserves view.
998
999
  """
999
1000
  if "dex_nft" in values:
1000
1001
  if not isinstance(values["assets"], Assets):
@@ -14,12 +14,7 @@ from typing import List
14
14
  from pycardano import IndefiniteList
15
15
  from pycardano import PlutusData
16
16
 
17
-
18
- def asset_unit(policy: bytes, name: bytes) -> str:
19
- """Dendrite unit string for a (policy, name) asset ('lovelace' for ADA)."""
20
- if not policy and not name:
21
- return "lovelace"
22
- return policy.hex() + name.hex()
17
+ from charli3_dendrite.lending.units import asset_unit
23
18
 
24
19
 
25
20
  @dataclass
@@ -37,6 +37,7 @@ from enum import IntEnum
37
37
  import cbor2 # type: ignore[import-not-found]
38
38
 
39
39
  from charli3_dendrite.lending.danogo.datums import asset_unit
40
+ from charli3_dendrite.lending.units import constr_alt
40
41
 
41
42
 
42
43
  class UTxOTarget(IntEnum):
@@ -126,14 +127,8 @@ _CONSTR_TAG_EXT = 1280
126
127
  _CONSTR_EXT_OFFSET = 7
127
128
  _RDMR_BORROW_FIELD = 4
128
129
 
129
-
130
- def _constr_alt(tag: int) -> int:
131
- """CBOR constructor tag -> alternative index (pycardano convention)."""
132
- if _CONSTR_TAG_MIN <= tag <= _CONSTR_TAG_MAX:
133
- return tag - _CONSTR_TAG_MIN
134
- if tag >= _CONSTR_TAG_EXT:
135
- return tag - _CONSTR_TAG_EXT + _CONSTR_EXT_OFFSET
136
- raise ValueError(f"not a constructor tag: {tag}")
130
+ # Thin alias over the shared primitive; kept for existing danogo call sites.
131
+ _constr_alt = constr_alt
137
132
 
138
133
 
139
134
  def _alt_constr_tag(alt: int) -> int:
@@ -0,0 +1 @@
1
+ """FluidTokens V3 lending protocol integration."""
@@ -0,0 +1,207 @@
1
+ """FluidTokens V3 mainnet coordinates.
2
+
3
+ The protocol is parameterized by a single config NFT; the config UTxO datum holds
4
+ every protocol script hash / policy id. The constants below are the live mainnet
5
+ deployment coordinates (a static fallback), and `resolve_addresses` re-reads the live
6
+ config datum through the backend so entity discovery self-heals across a redeploy,
7
+ falling back to the constants when the datum cannot be read (e.g. a non-dbsync
8
+ backend).
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from typing import TYPE_CHECKING
14
+ from typing import TypedDict
15
+
16
+ import cbor2 # type: ignore[import-not-found]
17
+ from pycardano import Address
18
+ from pycardano import Network
19
+ from pycardano import ScriptHash
20
+
21
+ if TYPE_CHECKING:
22
+ from charli3_dendrite.backend.backend_base import AbstractBackend
23
+
24
+ PROTOCOL_CONFIG_NFT_POLICY = "219832152b2c489358f4c02a1818d312a851b1f55774ae881e33a907"
25
+ PROTOCOL_CONFIG_NFT_NAME = "706172616d6574657273" # "parameters"
26
+
27
+ # Mainnet deployment: config-datum field -> hash / policy id.
28
+ POOL_POLICY = "befbcb19919ff8ce5323d123c835da8e7653a098ad482271a72b72f2"
29
+ REQUEST_POLICY = "a37578f027ae878115cc70cd0909ddc855d67b6dd3bd038a757bd221"
30
+ BORROWER_BOND_POLICY = "eadc69a5d2d1357acc9b9d49ec5390fcdf6e080c7a40139917223dcb"
31
+ LENDER_BOND_POLICY = "bcd713bb7858d4b08738bed90ee7068d8f9b38d02e0cae0b45ac7a9b"
32
+ LOAN_POLICY = "30f1095a8a2acb68bb0ffa193e18e004b6dd3e12b5d9c2375a1d5c41"
33
+ REPAYMENT_POLICY = "1fb02a2a8f89d1484141e57bd370587773b3dbd69d45fec93a6b2a94"
34
+
35
+ POOL_SPEND_SKH = "ad353a777c817f4d9d6c4324930f5c6128400517ec9dae0461e034cd"
36
+ REQUEST_SPEND_SKH = "dc9003272dbd7fc5d19ce4f0eb3a92bec2c4ffcbd58c8ce4493888bc"
37
+ LOAN_SPEND_SKH = "5abbaa2eb177b574707fa3617e3436295d45d7795e0874623a9504da"
38
+ LOAN_CLAIM_ACTION_SKH = "79cc329af69d79ba85f56a04c0e8512306eb7ed98a5bd0c878485910"
39
+ LOAN_REPAY_ACTION_SKH = "5fcd23d021add45fdb25e8c7c674d6e2dbc445feafe246c5a0fab02f"
40
+ LOAN_CHANGE_COLLATERAL_ACTION_SKH = (
41
+ "6ca3b95015bbef6237db91322132ebd3ac0c3850f79096eb6f42e1af"
42
+ )
43
+ LOAN_RECAST_ACTION_SKH = "696d17c79d1276945d0e96d2368a7c48b431afbe880c008da8fee0f2"
44
+ ASSET_MANAGER_SPEND_SKH = "e20678c018fe01a9b0d116a5a1bfa57e2efe8520645ca303d2c26a0e"
45
+
46
+ # Mainnet bech32 addresses where each entity's UTxOs live (payment cred = the
47
+ # general_spend instance for that entity; stake part carries the action withdraw cred).
48
+ POOL_ADDRESS = "addr1zxkn2wnh0jqh7nvad3pjfyc0t3sjssq9zlkfmtsyv8srfnfhmnz9plgputfxf9gqn86lwgyk0qu3n59haevkkdx0klmqspeu5h" # noqa: E501
49
+ LOAN_ADDRESS = "addr1z9dth23wk9mm2ars073kzl35xc5463wh090qsarz822sfksvadkn2cntfnulwwvs7nq44jmrlzdfhtyvate92x7k67ysyhqtnf" # noqa: E501
50
+ REQUEST_ADDRESS = "addr1z8wfqqe89k7hl3w3nnj0p6e6j2lv938le02cer8yfyug30xfmmkg85yfq8c7nrysz63g2sq8ttmt8gn7jmgfqy995d4s48shzc" # noqa: E501
51
+
52
+
53
+ class FluidScriptAddresses(TypedDict):
54
+ """Resolved entity coordinates used by the loader/builder."""
55
+
56
+ pool: str
57
+ loan: str
58
+ request: str
59
+ pool_policy: str
60
+ loan_policy: str
61
+ request_policy: str
62
+
63
+
64
+ # Config datum layout: Constr(0, [ ... ]). Fields 0-1 are governance credentials; 2-15
65
+ # are the policy ids / script hashes below; 16-21 are reserved (currently empty / zero).
66
+ _CONFIG_CONSTR_0 = 121
67
+ _CONFIG_MIN_FIELDS = 16
68
+ _CONFIG_FIELD_IX = {
69
+ "pool_policy": 2,
70
+ "request_policy": 3,
71
+ "borrower_bond_policy": 4,
72
+ "lender_bond_policy": 5,
73
+ "loan_policy": 6,
74
+ "repayment_policy": 7,
75
+ "pool_spend_skh": 8,
76
+ "request_spend_skh": 9,
77
+ "loan_spend_skh": 10,
78
+ "loan_claim_action_skh": 11,
79
+ "loan_repay_action_skh": 12,
80
+ "loan_change_collateral_action_skh": 13,
81
+ "loan_recast_action_skh": 14,
82
+ "asset_manager_spend_skh": 15,
83
+ }
84
+
85
+
86
+ @dataclass(frozen=True)
87
+ class FluidConfig:
88
+ """The protocol policy ids / script hashes carried by the config NFT datum.
89
+
90
+ Every field is a hex hash. :meth:`parse` decodes the on-chain config datum;
91
+ :meth:`defaults` returns the static mainnet constants defined in this module, used
92
+ as a fallback when the live datum cannot be read.
93
+ """
94
+
95
+ pool_policy: str
96
+ request_policy: str
97
+ borrower_bond_policy: str
98
+ lender_bond_policy: str
99
+ loan_policy: str
100
+ repayment_policy: str
101
+ pool_spend_skh: str
102
+ request_spend_skh: str
103
+ loan_spend_skh: str
104
+ loan_claim_action_skh: str
105
+ loan_repay_action_skh: str
106
+ loan_change_collateral_action_skh: str
107
+ loan_recast_action_skh: str
108
+ asset_manager_spend_skh: str
109
+
110
+ @classmethod
111
+ def parse(cls, datum_cbor: str) -> FluidConfig:
112
+ """Decode the config NFT datum cbor-hex into a :class:`FluidConfig`.
113
+
114
+ Reads the known policy/script-hash fields (2-15) and tolerates the reserved
115
+ tail (16+). Raises :class:`ValueError` if the datum is not the expected
116
+ ``Constr(0, [...])`` with at least the known fields, all bytes.
117
+ """
118
+ try:
119
+ top = cbor2.loads(bytes.fromhex(datum_cbor))
120
+ except (ValueError, cbor2.CBORDecodeError) as exc:
121
+ raise ValueError(f"config datum: undecodable cbor: {exc}") from exc
122
+ if not isinstance(top, cbor2.CBORTag) or top.tag != _CONFIG_CONSTR_0:
123
+ raise ValueError("config datum: expected Constr(0, ...)")
124
+ fields = top.value
125
+ if not isinstance(fields, list) or len(fields) < _CONFIG_MIN_FIELDS:
126
+ raise ValueError(
127
+ f"config datum: expected >= {_CONFIG_MIN_FIELDS} fields",
128
+ )
129
+
130
+ def _hash(name: str) -> str:
131
+ value = fields[_CONFIG_FIELD_IX[name]]
132
+ if not isinstance(value, bytes):
133
+ raise ValueError(f"config datum: field {name} is not bytes")
134
+ return value.hex()
135
+
136
+ return cls(**{name: _hash(name) for name in _CONFIG_FIELD_IX})
137
+
138
+ @classmethod
139
+ def defaults(cls) -> FluidConfig:
140
+ """The static mainnet constants defined in this module."""
141
+ return cls(
142
+ pool_policy=POOL_POLICY,
143
+ request_policy=REQUEST_POLICY,
144
+ borrower_bond_policy=BORROWER_BOND_POLICY,
145
+ lender_bond_policy=LENDER_BOND_POLICY,
146
+ loan_policy=LOAN_POLICY,
147
+ repayment_policy=REPAYMENT_POLICY,
148
+ pool_spend_skh=POOL_SPEND_SKH,
149
+ request_spend_skh=REQUEST_SPEND_SKH,
150
+ loan_spend_skh=LOAN_SPEND_SKH,
151
+ loan_claim_action_skh=LOAN_CLAIM_ACTION_SKH,
152
+ loan_repay_action_skh=LOAN_REPAY_ACTION_SKH,
153
+ loan_change_collateral_action_skh=LOAN_CHANGE_COLLATERAL_ACTION_SKH,
154
+ loan_recast_action_skh=LOAN_RECAST_ACTION_SKH,
155
+ asset_manager_spend_skh=ASSET_MANAGER_SPEND_SKH,
156
+ )
157
+
158
+
159
+ def _payment_address(script_hash_hex: str) -> str:
160
+ """A mainnet payment-credential (enterprise) address for a spend script hash.
161
+
162
+ Entity UTxOs sit at base addresses whose stake part is not carried by the config
163
+ datum, but the backend discovers them by payment credential only, so a
164
+ payment-credential address is the stable, redeploy-proof identity to match on.
165
+ """
166
+ return Address(
167
+ payment_part=ScriptHash(bytes.fromhex(script_hash_hex)),
168
+ network=Network.MAINNET,
169
+ ).encode()
170
+
171
+
172
+ def resolve_config(backend: AbstractBackend) -> FluidConfig:
173
+ """Read the live config NFT datum into a :class:`FluidConfig`.
174
+
175
+ Falls back to :meth:`FluidConfig.defaults` when the datum cannot be read or parsed
176
+ (e.g. a non-dbsync backend, a missing config UTxO, or an unexpected datum shape) so
177
+ the loader keeps working offline / against a degraded backend.
178
+ """
179
+ try:
180
+ # Imported lazily: `resolve` imports this module, so a top-level import cycles.
181
+ from charli3_dendrite.lending.fluidtokens.transactions.resolve import (
182
+ resolve_config_utxo,
183
+ )
184
+
185
+ utxo = resolve_config_utxo(backend)
186
+ return FluidConfig.parse(utxo.datum)
187
+ except (TypeError, ValueError, IndexError, KeyError, AttributeError):
188
+ return FluidConfig.defaults()
189
+
190
+
191
+ def resolve_addresses(backend: AbstractBackend) -> FluidScriptAddresses:
192
+ """Resolve the entity coordinate set, preferring the live config NFT datum.
193
+
194
+ Re-reads the config datum through `backend` so pool / loan / request discovery
195
+ self-heals across a protocol redeploy (new spend scripts / policies); falls back to
196
+ the static mainnet constants when the datum cannot be read. Addresses are
197
+ payment-credential identities (see :func:`_payment_address`).
198
+ """
199
+ config = resolve_config(backend)
200
+ return FluidScriptAddresses(
201
+ pool=_payment_address(config.pool_spend_skh),
202
+ loan=_payment_address(config.loan_spend_skh),
203
+ request=_payment_address(config.request_spend_skh),
204
+ pool_policy=config.pool_policy,
205
+ loan_policy=config.loan_policy,
206
+ request_policy=config.request_policy,
207
+ )
@@ -0,0 +1,232 @@
1
+ """pycardano mirrors of the deployed FluidTokens V3 datums (mainnet)."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+ from typing import TypeAlias
7
+
8
+ from pycardano import Datum
9
+ from pycardano import IndefiniteList
10
+ from pycardano import PlutusData
11
+
12
+ from charli3_dendrite.lending.units import asset_unit
13
+
14
+
15
+ @dataclass
16
+ class Asset(PlutusData):
17
+ """(policy_id, asset_name) as a `Constr`; ADA is (b"", b"")."""
18
+
19
+ CONSTR_ID = 0
20
+ policy_id: bytes
21
+ asset_name: bytes
22
+
23
+ def unit(self) -> str:
24
+ """Dendrite unit string ('lovelace' for ADA)."""
25
+ return asset_unit(self.policy_id, self.asset_name)
26
+
27
+
28
+ @dataclass
29
+ class CollateralAsset(PlutusData):
30
+ """A collateral type: policy, optional asset name, and its oracle token."""
31
+
32
+ CONSTR_ID = 0
33
+ policy_id: bytes
34
+ maybe_asset_name: Datum # Option<AssetName>: Constr0([name]) / Constr1([])
35
+ oracle_token_asset: Asset
36
+
37
+
38
+ @dataclass
39
+ class NoLiquidationFullCollateralClaim(PlutusData):
40
+ """LiquidationMode variant: on default the lender claims all collateral."""
41
+
42
+ CONSTR_ID = 0
43
+
44
+
45
+ @dataclass
46
+ class NoLiquidationDutchAuctionClaim(PlutusData):
47
+ """LiquidationMode variant: on default the collateral is dutch-auctioned."""
48
+
49
+ CONSTR_ID = 1
50
+
51
+
52
+ @dataclass
53
+ class Liquidation(PlutusData):
54
+ """LiquidationMode variant: liquidate against a loan-to-value threshold.
55
+
56
+ Three fields, matching the deployed datum and `ft-cardano-loans-v3` lib
57
+ (`general.ak`): the LTV is ``l_tv / l_tv_divider``, and the sign of
58
+ ``partial_liquidation_penalty_per_mille`` encodes the borrower-equity rule
59
+ (``< 0`` the borrower loses all collateral; ``>= 0`` the lender pays back the
60
+ difference; ``> 0`` that per-mille of the debt is kept as a penalty).
61
+ """
62
+
63
+ CONSTR_ID = 2
64
+ l_tv: int
65
+ l_tv_divider: int
66
+ partial_liquidation_penalty_per_mille: int
67
+
68
+
69
+ @dataclass
70
+ class InterestOnRemainingPrincipal(PlutusData):
71
+ """RepaymentMode variant: interest accrues on the remaining principal."""
72
+
73
+ CONSTR_ID = 0
74
+ max_possible_recasts: int
75
+
76
+
77
+ @dataclass
78
+ class PrincipalAndInterestOnInstallments(PlutusData):
79
+ """RepaymentMode variant: principal and interest split across installments."""
80
+
81
+ CONSTR_ID = 1
82
+
83
+
84
+ @dataclass
85
+ class PerpetualLoan(PlutusData):
86
+ """RepaymentMode variant: perpetual loan with a linear APY increase."""
87
+
88
+ CONSTR_ID = 2
89
+ apy_increase_linear_coefficient: int
90
+ max_possible_recasts: int
91
+
92
+
93
+ # Unions; parse via from_primitive dispatch where needed.
94
+ LiquidationMode: TypeAlias = Datum
95
+ RepaymentMode: TypeAlias = Datum
96
+
97
+
98
+ @dataclass
99
+ class CommonData(PlutusData):
100
+ """Loan terms shared by pool, request, and loan datums."""
101
+
102
+ CONSTR_ID = 0
103
+ principal_asset: Asset
104
+ principal_oracle_asset: Asset
105
+ interest_rate: int
106
+ installment_period: int
107
+ total_installments: int
108
+ initial_grace_period: int
109
+ liquidation_mode: LiquidationMode
110
+ repayment_mode: RepaymentMode
111
+ repayment_time_window: int
112
+ penalty_fee_for_late_repayment: int
113
+ repayment_receipts: Datum # Bool: Constr0/Constr1
114
+
115
+
116
+ @dataclass
117
+ class AuthCardanoSignature(PlutusData):
118
+ """AuthorizationMethod variant: authorize by a verification-key hash."""
119
+
120
+ CONSTR_ID = 0
121
+ key_hash: bytes
122
+
123
+
124
+ @dataclass
125
+ class AuthCardanoSpendScript(PlutusData):
126
+ """AuthorizationMethod variant: authorize by a spending script hash."""
127
+
128
+ CONSTR_ID = 1
129
+ script_hash: bytes
130
+
131
+
132
+ @dataclass
133
+ class AuthCardanoWithdrawScript(PlutusData):
134
+ """AuthorizationMethod variant: authorize by a withdrawal script hash."""
135
+
136
+ CONSTR_ID = 2
137
+ script_hash: bytes
138
+
139
+
140
+ @dataclass
141
+ class AuthCardanoMintScript(PlutusData):
142
+ """AuthorizationMethod variant: authorize by a minting script hash."""
143
+
144
+ CONSTR_ID = 3
145
+ script_hash: bytes
146
+
147
+
148
+ @dataclass
149
+ class PoolDatum(PlutusData):
150
+ """Deployed PoolDatum — Constr0, 10 fields.
151
+
152
+ ``collateral_options``, ``min_collateral``, and ``min_collateral_divider`` follow
153
+ Plutus list serialization: empty is a definite-length empty array (``80``);
154
+ non-empty is an indefinite-length array (``9f..ff``). A plain ``list`` field
155
+ reproduces the empty case but emits a DEFINITE array when non-empty, diverging
156
+ from on-chain, so ``__post_init__`` rebuilds each non-empty list as an
157
+ ``IndefiniteList`` (coercing decoded raw ``collateral_options`` entries back into
158
+ ``CollateralAsset``).
159
+ """
160
+
161
+ CONSTR_ID = 0
162
+ permissioned_condition_script_hash: bytes
163
+ extra_data: Datum
164
+ common_data: CommonData
165
+ lender_auth: Datum # AuthorizationMethod union
166
+ lender_bond_address: Datum # pycardano Address constr
167
+ lender_bond_inline_datum_hash: bytes
168
+ collateral_options: List[CollateralAsset] | IndefiniteList
169
+ min_collateral: List[int] | IndefiniteList
170
+ min_collateral_divider: List[int] | IndefiniteList
171
+ dynamic_collateral_price: Datum # Bool Constr0/Constr1
172
+
173
+ def __post_init__(self) -> None:
174
+ """Pin the list fields to their conditional on-chain encoding."""
175
+ options = [
176
+ o if isinstance(o, CollateralAsset) else CollateralAsset.from_primitive(o)
177
+ for o in self.collateral_options
178
+ ]
179
+ self.collateral_options = IndefiniteList(options) if options else options
180
+ self.min_collateral = (
181
+ IndefiniteList(list(self.min_collateral))
182
+ if len(self.min_collateral)
183
+ else self.min_collateral
184
+ )
185
+ self.min_collateral_divider = (
186
+ IndefiniteList(list(self.min_collateral_divider))
187
+ if len(self.min_collateral_divider)
188
+ else self.min_collateral_divider
189
+ )
190
+
191
+
192
+ @dataclass
193
+ class LoanDatum(PlutusData):
194
+ """Deployed LoanDatum — Constr0, 17 fields."""
195
+
196
+ CONSTR_ID = 0
197
+ done_recasts: int
198
+ principal_amount: int
199
+ lend_date: int
200
+ repaid_installments: int
201
+ interest_rate: int
202
+ total_installments: int
203
+ principal_asset: Asset
204
+ principal_oracle_asset: Asset
205
+ installment_period: int
206
+ initial_grace_period: int
207
+ liquidation_mode: LiquidationMode
208
+ repayment_mode: RepaymentMode
209
+ repayment_time_window: int
210
+ penalty_fee_for_late_repayment: int
211
+ repayment_receipts: Datum
212
+ origin_id: bytes
213
+ collateral: CollateralAsset
214
+
215
+
216
+ @dataclass
217
+ class RequestDatum(PlutusData):
218
+ """Deployed RequestDatum — Constr0, 12 fields."""
219
+
220
+ CONSTR_ID = 0
221
+ permissioned_condition_script_hash: bytes
222
+ extra_data: Datum
223
+ common_data: CommonData
224
+ borrower_auth: Datum
225
+ borrower_address: Datum
226
+ collateral: CollateralAsset
227
+ min_principal: int
228
+ min_principal_divider: int
229
+ max_principal: int
230
+ dynamic_collateral_price: Datum
231
+ request_expiration: int
232
+ request_expiration_penalty: int