charli3_dendrite 1.6.7.dev0__tar.gz → 1.6.7.dev1__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 (173) hide show
  1. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/PKG-INFO +1 -1
  2. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/pyproject.toml +2 -2
  3. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/dbsync/__init__.py +2 -0
  4. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/builtins.py +20 -0
  5. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/forward.py +72 -15
  6. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/locator.py +2 -0
  7. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/reproduce.py +2 -2
  8. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/_common.py +11 -12
  9. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/fetch.py +58 -0
  10. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/indexing.py +2 -41
  11. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/loader.py +11 -29
  12. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/market.py +21 -25
  13. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/rates.py +2 -17
  14. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/state.py +5 -18
  15. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/datums.py +657 -0
  16. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/deployment.py +926 -0
  17. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/indexing.py +363 -0
  18. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/lifecycle.py +405 -0
  19. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/loader.py +104 -0
  20. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/market.py +459 -0
  21. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/math.py +415 -0
  22. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/oracles.py +327 -0
  23. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/rates.py +179 -0
  24. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/liqwid/registry_v6.json +5739 -0
  25. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/markets.py +151 -17
  26. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/math.py +85 -0
  27. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/normalized.py +176 -18
  28. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/models.py +4 -2
  29. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/oracles/qtoken.py +150 -0
  30. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/rates.py +63 -6
  31. charli3_dendrite-1.6.7.dev1/src/charli3_dendrite/lending/units.py +182 -0
  32. charli3_dendrite-1.6.7.dev0/src/charli3_dendrite/lending/liqwid/datums.py +0 -112
  33. charli3_dendrite-1.6.7.dev0/src/charli3_dendrite/lending/math.py +0 -34
  34. charli3_dendrite-1.6.7.dev0/src/charli3_dendrite/lending/oracles/qtoken.py +0 -50
  35. charli3_dendrite-1.6.7.dev0/src/charli3_dendrite/lending/units.py +0 -83
  36. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/LICENSE +0 -0
  37. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/README.md +0 -0
  38. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/__init__.py +0 -0
  39. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/__init__.py +0 -0
  40. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/backend_base.py +0 -0
  41. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
  42. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
  43. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
  44. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
  45. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
  46. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/backend/utils.py +0 -0
  47. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
  48. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dataclasses/datums.py +0 -0
  49. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dataclasses/models.py +0 -0
  50. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/__init__.py +0 -0
  51. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
  52. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
  53. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
  54. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
  55. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/dano.py +0 -0
  56. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
  57. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
  58. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/multi_asset.py +0 -0
  59. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
  60. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
  61. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
  62. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/sundae_v4.py +0 -0
  63. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/sundae_v4_banded_cl_math.py +0 -0
  64. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/sundae_v4_deployments.json +0 -0
  65. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/sundae_v4_stableswap_math.py +0 -0
  66. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
  67. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
  68. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
  69. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/core/base.py +0 -0
  70. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/core/errors.py +0 -0
  71. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
  72. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
  73. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +0 -0
  74. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
  75. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
  76. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
  77. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
  78. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/dexs/ob/saturnswap.py +0 -0
  79. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/__init__.py +0 -0
  80. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/base.py +0 -0
  81. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/__init__.py +0 -0
  82. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/constants.py +0 -0
  83. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/datums.py +0 -0
  84. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/loader.py +0 -0
  85. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/market.py +0 -0
  86. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/math.py +0 -0
  87. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/__init__.py +0 -0
  88. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/aggregator.py +0 -0
  89. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/aggregator_datums.py +0 -0
  90. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/deployments.py +0 -0
  91. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/leaves.py +0 -0
  92. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/lp_pricing.py +0 -0
  93. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/recipes.json +0 -0
  94. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/redeemer.py +0 -0
  95. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/oracles/structured_datums.py +0 -0
  96. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/state.py +0 -0
  97. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/__init__.py +0 -0
  98. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/build.py +0 -0
  99. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/builder.py +0 -0
  100. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/context.py +0 -0
  101. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/create_loan.py +0 -0
  102. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/datum_synth.py +0 -0
  103. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/increase_loan.py +0 -0
  104. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/loan_ids.py +0 -0
  105. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/modify_collateral.py +0 -0
  106. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/oracle_redeemer.py +0 -0
  107. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/oracle_synth.py +0 -0
  108. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/redeemers.py +0 -0
  109. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/repay.py +0 -0
  110. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/topup_withdraw.py +0 -0
  111. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/danogo/transactions/verify.py +0 -0
  112. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/__init__.py +0 -0
  113. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/constants.py +0 -0
  114. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/datums.py +0 -0
  115. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/loader.py +0 -0
  116. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/market.py +0 -0
  117. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/math.py +0 -0
  118. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/oracles/__init__.py +0 -0
  119. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/oracles/feeds.py +0 -0
  120. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/oracles/fluid_api.py +0 -0
  121. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/oracles/witness.py +0 -0
  122. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/state.py +0 -0
  123. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/__init__.py +0 -0
  124. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/_common.py +0 -0
  125. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow.py +0 -0
  126. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow_terms.py +0 -0
  127. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/builder.py +0 -0
  128. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/change_collateral.py +0 -0
  129. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/context.py +0 -0
  130. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/datum_synth.py +0 -0
  131. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/lend.py +0 -0
  132. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/pool.py +0 -0
  133. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/recast.py +0 -0
  134. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/redeemers.py +0 -0
  135. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/repay.py +0 -0
  136. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/request.py +0 -0
  137. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/resolve.py +0 -0
  138. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens/transactions/utxos.py +0 -0
  139. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/__init__.py +0 -0
  140. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/constants.py +0 -0
  141. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/datums.py +0 -0
  142. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/__init__.py +0 -0
  143. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/borrow.py +0 -0
  144. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/builder.py +0 -0
  145. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/change_collateral.py +0 -0
  146. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/claim.py +0 -0
  147. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/common.py +0 -0
  148. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/lender_bond.py +0 -0
  149. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_action.py +0 -0
  150. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_terms.py +0 -0
  151. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/oracle.py +0 -0
  152. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_action.py +0 -0
  153. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_cancel.py +0 -0
  154. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_create.py +0 -0
  155. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_edit.py +0 -0
  156. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_terms.py +0 -0
  157. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/recast.py +0 -0
  158. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/redeemers.py +0 -0
  159. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/repay.py +0 -0
  160. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/resolve.py +0 -0
  161. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/liqwid/__init__.py +0 -0
  162. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/__init__.py +0 -0
  163. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/charli3.py +0 -0
  164. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/dex_pooled.py +0 -0
  165. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/fluid.py +0 -0
  166. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/oracles/orcfax.py +0 -0
  167. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/plutus.py +0 -0
  168. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/registry.py +0 -0
  169. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/transactions/__init__.py +0 -0
  170. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/transactions/base.py +0 -0
  171. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/transactions/infra.py +0 -0
  172. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/src/charli3_dendrite/lending/transactions/snapshot.py +0 -0
  173. {charli3_dendrite-1.6.7.dev0 → charli3_dendrite-1.6.7.dev1}/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.6.7.dev0
3
+ Version: 1.6.7.dev1
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.6.7-dev0"
3
+ version = "1.6.7-dev1"
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.6.7-dev0"
53
+ current_version = "1.6.7-dev1"
54
54
  parse = """(?x)
55
55
  (?P<major>\\d+)\\.
56
56
  (?P<minor>\\d+)\\.
@@ -214,7 +214,9 @@ AND txo.consumed_by_tx_id IS NULL"""
214
214
  datum_selector += """
215
215
  AND ma.policy = ANY(%(policies)b) AND ma.name = ANY(%(names)b)"""
216
216
 
217
+ # A stable order, so LIMIT / OFFSET pages neither skip nor repeat a row.
217
218
  datum_selector += """
219
+ ORDER BY txo.id
218
220
  LIMIT %(limit)s
219
221
  OFFSET %(offset)s"""
220
222
 
@@ -0,0 +1,20 @@
1
+ """The protocol modules shipped with the lending package, in one table.
2
+
3
+ Each entry names the module that registers a protocol (never its bare package), and
4
+ that module provides:
5
+
6
+ - ``RATE_MODELS: tuple[type[RateModel], ...]``, the protocol's rate models, which
7
+ :mod:`charli3_dendrite.lending.rates` registers on its first lookup; and
8
+ - ``market_source() -> MarketSource``, the protocol's market source, which
9
+ :mod:`charli3_dendrite.lending.markets` registers on its first use.
10
+
11
+ Both registries keep a caller's own registration under the same key. No entry is
12
+ imported until a registry is first used.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ BUILTIN_PROTOCOL_PACKAGES: tuple[str, ...] = (
18
+ "charli3_dendrite.lending.fluidtokens_v4.market",
19
+ "charli3_dendrite.lending.liqwid.market",
20
+ )
@@ -17,8 +17,8 @@ from charli3_dendrite.lending.danogo.oracles.redeemer import OracleUtxoType
17
17
  from charli3_dendrite.lending.danogo.oracles.reproduce import OracleLeaf
18
18
  from charli3_dendrite.lending.danogo.oracles.reproduce import leaf_forward_rates
19
19
  from charli3_dendrite.lending.danogo.oracles.reproduce import splash_lp_candidate
20
- from charli3_dendrite.lending.liqwid.datums import liqwid_oracle_feed_id
21
- from charli3_dendrite.lending.liqwid.datums import parse_liqwid_oracle_v2
20
+ from charli3_dendrite.lending.liqwid.datums import POLICY_KEY_PREFIX
21
+ from charli3_dendrite.lending.liqwid.datums import decode_oracle_feed
22
22
  from charli3_dendrite.lending.oracles.models import OraclePrice
23
23
  from charli3_dendrite.lending.oracles.models import OracleSource
24
24
  from charli3_dendrite.lending.oracles.models import PriceMap
@@ -57,9 +57,10 @@ def leaf_discriminator(otype: str, datum: str | None) -> str:
57
57
  Some source kinds live many-to-one behind a shared marker token at a common
58
58
  address, so the value alone cannot pin a UTxO; a stable datum field can:
59
59
 
60
- * Liqwid V2 oracles -> ``updater_key:priced_asset``. Neither part is unique on
61
- its own (one updater key spans many assets; one asset, e.g. ADA, can have
62
- several feeds), but together they pin the UTxO.
60
+ * Liqwid V2 oracles -> the priced asset's key (``OracleFeedDatum.asset_key``:
61
+ the asset unit, or ``policy:<policy>`` for a policy-wide feed). Each priced
62
+ asset has exactly one unspent feed carrying the oracle token; the updater key
63
+ rotates and is not part of the identity.
63
64
  * Minswap pools -> the ``asset_a|asset_b`` pair (all pools carry one MSP token).
64
65
 
65
66
  Returns "" for kinds already pinned by a unique NFT (no datum disambiguation
@@ -69,7 +70,7 @@ def leaf_discriminator(otype: str, datum: str | None) -> str:
69
70
  return ""
70
71
  try:
71
72
  if otype == OracleUtxoType.TLIQWID_ORACLE_V2.name:
72
- return f"{liqwid_oracle_feed_id(datum)}:{parse_liqwid_oracle_v2(datum)[0]}"
73
+ return decode_oracle_feed(datum).asset_key
73
74
  if otype == OracleUtxoType.TMINSWAP_LP.name:
74
75
  asset_a, _, asset_b, _ = parse_minswap_lp(datum)
75
76
  return f"{asset_a}|{asset_b}"
@@ -78,6 +79,32 @@ def leaf_discriminator(otype: str, datum: str | None) -> str:
78
79
  return ""
79
80
 
80
81
 
82
+ def _handle_key(handle: LeafHandle) -> str:
83
+ """The identity ``handle.datum_key`` pins, in `leaf_discriminator`'s form.
84
+
85
+ A Liqwid oracle key in the earlier ``<updater>:<asset>`` form pins its asset
86
+ part; a ``policy:<policy>`` key is already in the current form.
87
+ """
88
+ key = handle.datum_key
89
+ if handle.otype == OracleUtxoType.TLIQWID_ORACLE_V2.name and not key.startswith(
90
+ POLICY_KEY_PREFIX,
91
+ ):
92
+ return key.rpartition(":")[2]
93
+ return key
94
+
95
+
96
+ def leaf_matches_handle(handle: LeafHandle, datum: str | None) -> bool:
97
+ """Whether a leaf's datum carries the identity ``handle.datum_key`` pins.
98
+
99
+ True for every datum when the handle has no ``datum_key`` (its NFT alone pins
100
+ the UTxO). Otherwise the leaf's `leaf_discriminator` must equal the handle's key;
101
+ a Liqwid oracle key captured as ``<updater>:<asset>`` is compared by its asset.
102
+ """
103
+ if not handle.datum_key:
104
+ return True
105
+ return leaf_discriminator(handle.otype, datum) == _handle_key(handle)
106
+
107
+
81
108
  @dataclass(frozen=True)
82
109
  class LiveLeaf:
83
110
  """A source leaf as currently read on-chain: its parser type, datum, and value."""
@@ -206,6 +233,35 @@ def compose_cross_quote(
206
233
  return collat_price, intermediate_to_quote
207
234
 
208
235
 
236
+ def _leaf_addresses(handle: LeafHandle) -> list[str]:
237
+ """The addresses a handle's leaf is read from.
238
+
239
+ A Liqwid oracle leaf is read at ``handle.address`` and at every Liqwid oracle
240
+ validator of the bundled deployment, captured address first, each address once:
241
+ Liqwid binds a feed by oracle token and asset, whatever its validator, and the
242
+ captured address stays read when the deployment no longer lists it. Every other
243
+ kind is read at ``handle.address`` only.
244
+ """
245
+ if handle.otype != OracleUtxoType.TLIQWID_ORACLE_V2.name:
246
+ return [handle.address]
247
+ # Imported here so that importing this module loads no Liqwid deployment.
248
+ from charli3_dendrite.lending.liqwid.indexing import LiqwidKind
249
+ from charli3_dendrite.lending.liqwid.indexing import liqwid_selectors
250
+
251
+ return list(
252
+ dict.fromkeys(
253
+ [
254
+ handle.address,
255
+ *(
256
+ selector.address
257
+ for selector in liqwid_selectors()
258
+ if selector.kind is LiqwidKind.ORACLE
259
+ ),
260
+ ],
261
+ ),
262
+ )
263
+
264
+
209
265
  def resolve_leaf_info(
210
266
  backend: AbstractBackend,
211
267
  handle: LeafHandle,
@@ -214,7 +270,9 @@ def resolve_leaf_info(
214
270
 
215
271
  A unique identifying NFT yields a single match; kinds that share a marker token
216
272
  across many feeds at one address (e.g. Liqwid V2 oracles) are narrowed by
217
- `handle.datum_key` -- the stable asset-identity parsed from each candidate's datum.
273
+ `handle.datum_key` -- the stable asset-identity parsed from each candidate's datum
274
+ (`leaf_matches_handle`). A Liqwid oracle leaf is looked up at ``handle.address``
275
+ and at every Liqwid oracle validator (`_leaf_addresses`).
218
276
  Returns None unless exactly one UTxO matches, so the caller never reads the wrong
219
277
  feed. This is the shared resolution both `read_live_leaf` (forward pricing) and the
220
278
  create-loan snapshot (full-UTxO assembly) rely on.
@@ -222,18 +280,17 @@ def resolve_leaf_info(
222
280
  want = (handle.nft_policy + handle.nft_name) if handle.nft_policy else None
223
281
  rows = list(
224
282
  backend.get_pool_utxos(
225
- addresses=[handle.address],
283
+ addresses=_leaf_addresses(handle),
226
284
  assets=[want] if want else None,
227
285
  historical=False,
228
286
  ),
229
287
  )
230
- matches = [info for info in rows if want is None or want in info.assets.root]
231
- if handle.datum_key:
232
- matches = [
233
- info
234
- for info in matches
235
- if leaf_discriminator(handle.otype, info.datum_cbor) == handle.datum_key
236
- ]
288
+ matches = [
289
+ info
290
+ for info in rows
291
+ if (want is None or want in info.assets.root)
292
+ and leaf_matches_handle(handle, info.datum_cbor)
293
+ ]
237
294
  if len(matches) != 1:
238
295
  return None
239
296
  return matches[0]
@@ -50,6 +50,8 @@ class LeafHandle:
50
50
  `datum_key` is a further discriminator for kinds that share one marker token across
51
51
  many feeds (e.g. Liqwid V2 oracles): the stable asset-identity parsed from the leaf
52
52
  datum (see `forward.leaf_discriminator`). Empty when the NFT alone pins the UTxO.
53
+ A Liqwid oracle leaf is identified by its token and `datum_key` alone and is read
54
+ at every Liqwid oracle validator; its `address` is where it was captured.
53
55
  """
54
56
 
55
57
  otype: str
@@ -47,8 +47,8 @@ from charli3_dendrite.lending.danogo.oracles.leaves import parse_minswap_lp
47
47
  from charli3_dendrite.lending.danogo.oracles.leaves import parse_splash_cpamm_g3
48
48
  from charli3_dendrite.lending.danogo.oracles.leaves import splash_lp_token_price
49
49
  from charli3_dendrite.lending.danogo.oracles.redeemer import OracleUtxoType
50
+ from charli3_dendrite.lending.liqwid.datums import decode_oracle_feed
50
51
  from charli3_dendrite.lending.liqwid.datums import parse_liqwid_market_state
51
- from charli3_dendrite.lending.liqwid.datums import parse_liqwid_oracle_v2
52
52
 
53
53
  # Liqwid market qToken: the on-chain price divides the field-9 exchange rate by the
54
54
  # underlying's (cent-denominated) price; that constant is folded into the leaf rate so
@@ -96,7 +96,7 @@ def leaf_forward_rates(leaf: OracleLeaf) -> List[Tuple[str, Fraction]]:
96
96
  num, den = parse_danogo_staking_rate(datum)
97
97
  out.append(("stake", Fraction(num, den)))
98
98
  elif leaf.otype == OracleUtxoType.TLIQWID_ORACLE_V2 and datum is not None:
99
- _, (num, den) = parse_liqwid_oracle_v2(datum)
99
+ num, den = decode_oracle_feed(datum).price
100
100
  out.append(("liqv2", Fraction(num, den)))
101
101
  elif leaf.otype == OracleUtxoType.TDJED and datum is not None:
102
102
  _, (num, den) = parse_djed(datum)
@@ -47,7 +47,7 @@ from charli3_dendrite.lending.danogo.oracles.deployments import (
47
47
  from charli3_dendrite.lending.danogo.oracles.forward import INTERMEDIATE_QUOTE
48
48
  from charli3_dendrite.lending.danogo.oracles.forward import LiveLeaf
49
49
  from charli3_dendrite.lending.danogo.oracles.forward import compose_cross_quote
50
- from charli3_dendrite.lending.danogo.oracles.forward import leaf_discriminator
50
+ from charli3_dendrite.lending.danogo.oracles.forward import leaf_matches_handle
51
51
  from charli3_dendrite.lending.danogo.oracles.forward import replay_recipe
52
52
  from charli3_dendrite.lending.danogo.oracles.leaves import parse_orcfax_fs
53
53
  from charli3_dendrite.lending.danogo.oracles.locator import Recipe
@@ -145,18 +145,17 @@ def _leaf_for_handle(leaves: list[Utxo], handle: LeafHandle) -> Utxo | None:
145
145
  """Find the resolved source leaf a recipe step's handle points at.
146
146
 
147
147
  Matches by the handle's identifying NFT (policy + name) and, when present, the
148
- datum discriminator that pins kinds sharing one marker token across many feeds.
148
+ datum discriminator that pins kinds sharing one marker token across many feeds
149
+ (`leaf_matches_handle`, as `resolve_leaf_info`). None unless exactly one leaf
150
+ matches.
149
151
  """
150
- for u in leaves:
151
- if handle.nft_policy and not u.holds(handle.nft_policy, handle.nft_name):
152
- continue
153
- if (
154
- handle.datum_key
155
- and leaf_discriminator(handle.otype, u.datum) != handle.datum_key
156
- ):
157
- continue
158
- return u
159
- return None
152
+ matches = [
153
+ u
154
+ for u in leaves
155
+ if (not handle.nft_policy or u.holds(handle.nft_policy, handle.nft_name))
156
+ and leaf_matches_handle(handle, u.datum)
157
+ ]
158
+ return matches[0] if len(matches) == 1 else None
160
159
 
161
160
 
162
161
  def _resolve_recipe(
@@ -0,0 +1,58 @@
1
+ """Backend reads shared by the protocol loaders.
2
+
3
+ A protocol loader fetches every unspent UTxO at a script address and classifies each
4
+ row with its own parser; the paging, the out-ref de-duplication and the default
5
+ evaluation time are the same for every protocol and live here.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import time
11
+ from typing import TYPE_CHECKING
12
+ from typing import Final
13
+
14
+ if TYPE_CHECKING:
15
+ from charli3_dendrite.backend.backend_base import AbstractBackend
16
+ from charli3_dendrite.dataclasses.models import PoolStateInfo
17
+
18
+ PAGE_SIZE: Final[int] = 1000
19
+
20
+
21
+ def unspent_utxos(
22
+ backend: AbstractBackend,
23
+ address: str,
24
+ *,
25
+ page_size: int = PAGE_SIZE,
26
+ ) -> list[PoolStateInfo]:
27
+ """Every unspent UTxO the backend returns for ``address``, once per out-ref.
28
+
29
+ Pages through ``get_pool_utxos`` and terminates on a short page or on a page that
30
+ adds no new out-ref, so a backend that ignores ``page`` and returns the same rows
31
+ again ends the loop. Rows are de-duplicated by out-ref, keeping the first row
32
+ returned, since the backend pages with LIMIT / OFFSET. Rows keep the backend's
33
+ order.
34
+ """
35
+ rows_by_ref: dict[tuple[str, int], PoolStateInfo] = {}
36
+ page = 0
37
+ while True:
38
+ rows = list(
39
+ backend.get_pool_utxos(
40
+ addresses=[address],
41
+ limit=page_size,
42
+ page=page,
43
+ historical=False,
44
+ ),
45
+ )
46
+ before = len(rows_by_ref)
47
+ for info in rows:
48
+ rows_by_ref.setdefault((info.tx_hash, info.tx_index), info)
49
+ if len(rows) < page_size or len(rows_by_ref) == before:
50
+ return list(rows_by_ref.values())
51
+ page += 1
52
+
53
+
54
+ def resolve_now_ms(now_ms: int | None) -> int:
55
+ """``now_ms`` (POSIX ms), or the current time when it is None."""
56
+ if now_ms is None:
57
+ return int(time.time() * 1000)
58
+ return now_ms
@@ -13,13 +13,6 @@ from dataclasses import dataclass
13
13
  from enum import Enum
14
14
  from typing import Union
15
15
 
16
- import cbor2 # type: ignore[import-not-found]
17
- from pycardano import Address
18
- from pycardano import ScriptHash
19
- from pycardano.exception import DecodingException
20
- from pycardano.exception import DeserializeException
21
- from pycardano.exception import InvalidAddressInputException
22
-
23
16
  from charli3_dendrite.dataclasses.models import PoolSelector
24
17
  from charli3_dendrite.dataclasses.models import PoolStateInfo
25
18
  from charli3_dendrite.lending.fluidtokens_v4 import constants as c
@@ -32,6 +25,8 @@ from charli3_dendrite.lending.fluidtokens_v4.state import FluidV4PoolManagerStat
32
25
  from charli3_dendrite.lending.fluidtokens_v4.state import FluidV4PoolState
33
26
  from charli3_dendrite.lending.fluidtokens_v4.state import FluidV4RequestState
34
27
  from charli3_dendrite.lending.fluidtokens_v4.state import identity_name
28
+ from charli3_dendrite.lending.units import DECODE_ERRORS
29
+ from charli3_dendrite.lending.units import script_credential
35
30
  from charli3_dendrite.lending.units import script_payment_address
36
31
 
37
32
  FluidV4State = Union[
@@ -67,18 +62,6 @@ _STATE_CLASS: dict[EntityKind, type[FluidV4State]] = {
67
62
  EntityKind.LOCKED_BORROWER_MANAGER: FluidV4LockedBorrowerState,
68
63
  }
69
64
 
70
- # Everything a malformed record can raise while its datum is decoded. Truncated CBOR
71
- # raises cbor2's end-of-stream error, which is not a ValueError.
72
- DECODE_ERRORS = (
73
- cbor2.CBORDecodeError,
74
- DeserializeException,
75
- ValueError,
76
- TypeError,
77
- KeyError,
78
- IndexError,
79
- AttributeError,
80
- )
81
-
82
65
 
83
66
  @dataclass(frozen=True)
84
67
  class EntitySelector:
@@ -138,28 +121,6 @@ def entity_selectors(
138
121
  }
139
122
 
140
123
 
141
- def script_credential(address: str) -> str | None:
142
- """Payment script hash (hex) of a bech32 address; None for any other address.
143
-
144
- Every V4 entity sits at a script credential, so a key-hash payment part (even one
145
- whose bytes equal a V4 script hash) returns None, as does an unparseable address.
146
- pycardano asserts key-hash sizes and decodes a bech32 Byron header as CBOR, so a
147
- malformed address can also raise ``AssertionError`` or ``DeserializeException``.
148
- """
149
- try:
150
- part = Address.decode(address).payment_part
151
- except (
152
- AssertionError,
153
- DecodingException,
154
- DeserializeException,
155
- InvalidAddressInputException,
156
- TypeError,
157
- ValueError,
158
- ):
159
- return None
160
- return part.payload.hex() if isinstance(part, ScriptHash) else None
161
-
162
-
163
124
  def parse_utxo(
164
125
  info: PoolStateInfo,
165
126
  selectors: Mapping[EntityKind, EntitySelector] | None = None,
@@ -12,12 +12,14 @@ that matches exact addresses the snapshot comes back empty.
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
- import time
16
15
  from dataclasses import dataclass
17
16
  from typing import TYPE_CHECKING
18
17
  from typing import TypeVar
19
18
 
20
19
  from charli3_dendrite.lending.base import LendingBook
20
+ from charli3_dendrite.lending.fetch import PAGE_SIZE
21
+ from charli3_dendrite.lending.fetch import resolve_now_ms
22
+ from charli3_dendrite.lending.fetch import unspent_utxos
21
23
  from charli3_dendrite.lending.fluidtokens_v4.constants import resolve_config
22
24
  from charli3_dendrite.lending.fluidtokens_v4.indexing import EntityKind
23
25
  from charli3_dendrite.lending.fluidtokens_v4.indexing import EntitySelector
@@ -37,8 +39,6 @@ if TYPE_CHECKING:
37
39
  from charli3_dendrite.lending.fluidtokens_v4.datums import ConfigDatum
38
40
  from charli3_dendrite.lending.oracles.models import PriceMap
39
41
 
40
- PAGE_SIZE = 1000
41
-
42
42
  _T = TypeVar("_T")
43
43
 
44
44
 
@@ -50,33 +50,16 @@ def fetch_entities(
50
50
  ) -> list[FluidV4State]:
51
51
  """Every unspent UTxO at ``selector``'s credential that parses as its kind.
52
52
 
53
- Pages through ``get_pool_utxos`` and terminates on a short page or on a page that
54
- adds no new out-ref, so a backend that ignores ``page`` and returns the same rows
55
- again ends the loop. Pages are de-duplicated by out-ref, since the backend pages
56
- with LIMIT / OFFSET. Sorted by out-ref.
53
+ The rows are those of :func:`~charli3_dendrite.lending.fetch.unspent_utxos`: every
54
+ page, once per out-ref. Sorted by out-ref.
57
55
  """
58
56
  only = {selector.kind: selector}
59
57
  found: dict[str, FluidV4State] = {}
60
- seen: set[tuple[str, int]] = set()
61
- page = 0
62
- while True:
63
- rows = list(
64
- backend.get_pool_utxos(
65
- addresses=[selector.address],
66
- limit=page_size,
67
- page=page,
68
- historical=False,
69
- ),
70
- )
71
- before = len(seen)
72
- for info in rows:
73
- seen.add((info.tx_hash, info.tx_index))
74
- state = parse_utxo(info, only)
75
- if state is not None:
76
- found.setdefault(state.out_ref, state)
77
- if len(rows) < page_size or len(seen) == before:
78
- return [found[ref] for ref in sorted(found)]
79
- page += 1
58
+ for info in unspent_utxos(backend, selector.address, page_size=page_size):
59
+ state = parse_utxo(info, only)
60
+ if state is not None:
61
+ found.setdefault(state.out_ref, state)
62
+ return [found[ref] for ref in sorted(found)]
80
63
 
81
64
 
82
65
  def link_loans(
@@ -134,8 +117,7 @@ def snapshot(
134
117
 
135
118
  ``now_ms`` (POSIX ms) is the loans' evaluation time; it defaults to now.
136
119
  """
137
- if now_ms is None:
138
- now_ms = int(time.time() * 1000)
120
+ now_ms = resolve_now_ms(now_ms)
139
121
  config = resolve_config(backend)
140
122
  fetched = {
141
123
  kind: fetch_entities(backend, selector)
@@ -7,7 +7,6 @@ number comes from the datum and the contract-exact maths.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- import time
11
10
  from fractions import Fraction
12
11
  from typing import TYPE_CHECKING
13
12
  from typing import Any
@@ -22,6 +21,7 @@ from charli3_dendrite.lending.fluidtokens_v4.indexing import EntityKind
22
21
  from charli3_dendrite.lending.fluidtokens_v4.indexing import entity_selectors
23
22
  from charli3_dendrite.lending.fluidtokens_v4.indexing import parse_utxo
24
23
  from charli3_dendrite.lending.fluidtokens_v4.rates import PROTOCOL_NAME
24
+ from charli3_dendrite.lending.fluidtokens_v4.rates import RATE_MODELS # noqa: F401
25
25
  from charli3_dendrite.lending.fluidtokens_v4.rates import FluidAmortizedRate
26
26
  from charli3_dendrite.lending.fluidtokens_v4.rates import FluidFlatTermRate
27
27
  from charli3_dendrite.lending.fluidtokens_v4.rates import FluidPerpetualRate
@@ -37,6 +37,7 @@ from charli3_dendrite.lending.fluidtokens_v4.state import names_under
37
37
  from charli3_dendrite.lending.fluidtokens_v4.transactions.oracle import has_oracle
38
38
  from charli3_dendrite.lending.markets import LendingSnapshot
39
39
  from charli3_dendrite.lending.markets import WatchSpec
40
+ from charli3_dendrite.lending.markets import convertible_views
40
41
  from charli3_dendrite.lending.normalized import BorrowRequest
41
42
  from charli3_dendrite.lending.normalized import CollateralHolding
42
43
  from charli3_dendrite.lending.normalized import CollateralTerms
@@ -47,6 +48,7 @@ from charli3_dendrite.lending.normalized import LendingPosition
47
48
  from charli3_dendrite.lending.normalized import Origin
48
49
  from charli3_dendrite.lending.normalized import Party
49
50
  from charli3_dendrite.lending.normalized import PartyKind
51
+ from charli3_dendrite.lending.normalized import as_parse_error
50
52
  from charli3_dendrite.lending.oracles.models import OracleRef
51
53
  from charli3_dendrite.lending.oracles.models import OracleSource
52
54
  from charli3_dendrite.lending.units import constr
@@ -58,6 +60,8 @@ if TYPE_CHECKING:
58
60
  from charli3_dendrite.lending.fluidtokens_v4.datums import CollateralAsset
59
61
  from charli3_dendrite.lending.fluidtokens_v4.datums import ConfigDatum
60
62
  from charli3_dendrite.lending.fluidtokens_v4.state import FluidV4PoolManagerState
63
+ from charli3_dendrite.lending.markets import ParseContext
64
+ from charli3_dendrite.lending.markets import PositionLifecycle
61
65
  from charli3_dendrite.lending.rates import RateModel
62
66
 
63
67
  # Constructor alternatives of RepaymentMode, LiquidationMode and Option.
@@ -212,12 +216,6 @@ def lendable_principal(pool: FluidV4PoolState) -> int:
212
216
  return max(pool.assets["lovelace"] - floor, 0)
213
217
 
214
218
 
215
- def _converted(what: str, exc: Exception) -> LendingParseError:
216
- if isinstance(exc, LendingParseError):
217
- return exc
218
- return LendingParseError(f"{what}: {exc}")
219
-
220
-
221
219
  def pool_to_market(
222
220
  pool: FluidV4PoolState,
223
221
  pool_manager: FluidV4PoolManagerState | None = None,
@@ -267,7 +265,7 @@ def pool_to_market(
267
265
  permissioned=pool.is_permissioned,
268
266
  )
269
267
  except _CONVERSION_ERRORS as exc:
270
- raise _converted(f"pool {pool.out_ref}", exc) from exc
268
+ raise as_parse_error(f"pool {pool.out_ref}", exc) from exc
271
269
 
272
270
 
273
271
  def _origin(loan: FluidV4LoanState) -> Origin | None:
@@ -303,7 +301,7 @@ def loan_to_position(loan: FluidV4LoanState) -> LendingPosition:
303
301
  opened_ms=int(datum.lend_date), # type: ignore[attr-defined]
304
302
  )
305
303
  except _CONVERSION_ERRORS as exc:
306
- raise _converted(f"loan {loan.out_ref}", exc) from exc
304
+ raise as_parse_error(f"loan {loan.out_ref}", exc) from exc
307
305
 
308
306
 
309
307
  def request_to_borrow_request(request: FluidV4RequestState) -> BorrowRequest:
@@ -343,7 +341,7 @@ def request_to_borrow_request(request: FluidV4RequestState) -> BorrowRequest:
343
341
  != PERMISSIONLESS_MARKER,
344
342
  )
345
343
  except _CONVERSION_ERRORS as exc:
346
- raise _converted(f"request {request.out_ref}", exc) from exc
344
+ raise as_parse_error(f"request {request.out_ref}", exc) from exc
347
345
 
348
346
 
349
347
  _VIEW_KINDS = (EntityKind.POOL, EntityKind.LOAN, EntityKind.REQUEST)
@@ -353,6 +351,8 @@ class FluidTokensV4MarketSource:
353
351
  """FluidTokens V4 pools, loans and requests as common views."""
354
352
 
355
353
  name = PROTOCOL_NAME
354
+ # Every V4 loan holds its own identity token, so positions need no chaining.
355
+ lifecycle: PositionLifecycle | None = None
356
356
 
357
357
  def __init__(self, config: ConfigDatum | None = None) -> None:
358
358
  """Watch the deployment ``config`` names; mainnet by default."""
@@ -369,9 +369,13 @@ class FluidTokensV4MarketSource:
369
369
  def parse(
370
370
  self,
371
371
  info: PoolStateInfo,
372
+ *,
373
+ context: ParseContext | None = None,
372
374
  ) -> LendingMarket | LendingPosition | BorrowRequest | None:
373
375
  """One UTxO as its view; None when it is not a V4 pool, loan or request.
374
376
 
377
+ A V4 view reads only its own UTxO, so ``context`` is ignored.
378
+
375
379
  Raises LendingParseError for a pool, loan or request it cannot convert.
376
380
  """
377
381
  state = parse_utxo(info, self._selectors)
@@ -394,26 +398,18 @@ class FluidTokensV4MarketSource:
394
398
  """
395
399
  from charli3_dendrite.lending.fluidtokens_v4.loader import snapshot
396
400
 
397
- found = snapshot(
398
- backend,
399
- now_ms=int(time.time() * 1000) if now_ms is None else now_ms,
400
- )
401
+ found = snapshot(backend, now_ms=now_ms)
401
402
  managers = {manager.pool_id: manager for manager in found.pool_managers}
402
403
  return LendingSnapshot(
403
- markets=_convertible(
404
+ markets=convertible_views(
404
405
  lambda pool: pool_to_market(pool, managers.get(pool.pool_id)),
405
406
  found.pools,
406
407
  ),
407
- positions=_convertible(loan_to_position, found.loans),
408
- requests=_convertible(request_to_borrow_request, found.requests),
408
+ positions=convertible_views(loan_to_position, found.loans),
409
+ requests=convertible_views(request_to_borrow_request, found.requests),
409
410
  )
410
411
 
411
412
 
412
- def _convertible(convert: Any, states: list[Any]) -> tuple[Any, ...]: # noqa: ANN401
413
- out = []
414
- for state in states:
415
- try:
416
- out.append(convert(state))
417
- except LendingParseError:
418
- continue
419
- return tuple(out)
413
+ def market_source() -> FluidTokensV4MarketSource:
414
+ """The mainnet FluidTokens V4 source, as ``lending.builtins`` registers it."""
415
+ return FluidTokensV4MarketSource()
@@ -12,12 +12,9 @@ headline rate annualizes it over the term.
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
- import dataclasses
16
15
  from abc import abstractmethod
17
16
  from dataclasses import dataclass
18
17
  from fractions import Fraction
19
- from typing import TYPE_CHECKING
20
- from typing import Any
21
18
  from typing import ClassVar
22
19
 
23
20
  from charli3_dendrite.lending.fluidtokens.math import amortization_installment
@@ -28,19 +25,17 @@ from charli3_dendrite.lending.fluidtokens.math import perpetual_debt
28
25
  from charli3_dendrite.lending.fluidtokens.math import perpetual_outstanding_debt
29
26
  from charli3_dendrite.lending.normalized import LendingParseError
30
27
  from charli3_dendrite.lending.rates import HOURS_PER_YEAR
28
+ from charli3_dendrite.lending.rates import DataclassIntParams
31
29
  from charli3_dendrite.lending.rates import RateKind
32
30
  from charli3_dendrite.lending.rates import RateModel
33
31
 
34
- if TYPE_CHECKING:
35
- from collections.abc import Mapping
36
-
37
32
  PROTOCOL_NAME = "FluidTokensV4"
38
33
 
39
34
  _RATE_BASIS = 10_000
40
35
 
41
36
 
42
37
  @dataclass(frozen=True)
43
- class _FluidRate(RateModel):
38
+ class _FluidRate(DataclassIntParams):
44
39
  """Terms every FluidTokens repayment mode carries."""
45
40
 
46
41
  interest_rate: int
@@ -69,16 +64,6 @@ class _FluidRate(RateModel):
69
64
  repayment_time_window=self.repayment_time_window,
70
65
  )
71
66
 
72
- def params(self) -> dict[str, int]:
73
- """The datum integers, by field name."""
74
- return dataclasses.asdict(self)
75
-
76
- @classmethod
77
- def from_params(cls, params: Mapping[str, Any]) -> RateModel:
78
- """Rebuild from :meth:`params`."""
79
- names = [field.name for field in dataclasses.fields(cls)]
80
- return cls(**{name: int(params[name]) for name in names})
81
-
82
67
 
83
68
  @dataclass(frozen=True)
84
69
  class FluidPerpetualRate(_FluidRate):