charli3_dendrite 1.5.8.dev0__tar.gz → 1.5.9.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/PKG-INFO +1 -1
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/pyproject.toml +2 -2
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/dano.py +138 -44
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/loader.py +48 -11
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/forward.py +0 -4
- charli3_dendrite-1.5.9.dev0/src/charli3_dendrite/lending/danogo/oracles/locator.py +300 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/state.py +1 -1
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/state.py +2 -2
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/models.py +49 -13
- charli3_dendrite-1.5.8.dev0/src/charli3_dendrite/lending/danogo/oracles/locator.py +0 -140
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/LICENSE +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/README.md +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/constants.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/datums.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/market.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/math.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator_datums.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/deployments.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/leaves.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/lp_pricing.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/recipes.json +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/redeemer.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/reproduce.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/oracles/structured_datums.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/build.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/context.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/create_loan.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/increase_loan.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/loan_ids.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/modify_collateral.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_redeemer.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_synth.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/topup_withdraw.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/danogo/transactions/verify.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/constants.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/datums.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/loader.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/market.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/math.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/feeds.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/fluid_api.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/witness.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/change_collateral.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/context.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/lend.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/pool.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/recast.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/request.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/resolve.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/math.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/charli3.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/dex_pooled.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/fluid.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/orcfax.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/oracles/qtoken.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/registry.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/transactions/base.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/transactions/infra.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/transactions/snapshot.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/lending/units.py +0 -0
- {charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/utility.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "charli3_dendrite"
|
|
3
|
-
version = "1.5.
|
|
3
|
+
version = "1.5.9-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.
|
|
53
|
+
current_version = "1.5.9-dev0"
|
|
54
54
|
parse = """(?x)
|
|
55
55
|
(?P<major>\\d+)\\.
|
|
56
56
|
(?P<minor>\\d+)\\.
|
{charli3_dendrite-1.5.8.dev0 → charli3_dendrite-1.5.9.dev0}/src/charli3_dendrite/dexs/amm/dano.py
RENAMED
|
@@ -35,8 +35,10 @@ from pycardano import TransactionId
|
|
|
35
35
|
from pycardano import TransactionInput
|
|
36
36
|
from pycardano import TransactionOutput
|
|
37
37
|
from pycardano import UTxO
|
|
38
|
+
from pycardano import Value
|
|
38
39
|
from pycardano import Withdrawals
|
|
39
40
|
from pycardano import plutus_script_hash
|
|
41
|
+
from pycardano.serialization import ByteString
|
|
40
42
|
from pycardano.serialization import CBORSerializable
|
|
41
43
|
|
|
42
44
|
from charli3_dendrite.backend import get_backend
|
|
@@ -204,19 +206,44 @@ def parse_swap_redeemer_bytes(
|
|
|
204
206
|
return first_byte, action, entries
|
|
205
207
|
|
|
206
208
|
|
|
209
|
+
def _value_to_assets(value: Value) -> Assets:
|
|
210
|
+
"""Convert a pycardano ``Value`` (a raw on-chain UTxO amount) to ``Assets``.
|
|
211
|
+
|
|
212
|
+
Used to seed the new pool output from the spent pool UTxO's exact value bag
|
|
213
|
+
so the swap only mutates the traded reserves + swap-fee lovelace, leaving the
|
|
214
|
+
pool's min-ADA, dex NFT, and any other assets untouched (the withdraw
|
|
215
|
+
validator requires the continuation to preserve them).
|
|
216
|
+
"""
|
|
217
|
+
assets = Assets(root={"lovelace": int(value.coin)})
|
|
218
|
+
multi = getattr(value, "multi_asset", None)
|
|
219
|
+
if multi:
|
|
220
|
+
for policy, names in multi.data.items():
|
|
221
|
+
for asset_name, quantity in names.data.items():
|
|
222
|
+
unit = policy.payload.hex() + asset_name.payload.hex()
|
|
223
|
+
assets.root[unit] = int(quantity)
|
|
224
|
+
return assets
|
|
225
|
+
|
|
226
|
+
|
|
207
227
|
@dataclass
|
|
208
228
|
class DanoSwapRedeemer(CBORSerializable):
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
the
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
229
|
+
"""Dano swap redeemer (Spend or Withdraw) for a batch of >= 1 pool spends.
|
|
230
|
+
|
|
231
|
+
A Dano swap tx spends N >= 1 pool UTxOs governed by a single withdraw-zero:
|
|
232
|
+
the tx carries N Spend redeemers + one Withdraw redeemer, and EVERY redeemer
|
|
233
|
+
carries the same batch vector of per-pool ``(pool_in_idx, pool_out_idx,
|
|
234
|
+
delta)`` entries. Only the leading ``first_byte`` differs — a Spend's is its
|
|
235
|
+
own pool input index; the Withdraw's is the protocol-config reference index.
|
|
236
|
+
``pool_in_idx`` is the pool's transaction input index; ``pool_out_idx`` is the
|
|
237
|
+
pool's position in the batch vector (its append index ``0..N-1``), NOT a tx
|
|
238
|
+
output index. The input index depends on the FINAL sorted inputs, so the
|
|
239
|
+
batch is resolved post-build by :meth:`set_idx`, which the tx builder calls
|
|
240
|
+
after sorting and indexing inputs (mirrors ``SSPoolRedeemer.set_idx`` and the
|
|
241
|
+
clmm-sdk's ``RedeemerArg`` callback).
|
|
242
|
+
|
|
243
|
+
``swap_utxo`` accumulates the batch on ``tx_builder._dano_swap_batch`` as each
|
|
244
|
+
pool is folded in, so a single-pool call and a composed multi-pool tx share
|
|
245
|
+
one code path. The on-chain redeemer Plutus Data is the raw swap payload
|
|
246
|
+
serialized as a CBOR byte string; :meth:`to_primitive` returns the payload.
|
|
220
247
|
"""
|
|
221
248
|
|
|
222
249
|
pool_input: TransactionInput
|
|
@@ -240,8 +267,32 @@ class DanoSwapRedeemer(CBORSerializable):
|
|
|
240
267
|
return i
|
|
241
268
|
raise InvalidPoolError("redeemer UTxO not found in transaction during set_idx")
|
|
242
269
|
|
|
270
|
+
def _resolve_entries(
|
|
271
|
+
self,
|
|
272
|
+
tx_builder: TransactionBuilder,
|
|
273
|
+
) -> list[tuple[int, int, int]]:
|
|
274
|
+
"""Resolve the shared batch entry vector in pool-batch order.
|
|
275
|
+
|
|
276
|
+
Every Spend and the single Withdraw redeemer of a Dano tx carry the same
|
|
277
|
+
vector of ``(pool_in_idx, pool_out_idx, delta)`` entries — one per pool
|
|
278
|
+
folded into ``tx_builder._dano_swap_batch`` (append order). Mirrors the
|
|
279
|
+
clmm-sdk ``swapTokensRedeemer``: ``pool_in_idx`` is the pool's transaction
|
|
280
|
+
input index; ``pool_out_idx`` is the pool's position in the batch vector
|
|
281
|
+
(its append index ``0..N-1``), NOT a tx output index; ``delta`` is that
|
|
282
|
+
pool's signed swap amount. Order is the batch append order (no sort).
|
|
283
|
+
"""
|
|
284
|
+
batch = getattr(tx_builder, "_dano_swap_batch", None)
|
|
285
|
+
if not batch:
|
|
286
|
+
batch = [(self.pool_input, self.delta_amount)]
|
|
287
|
+
inputs = list(tx_builder.inputs)
|
|
288
|
+
return [
|
|
289
|
+
(self._sorted_index(inputs, pool_input), pool_out_idx, delta)
|
|
290
|
+
for pool_out_idx, (pool_input, delta) in enumerate(batch)
|
|
291
|
+
]
|
|
292
|
+
|
|
243
293
|
def set_idx(self, tx_builder: TransactionBuilder) -> None:
|
|
244
|
-
"""Resolve
|
|
294
|
+
"""Resolve the shared batch + this redeemer's first byte post-build."""
|
|
295
|
+
self._entries = self._resolve_entries(tx_builder)
|
|
245
296
|
self.pool_in_idx = self._sorted_index(list(tx_builder.inputs), self.pool_input)
|
|
246
297
|
if self.is_withdraw:
|
|
247
298
|
if self.protocol_config_input is None:
|
|
@@ -255,13 +306,22 @@ class DanoSwapRedeemer(CBORSerializable):
|
|
|
255
306
|
else:
|
|
256
307
|
self.first_byte = self.pool_in_idx
|
|
257
308
|
|
|
258
|
-
def to_primitive(self) ->
|
|
259
|
-
"""Serialize the redeemer as the packed swap payload bytestring.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
309
|
+
def to_primitive(self) -> ByteString:
|
|
310
|
+
"""Serialize the redeemer as the packed batch swap payload bytestring.
|
|
311
|
+
|
|
312
|
+
Wrapped in :class:`ByteString` so a payload longer than 64 bytes (any
|
|
313
|
+
batch of >= 2 pools: 2 + 34*N bytes) serializes as a CBOR
|
|
314
|
+
indefinite-length chunked bytestring, as the on-chain validator requires;
|
|
315
|
+
a single-pool payload (36 bytes) stays a definite bytestring.
|
|
316
|
+
"""
|
|
317
|
+
entries = getattr(self, "_entries", None)
|
|
318
|
+
if entries is None:
|
|
319
|
+
entries = [(self.pool_in_idx, self.pool_out_idx, self.delta_amount)]
|
|
320
|
+
return ByteString(
|
|
321
|
+
build_batch_swap_redeemer_bytes(
|
|
322
|
+
first_byte=self.first_byte,
|
|
323
|
+
entries=entries,
|
|
324
|
+
),
|
|
265
325
|
)
|
|
266
326
|
|
|
267
327
|
@classmethod
|
|
@@ -732,15 +792,20 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
|
|
|
732
792
|
|
|
733
793
|
def _new_pool_assets(
|
|
734
794
|
self,
|
|
795
|
+
base_assets: Assets,
|
|
735
796
|
pool_change_x: int,
|
|
736
797
|
pool_change_y: int,
|
|
737
798
|
swap_fee: int,
|
|
738
799
|
staking_reward: int = 0,
|
|
739
800
|
) -> Assets:
|
|
740
801
|
d = self._datum
|
|
741
|
-
#
|
|
742
|
-
#
|
|
743
|
-
|
|
802
|
+
# Copy the spent pool UTxO's exact value bag and mutate ONLY the traded
|
|
803
|
+
# reserves + swap-fee lovelace. The pool's min-ADA, dex NFT, and any other
|
|
804
|
+
# assets carry over untouched — the withdraw validator requires the
|
|
805
|
+
# continuation to preserve them, and reconstructing from the net reserves
|
|
806
|
+
# (``_gross_assets``) drops a token/token pool's real ADA (its min-ADA is
|
|
807
|
+
# not a reserve, so ``assets`` never carried it).
|
|
808
|
+
new = Assets(root=dict(base_assets.root))
|
|
744
809
|
if self.dex_nft is not None:
|
|
745
810
|
new.root[self.dex_nft.unit()] = 1
|
|
746
811
|
new.root[d.unit_x] = new.root.get(d.unit_x, 0) + pool_change_x
|
|
@@ -834,6 +899,22 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
|
|
|
834
899
|
raise InvalidPoolError("Could not re-fetch pool UTxO address via backend")
|
|
835
900
|
pool_address = order_info[0].address
|
|
836
901
|
|
|
902
|
+
# Seed the input value + new pool output from the pool UTxO's EXACT
|
|
903
|
+
# on-chain value bag (min-ADA, dex NFT, any stray assets included) so the
|
|
904
|
+
# swap mutates only the traded reserves + swap-fee lovelace. Reconstructing
|
|
905
|
+
# from the net reserves (``_gross_assets``) drops a token/token pool's real
|
|
906
|
+
# ADA — its min-ADA is not a reserve, so ``assets`` never carried it — and
|
|
907
|
+
# the withdraw validator then rejects the continuation for not preserving
|
|
908
|
+
# it (mirrors SaturnSwap reading its input's coin). Resolve the raw UTxO by
|
|
909
|
+
# out-ref via the chain context; fall back to the reconstructed gross bag
|
|
910
|
+
# when a context cannot resolve by out-ref.
|
|
911
|
+
pool_bag = pool_in_assets
|
|
912
|
+
resolve_utxo = getattr(tx_builder.context, "utxo_by_tx_id", None)
|
|
913
|
+
if resolve_utxo is not None:
|
|
914
|
+
raw_utxo = resolve_utxo(self.tx_hash, self.tx_index)
|
|
915
|
+
if raw_utxo is not None:
|
|
916
|
+
pool_bag = _value_to_assets(raw_utxo.output.amount)
|
|
917
|
+
|
|
837
918
|
# Overdue ADA pool: when curEpoch > last_withdraw_epoch the validator
|
|
838
919
|
# requires the pool's accrued staking rewards to be withdrawn from the
|
|
839
920
|
# per-pool stake credential in the SAME tx (a second withdrawal) and the
|
|
@@ -884,6 +965,7 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
|
|
|
884
965
|
|
|
885
966
|
new_datum = self.compute_new_datum(delta_amount, swap_fee, cur_epoch)
|
|
886
967
|
new_pool_assets = self._new_pool_assets(
|
|
968
|
+
pool_bag,
|
|
887
969
|
pool_change_x,
|
|
888
970
|
pool_change_y,
|
|
889
971
|
swap_fee,
|
|
@@ -897,7 +979,7 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
|
|
|
897
979
|
),
|
|
898
980
|
output=TransactionOutput(
|
|
899
981
|
address=Address.decode(pool_address),
|
|
900
|
-
amount=asset_to_value(
|
|
982
|
+
amount=asset_to_value(pool_bag),
|
|
901
983
|
datum=self._datum,
|
|
902
984
|
),
|
|
903
985
|
)
|
|
@@ -914,42 +996,54 @@ class DanoCLMMState(AbstractConstantLiquidityPoolState):
|
|
|
914
996
|
"Pool script reference UTxO unavailable from backend",
|
|
915
997
|
)
|
|
916
998
|
|
|
917
|
-
#
|
|
918
|
-
#
|
|
919
|
-
#
|
|
920
|
-
#
|
|
921
|
-
#
|
|
922
|
-
# ``
|
|
923
|
-
#
|
|
924
|
-
|
|
925
|
-
|
|
999
|
+
# Fold this pool into the tx's shared Dano swap batch. A Dano tx spends
|
|
1000
|
+
# N >= 1 pool UTxOs under ONE withdraw-zero: every Spend redeemer and the
|
|
1001
|
+
# single Withdraw redeemer carry the same batch vector, resolved
|
|
1002
|
+
# POST-BUILD in ``DanoSwapRedeemer.set_idx`` (the builder runs it after
|
|
1003
|
+
# assigning redeemer indices). Composing another Dano pool into the same
|
|
1004
|
+
# ``tx_builder`` appends here and reuses the existing withdraw-zero — the
|
|
1005
|
+
# first pool folded in owns it, later pools only extend the batch.
|
|
1006
|
+
batch = getattr(tx_builder, "_dano_swap_batch", None)
|
|
1007
|
+
if batch is None:
|
|
1008
|
+
batch = []
|
|
1009
|
+
tx_builder._dano_swap_batch = batch
|
|
1010
|
+
first_dano = len(batch) == 0
|
|
1011
|
+
batch.append((input_utxo.input, delta_amount))
|
|
1012
|
+
|
|
926
1013
|
spend_redeemer = DanoSwapRedeemer(
|
|
927
1014
|
pool_input=input_utxo.input,
|
|
928
1015
|
delta_amount=delta_amount,
|
|
929
1016
|
is_withdraw=False,
|
|
930
1017
|
)
|
|
931
|
-
withdraw_redeemer = DanoSwapRedeemer(
|
|
932
|
-
pool_input=input_utxo.input,
|
|
933
|
-
delta_amount=delta_amount,
|
|
934
|
-
is_withdraw=True,
|
|
935
|
-
protocol_config_input=pc_utxo.input,
|
|
936
|
-
)
|
|
937
|
-
|
|
938
1018
|
tx_builder.add_script_input(
|
|
939
1019
|
utxo=input_utxo,
|
|
940
1020
|
script=script_ref,
|
|
941
1021
|
redeemer=Redeemer(spend_redeemer),
|
|
942
1022
|
)
|
|
943
1023
|
|
|
1024
|
+
# Add the withdraw-zero (and its batch Withdraw redeemer) exactly once per
|
|
1025
|
+
# tx. Merge into any existing withdrawals rather than overwrite, so a
|
|
1026
|
+
# prior Dano pool's withdraw-zero and any overdue per-pool staking
|
|
1027
|
+
# withdrawal survive.
|
|
944
1028
|
reward_addr = Address.from_primitive(DANO_POOL_REWARD_ADDRESS_MAINNET)
|
|
945
|
-
withdrawals: dict[bytes, int] =
|
|
1029
|
+
withdrawals: dict[bytes, int] = (
|
|
1030
|
+
dict(tx_builder.withdrawals) if tx_builder.withdrawals else {}
|
|
1031
|
+
)
|
|
1032
|
+
withdrawals[bytes(reward_addr)] = 0
|
|
946
1033
|
if is_overdue and staking_reward_addr is not None:
|
|
947
1034
|
withdrawals[bytes(staking_reward_addr)] = reward
|
|
948
1035
|
tx_builder.withdrawals = Withdrawals(withdrawals)
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1036
|
+
if first_dano:
|
|
1037
|
+
withdraw_redeemer = DanoSwapRedeemer(
|
|
1038
|
+
pool_input=input_utxo.input,
|
|
1039
|
+
delta_amount=delta_amount,
|
|
1040
|
+
is_withdraw=True,
|
|
1041
|
+
protocol_config_input=pc_utxo.input,
|
|
1042
|
+
)
|
|
1043
|
+
tx_builder.add_withdrawal_script(
|
|
1044
|
+
script_ref,
|
|
1045
|
+
Redeemer(withdraw_redeemer),
|
|
1046
|
+
)
|
|
953
1047
|
if is_overdue and staking_ref_utxo is not None:
|
|
954
1048
|
# Per-pool staking-reward withdrawal. Its redeemer is pool-input
|
|
955
1049
|
# indexed (like Spend, NOT the protocol-config-indexed withdraw-zero).
|
|
@@ -28,7 +28,10 @@ from charli3_dendrite.lending.danogo.state import DanogoLoanState
|
|
|
28
28
|
from charli3_dendrite.lending.danogo.state import DanogoPoolState
|
|
29
29
|
|
|
30
30
|
if TYPE_CHECKING:
|
|
31
|
+
from collections.abc import Collection
|
|
32
|
+
|
|
31
33
|
from charli3_dendrite.backend.backend_base import AbstractBackend
|
|
34
|
+
from charli3_dendrite.dataclasses.models import Assets
|
|
32
35
|
from charli3_dendrite.dataclasses.models import PoolStateInfo
|
|
33
36
|
from charli3_dendrite.lending.oracles.models import PriceMap
|
|
34
37
|
|
|
@@ -103,6 +106,29 @@ def _pool_nft_name(info: PoolStateInfo, policy: str) -> str | None:
|
|
|
103
106
|
return None
|
|
104
107
|
|
|
105
108
|
|
|
109
|
+
def _loan_market_name(
|
|
110
|
+
assets: Assets,
|
|
111
|
+
loan_policy: str,
|
|
112
|
+
valid_names: Collection[str],
|
|
113
|
+
) -> str | None:
|
|
114
|
+
"""Pool-NFT name (hex) of the market a loan belongs to, from its loan-identity NFT.
|
|
115
|
+
|
|
116
|
+
Each loan UTxO carries a loan token minted under the loan script hash whose asset
|
|
117
|
+
name IS the pool-NFT name of the loan's market (`create_loan` mints it that way).
|
|
118
|
+
Mirroring `_pool_nft_name`, this reads that name directly off the loan rather than
|
|
119
|
+
guessing the market from the borrowed supply token (several markets can share a
|
|
120
|
+
supply token) or the collateral (several markets can accept the same collateral).
|
|
121
|
+
Returns the name only when it is a known market/pool name (in `valid_names`), else
|
|
122
|
+
None (the loan is skipped, matching the existing skip-on-parse-failure degrade).
|
|
123
|
+
"""
|
|
124
|
+
for unit, qty in assets.root.items():
|
|
125
|
+
if unit != "lovelace" and unit.startswith(loan_policy) and qty == 1:
|
|
126
|
+
name = unit[len(loan_policy) :]
|
|
127
|
+
if name in valid_names:
|
|
128
|
+
return name
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
|
|
106
132
|
def fetch_markets(
|
|
107
133
|
backend: AbstractBackend,
|
|
108
134
|
addresses: DanogoScriptAddresses,
|
|
@@ -193,9 +219,22 @@ def snapshot(
|
|
|
193
219
|
if prices is None:
|
|
194
220
|
try:
|
|
195
221
|
from charli3_dendrite.lending.danogo.oracles import forward
|
|
222
|
+
from charli3_dendrite.lending.danogo.oracles.locator import (
|
|
223
|
+
augment_registry_with_bond_dtokens,
|
|
224
|
+
)
|
|
196
225
|
from charli3_dendrite.lending.danogo.oracles.locator import load_registry
|
|
197
226
|
|
|
198
227
|
registry = load_registry()
|
|
228
|
+
# Bond dTokens (a pool's own redeemable dToken) are accepted as collateral
|
|
229
|
+
# but are not mined for every (dToken, quote); synthesize their pricing
|
|
230
|
+
# recipes from the live pool/market state before resolving, so a dToken
|
|
231
|
+
# collateral prices instead of collapsing the loan's health factor.
|
|
232
|
+
augment_registry_with_bond_dtokens(
|
|
233
|
+
registry,
|
|
234
|
+
pool_address=addresses["pool"],
|
|
235
|
+
config_pool_cred=_payment_cred_hex(addresses["config_pool"]),
|
|
236
|
+
markets=markets,
|
|
237
|
+
)
|
|
199
238
|
pairs = {
|
|
200
239
|
(collateral, market.supply_token)
|
|
201
240
|
for market in markets.values()
|
|
@@ -205,28 +244,26 @@ def snapshot(
|
|
|
205
244
|
except Exception: # noqa: BLE001 - pricing outage must not crash the snapshot
|
|
206
245
|
prices = PriceMap()
|
|
207
246
|
|
|
208
|
-
# Pair pool <-> market (same pool-NFT name) and index
|
|
209
|
-
#
|
|
247
|
+
# Pair pool <-> market (same pool-NFT name) and index BY THAT NAME. Each loan is
|
|
248
|
+
# stitched to the market its own loan-identity NFT names -- not one guessed from its
|
|
249
|
+
# borrowed supply token or collateral, both of which several markets can share.
|
|
210
250
|
pools: list[DanogoPoolState] = []
|
|
211
|
-
|
|
251
|
+
by_name: dict[str, tuple[DanogoPoolState, DanogoMarket]] = {}
|
|
212
252
|
for name, pool in pools_by_name.items():
|
|
213
253
|
market = markets.get(name)
|
|
214
254
|
if market is None:
|
|
215
255
|
continue
|
|
216
256
|
pool.attach_market(market)
|
|
217
257
|
pools.append(pool)
|
|
218
|
-
|
|
258
|
+
by_name[name] = (pool, market)
|
|
219
259
|
|
|
260
|
+
loan_policy = _payment_cred_hex(addresses["loan"])
|
|
220
261
|
stitched: list[DanogoLoanState] = []
|
|
221
262
|
for loan in loans:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
except (ValueError, IndexError, TypeError, AttributeError):
|
|
225
|
-
continue
|
|
226
|
-
ctx = by_supply.get(supply)
|
|
227
|
-
if ctx is None:
|
|
263
|
+
loan_market = _loan_market_name(loan.assets, loan_policy, by_name)
|
|
264
|
+
if loan_market is None:
|
|
228
265
|
continue
|
|
229
|
-
pool, market =
|
|
266
|
+
pool, market = by_name[loan_market]
|
|
230
267
|
loan.attach_context(pool=pool, market=market, now_ms=now_ms)
|
|
231
268
|
stitched.append(loan)
|
|
232
269
|
|
|
@@ -296,10 +296,6 @@ def resolve_prices(
|
|
|
296
296
|
Emits ``OraclePrice(token=..., quote=quote, ...)``. A pair with no recipe, a
|
|
297
297
|
missing leaf, or a non-reproducing walk is simply omitted (collateral stays unpriced
|
|
298
298
|
-> not-liquidatable). Never raises into the caller.
|
|
299
|
-
|
|
300
|
-
NOTE: ``PriceMap`` keys by token only, so a collateral used across markets with
|
|
301
|
-
different supply tokens can hold only one quote. That's a pre-existing PriceMap
|
|
302
|
-
constraint, not handled here.
|
|
303
299
|
"""
|
|
304
300
|
pm = PriceMap()
|
|
305
301
|
for collateral, quote in pairs:
|