charli3_dendrite 1.5.15.dev1__tar.gz → 1.5.16.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.15.dev1 → charli3_dendrite-1.5.16.dev0}/PKG-INFO +1 -1
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/pyproject.toml +2 -2
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/constants.py +6 -3
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/indexing.py +2 -2
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/builder.py +57 -1
- charli3_dendrite-1.5.16.dev0/src/charli3_dendrite/lending/fluidtokens_v4/transactions/claim.py +447 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/common.py +13 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_action.py +2 -5
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/redeemers.py +38 -1
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/resolve.py +148 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/transactions/base.py +3 -1
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/LICENSE +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/README.md +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/dano.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/multi_asset.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/sundae_v4.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/sundae_v4_deployments.json +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/base.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/constants.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/loader.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/market.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/math.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator_datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/deployments.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/forward.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/leaves.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/locator.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/lp_pricing.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/recipes.json +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/redeemer.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/reproduce.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/oracles/structured_datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/state.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/build.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/context.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/create_loan.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/increase_loan.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/loan_ids.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/modify_collateral.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_redeemer.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_synth.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/topup_withdraw.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/danogo/transactions/verify.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/constants.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/loader.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/market.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/math.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/feeds.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/fluid_api.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/witness.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/state.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow_terms.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/change_collateral.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/context.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/lend.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/pool.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/recast.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/request.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/resolve.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/utxos.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/datums.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/loader.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/state.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/borrow.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/change_collateral.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/lender_bond.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_action.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_terms.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/oracle.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_cancel.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_create.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_edit.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_terms.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/recast.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/math.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/charli3.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/dex_pooled.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/fluid.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/models.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/orcfax.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/oracles/qtoken.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/plutus.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/registry.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/transactions/infra.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/transactions/snapshot.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.dev0}/src/charli3_dendrite/lending/units.py +0 -0
- {charli3_dendrite-1.5.15.dev1 → charli3_dendrite-1.5.16.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.16-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.16-dev0"
|
|
54
54
|
parse = """(?x)
|
|
55
55
|
(?P<major>\\d+)\\.
|
|
56
56
|
(?P<minor>\\d+)\\.
|
|
@@ -8,9 +8,9 @@ policy id and script hash. The constants below are the live mainnet values:
|
|
|
8
8
|
follows a config update.
|
|
9
9
|
|
|
10
10
|
The lender-manager spend script is not listed in the config datum: pools opt into it
|
|
11
|
-
by pointing ``lender_bond_address`` at it, and it ships as a constant here
|
|
12
|
-
|
|
13
|
-
config NFT.
|
|
11
|
+
by pointing ``lender_bond_address`` at it, and it ships as a constant here, as does
|
|
12
|
+
its dispatch withdraw script, a parameter of the spend script. Its own action scripts
|
|
13
|
+
are listed in the lender-manager config datum, held with a separate config NFT.
|
|
14
14
|
|
|
15
15
|
The pool manager's owner-check scripts are not listed either: they are parameters of
|
|
16
16
|
the pool-manager policy, so they change only with a new pool-manager policy, which
|
|
@@ -72,6 +72,9 @@ LOCKED_BORROWER_MANAGER_SPEND_SKH = (
|
|
|
72
72
|
|
|
73
73
|
# Not carried by the config datum (see the module docstring).
|
|
74
74
|
LENDER_MANAGER_SPEND_SKH = "6743f4b69446b4e066cfb89daa3d01ef041b6d2646968993be4cec09"
|
|
75
|
+
# The lender-manager dispatch: its withdraw redeemer names the action, and it requires
|
|
76
|
+
# the withdrawal of that action's script from the lender-manager config.
|
|
77
|
+
LENDER_MANAGER_WITHDRAW_SKH = "247065fa7d0f8c5bce2bb379aa76d2cd79ad4e6a7ab207627039a804"
|
|
75
78
|
|
|
76
79
|
# The pool manager's owner checks for a pool edit and a pool cancel: the
|
|
77
80
|
# ``pm_edit_pool`` and ``pm_cancel_pool_manager`` validators of
|
|
@@ -69,7 +69,7 @@ _STATE_CLASS: dict[EntityKind, type[FluidV4State]] = {
|
|
|
69
69
|
|
|
70
70
|
# Everything a malformed record can raise while its datum is decoded. Truncated CBOR
|
|
71
71
|
# raises cbor2's end-of-stream error, which is not a ValueError.
|
|
72
|
-
|
|
72
|
+
DECODE_ERRORS = (
|
|
73
73
|
cbor2.CBORDecodeError,
|
|
74
74
|
DeserializeException,
|
|
75
75
|
ValueError,
|
|
@@ -187,5 +187,5 @@ def parse_utxo(
|
|
|
187
187
|
return None
|
|
188
188
|
try:
|
|
189
189
|
return _STATE_CLASS[selector.kind].from_record(info)
|
|
190
|
-
except
|
|
190
|
+
except DECODE_ERRORS:
|
|
191
191
|
return None
|
|
@@ -22,6 +22,8 @@ from charli3_dendrite.lending.fluidtokens_v4.transactions.change_collateral impo
|
|
|
22
22
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.change_collateral import (
|
|
23
23
|
build_change_collateral,
|
|
24
24
|
)
|
|
25
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.claim import ClaimSnapshot
|
|
26
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.claim import build_claim
|
|
25
27
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.pool_cancel import (
|
|
26
28
|
PoolCancelSnapshot,
|
|
27
29
|
)
|
|
@@ -56,6 +58,19 @@ if TYPE_CHECKING:
|
|
|
56
58
|
from charli3_dendrite.lending.transactions.base import ActionParams
|
|
57
59
|
from charli3_dendrite.lending.transactions.snapshot import PoolActionSnapshot
|
|
58
60
|
|
|
61
|
+
# The borrower's actions on an existing loan, and the lender's actions.
|
|
62
|
+
_LOAN_ACTIONS = {
|
|
63
|
+
LendingAction.REPAY,
|
|
64
|
+
LendingAction.MODIFY_COLLATERAL,
|
|
65
|
+
LendingAction.RECAST,
|
|
66
|
+
}
|
|
67
|
+
_LENDER_ACTIONS = {
|
|
68
|
+
LendingAction.POOL_CREATE,
|
|
69
|
+
LendingAction.POOL_EDIT,
|
|
70
|
+
LendingAction.POOL_CANCEL,
|
|
71
|
+
LendingAction.CLAIM_REPAYMENTS,
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
# Each action's snapshot type and the function that adds it to a builder.
|
|
60
75
|
_ACTIONS: dict[
|
|
61
76
|
LendingAction,
|
|
@@ -71,6 +86,7 @@ _ACTIONS: dict[
|
|
|
71
86
|
LendingAction.POOL_CREATE: (PoolCreateSnapshot, build_pool_create),
|
|
72
87
|
LendingAction.POOL_EDIT: (PoolEditSnapshot, build_pool_edit),
|
|
73
88
|
LendingAction.POOL_CANCEL: (PoolCancelSnapshot, build_pool_cancel),
|
|
89
|
+
LendingAction.CLAIM_REPAYMENTS: (ClaimSnapshot, build_claim),
|
|
74
90
|
}
|
|
75
91
|
|
|
76
92
|
|
|
@@ -99,7 +115,7 @@ class FluidTokensV4TxBuilder(AbstractLendingTxBuilder):
|
|
|
99
115
|
|
|
100
116
|
@classmethod
|
|
101
117
|
def supported_actions(cls) -> set[LendingAction]:
|
|
102
|
-
"""
|
|
118
|
+
"""The borrower's loan actions, the lender's pool actions and the claim."""
|
|
103
119
|
return set(_ACTIONS)
|
|
104
120
|
|
|
105
121
|
def resolve_snapshot(
|
|
@@ -126,11 +142,27 @@ class FluidTokensV4TxBuilder(AbstractLendingTxBuilder):
|
|
|
126
142
|
- POOL_EDIT: ``loan_utxo`` is the pool and ``amount`` the principal it gains
|
|
127
143
|
(negative withdraws); its terms are kept. ``actor_address`` owns the pool.
|
|
128
144
|
- POOL_CANCEL: ``loan_utxo`` is the pool; ``actor_address`` owns it.
|
|
145
|
+
- CLAIM_REPAYMENTS: the repayments owed to the lender bonds
|
|
146
|
+
``actor_address``'s key holds at the lender manager, at most
|
|
147
|
+
``MAX_REPAYMENTS_PER_CLAIM``; no other field may be set.
|
|
129
148
|
- POOL_CREATE takes lender terms ``ActionParams`` cannot carry: resolve it
|
|
130
149
|
with ``PoolCreateSnapshot.from_backend``.
|
|
131
150
|
"""
|
|
132
151
|
if action == LendingAction.BORROW:
|
|
133
152
|
return self._resolve_borrow(backend, params)
|
|
153
|
+
if action in _LOAN_ACTIONS:
|
|
154
|
+
return self._resolve_loan_action(backend, action, params)
|
|
155
|
+
if action in _LENDER_ACTIONS:
|
|
156
|
+
return self._resolve_lender_action(backend, action, params)
|
|
157
|
+
raise ValueError(f"{self.protocol()} does not support action {action.value!r}")
|
|
158
|
+
|
|
159
|
+
def _resolve_loan_action(
|
|
160
|
+
self,
|
|
161
|
+
backend: AbstractBackend,
|
|
162
|
+
action: LendingAction,
|
|
163
|
+
params: ActionParams,
|
|
164
|
+
) -> PoolActionSnapshot:
|
|
165
|
+
"""REPAY, MODIFY_COLLATERAL or RECAST of the loan in ``params``."""
|
|
134
166
|
if action == LendingAction.REPAY:
|
|
135
167
|
if params.amount:
|
|
136
168
|
raise ValueError(
|
|
@@ -158,6 +190,15 @@ class FluidTokensV4TxBuilder(AbstractLendingTxBuilder):
|
|
|
158
190
|
recasts=[(_out_ref(params.loan_utxo, "loan"), params.amount)],
|
|
159
191
|
borrower_address=params.actor_address,
|
|
160
192
|
)
|
|
193
|
+
raise ValueError(f"{self.protocol()} does not support action {action.value!r}")
|
|
194
|
+
|
|
195
|
+
def _resolve_lender_action(
|
|
196
|
+
self,
|
|
197
|
+
backend: AbstractBackend,
|
|
198
|
+
action: LendingAction,
|
|
199
|
+
params: ActionParams,
|
|
200
|
+
) -> PoolActionSnapshot:
|
|
201
|
+
"""POOL_EDIT, POOL_CANCEL or CLAIM_REPAYMENTS; refuses POOL_CREATE."""
|
|
161
202
|
if action == LendingAction.POOL_EDIT:
|
|
162
203
|
if not params.amount:
|
|
163
204
|
raise ValueError(
|
|
@@ -180,6 +221,21 @@ class FluidTokensV4TxBuilder(AbstractLendingTxBuilder):
|
|
|
180
221
|
pools=[_out_ref(params.loan_utxo, "pool")],
|
|
181
222
|
lender_address=params.actor_address,
|
|
182
223
|
)
|
|
224
|
+
if action == LendingAction.CLAIM_REPAYMENTS:
|
|
225
|
+
if (
|
|
226
|
+
params.loan_utxo
|
|
227
|
+
or params.amount
|
|
228
|
+
or params.collateral
|
|
229
|
+
or (params.borrow_amount)
|
|
230
|
+
):
|
|
231
|
+
raise ValueError(
|
|
232
|
+
"CLAIM_REPAYMENTS takes only params.actor_address; name the bonds "
|
|
233
|
+
"to claim with ClaimSnapshot.from_backend",
|
|
234
|
+
)
|
|
235
|
+
return ClaimSnapshot.from_backend(
|
|
236
|
+
backend,
|
|
237
|
+
lender_address=params.actor_address,
|
|
238
|
+
)
|
|
183
239
|
if action == LendingAction.POOL_CREATE:
|
|
184
240
|
raise ValueError(
|
|
185
241
|
"POOL_CREATE needs lender terms ActionParams cannot carry; resolve it "
|
charli3_dendrite-1.5.16.dev0/src/charli3_dendrite/lending/fluidtokens_v4/transactions/claim.py
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
"""FluidTokens V4 repayment claim: a lender collects the repayments of their loans.
|
|
2
|
+
|
|
3
|
+
A repayment lands at the asset manager, owned by the loan's lender bond, and the asset
|
|
4
|
+
manager releases it to any transaction that spends that bond. Lender bonds sit at the
|
|
5
|
+
lender manager, which lets them move only under an action named by its dispatch; the
|
|
6
|
+
``WithdrawBonds`` action requires every spent bond's lender to sign. A claim spends
|
|
7
|
+
the lender's bonds and the repayments they own, returns each bond to the lender
|
|
8
|
+
manager unchanged (so its automation keeps serving later repayments), and leaves the
|
|
9
|
+
repayments, with any repayment receipts they carry, to the caller's change.
|
|
10
|
+
|
|
11
|
+
The asset manager checks each repayment against every input of the transaction, so a
|
|
12
|
+
claim's execution budget grows with repayments times inputs: a claim spends at most
|
|
13
|
+
:data:`MAX_REPAYMENTS_PER_CLAIM` repayments, and more take several claims.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from collections.abc import Collection
|
|
19
|
+
from collections.abc import Sequence
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from typing import TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
from pycardano import Address
|
|
24
|
+
from pycardano import Redeemer
|
|
25
|
+
from pycardano import ScriptHash
|
|
26
|
+
from pycardano import TransactionBuilder
|
|
27
|
+
from pycardano import VerificationKeyHash
|
|
28
|
+
|
|
29
|
+
from charli3_dendrite.lending.fluidtokens.transactions._common import ref_index
|
|
30
|
+
from charli3_dendrite.lending.fluidtokens.transactions._common import reward_address
|
|
31
|
+
from charli3_dendrite.lending.fluidtokens.transactions.utxos import Utxo
|
|
32
|
+
from charli3_dendrite.lending.fluidtokens.transactions.utxos import ogmios_entry
|
|
33
|
+
from charli3_dendrite.lending.fluidtokens.transactions.utxos import script_ref_by_hash
|
|
34
|
+
from charli3_dendrite.lending.fluidtokens.transactions.utxos import to_pycardano_utxo
|
|
35
|
+
from charli3_dendrite.lending.fluidtokens.transactions.utxos import utxo_from_dict
|
|
36
|
+
from charli3_dendrite.lending.fluidtokens_v4 import constants as c
|
|
37
|
+
from charli3_dendrite.lending.fluidtokens_v4.datums import AssetManagerDatumWithToken
|
|
38
|
+
from charli3_dendrite.lending.fluidtokens_v4.datums import ConfigDatum
|
|
39
|
+
from charli3_dendrite.lending.fluidtokens_v4.datums import LenderManagerConfigDatum
|
|
40
|
+
from charli3_dendrite.lending.fluidtokens_v4.datums import LenderManagerDatum
|
|
41
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import (
|
|
42
|
+
add_zero_withdrawals,
|
|
43
|
+
)
|
|
44
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import ledger_order
|
|
45
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import min_ada
|
|
46
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import out_ref_of
|
|
47
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import signing_key
|
|
48
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.redeemers import (
|
|
49
|
+
AssetManagerWithdrawRedeemer,
|
|
50
|
+
)
|
|
51
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.redeemers import (
|
|
52
|
+
LenderManagerActionWithdrawBonds,
|
|
53
|
+
)
|
|
54
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.redeemers import (
|
|
55
|
+
LenderManagerWithdrawRedeemer,
|
|
56
|
+
)
|
|
57
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.redeemers import (
|
|
58
|
+
LoanSpendRedeemer,
|
|
59
|
+
)
|
|
60
|
+
from charli3_dendrite.lending.transactions.snapshot import PoolActionSnapshot
|
|
61
|
+
|
|
62
|
+
if TYPE_CHECKING:
|
|
63
|
+
from pycardano import TransactionOutput
|
|
64
|
+
|
|
65
|
+
from charli3_dendrite.backend.backend_base import AbstractBackend
|
|
66
|
+
|
|
67
|
+
# The most repayments one claim spends: this leaves room for the lender-manager and
|
|
68
|
+
# wallet inputs within the transaction's execution budget.
|
|
69
|
+
MAX_REPAYMENTS_PER_CLAIM = 10
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _payment_script(utxo: Utxo) -> str | None:
|
|
73
|
+
"""The script hash of ``utxo``'s payment credential, or None for a key address."""
|
|
74
|
+
payment = Address.decode(utxo.address).payment_part
|
|
75
|
+
return payment.payload.hex() if isinstance(payment, ScriptHash) else None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class ClaimPosition:
|
|
80
|
+
"""A UTxO holding lender bonds at the lender manager and the repayments it owns."""
|
|
81
|
+
|
|
82
|
+
bond: Utxo
|
|
83
|
+
repayments: list[Utxo]
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def out_ref(self) -> tuple[str, int]:
|
|
87
|
+
"""The bond UTxO's out-ref."""
|
|
88
|
+
return out_ref_of(self.bond)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def lender_datum(self) -> LenderManagerDatum:
|
|
92
|
+
"""The bond UTxO's lender-manager datum."""
|
|
93
|
+
if self.bond.datum is None:
|
|
94
|
+
raise ValueError("lender-bond UTxO is missing its datum")
|
|
95
|
+
return LenderManagerDatum.from_cbor(self.bond.datum)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def bond_names(self) -> list[bytes]:
|
|
99
|
+
"""The lender bonds the UTxO holds; each is named after its loan."""
|
|
100
|
+
return [
|
|
101
|
+
bytes.fromhex(n)
|
|
102
|
+
for p, n, q in self.bond.assets
|
|
103
|
+
if p == c.LENDER_BOND_POLICY
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def owner_pkh(self) -> bytes:
|
|
108
|
+
"""The key hash that must sign to move the bonds."""
|
|
109
|
+
return signing_key(self.lender_datum.lender_auth, "lender bond")
|
|
110
|
+
|
|
111
|
+
def check(self) -> None:
|
|
112
|
+
"""Raise unless the bonds sit at the lender manager and own every repayment."""
|
|
113
|
+
if _payment_script(self.bond) != c.LENDER_MANAGER_SPEND_SKH:
|
|
114
|
+
raise ValueError(f"UTxO {self.out_ref} is not at the lender manager")
|
|
115
|
+
if not self.bond_names:
|
|
116
|
+
raise ValueError(f"UTxO {self.out_ref} holds no lender bond")
|
|
117
|
+
if not self.repayments:
|
|
118
|
+
raise ValueError(f"lender bond UTxO {self.out_ref} owns no repayment")
|
|
119
|
+
names = set(self.bond_names)
|
|
120
|
+
for repayment in self.repayments:
|
|
121
|
+
owner = AssetManagerDatumWithToken.from_cbor(repayment.datum or "")
|
|
122
|
+
if (
|
|
123
|
+
bytes(owner.owner_asset.policy_id).hex() != c.LENDER_BOND_POLICY
|
|
124
|
+
or bytes(owner.owner_asset.asset_name) not in names
|
|
125
|
+
):
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"lender bond UTxO {self.out_ref} does not own repayment "
|
|
128
|
+
f"{out_ref_of(repayment)}",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class ClaimSnapshot(PoolActionSnapshot):
|
|
134
|
+
"""Everything a claim of one lender's repayments needs, resolved from chain."""
|
|
135
|
+
|
|
136
|
+
positions: Sequence[ClaimPosition]
|
|
137
|
+
funding: list[Utxo]
|
|
138
|
+
config: Utxo
|
|
139
|
+
lender_manager_config: Utxo
|
|
140
|
+
lender_manager_spend_script_ref: Utxo
|
|
141
|
+
lender_manager_withdraw_script_ref: Utxo
|
|
142
|
+
withdraw_bonds_script_ref: Utxo
|
|
143
|
+
asset_manager_spend_script_ref: Utxo
|
|
144
|
+
asset_manager_withdraw_script_ref: Utxo
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def ordered_positions(self) -> list[ClaimPosition]:
|
|
148
|
+
"""The positions in the order the ledger sorts their bond inputs."""
|
|
149
|
+
return sorted(
|
|
150
|
+
self.positions,
|
|
151
|
+
key=lambda p: (bytes.fromhex(p.out_ref[0]), p.out_ref[1]),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def withdraw_bonds_script_hash(self) -> str:
|
|
156
|
+
"""The lender manager's ``WithdrawBonds`` action, named by its config."""
|
|
157
|
+
if self.lender_manager_config.datum is None:
|
|
158
|
+
raise ValueError("lender-manager config UTxO is missing its datum")
|
|
159
|
+
return LenderManagerConfigDatum.from_cbor(
|
|
160
|
+
self.lender_manager_config.datum,
|
|
161
|
+
).withdraw_bonds_action_script_hash.hex()
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def from_capture(cls, fix: dict) -> ClaimSnapshot:
|
|
165
|
+
"""Rebuild the snapshot of a captured mainnet claim (for byte-exact replay)."""
|
|
166
|
+
inputs = [utxo_from_dict(u) for u in fix["inputs"]]
|
|
167
|
+
refs = [utxo_from_dict(u) for u in fix["ref_inputs"]]
|
|
168
|
+
config = next(
|
|
169
|
+
u for u in refs if u.holds(c.CONFIG_NFT_POLICY, c.CONFIG_NFT_NAME)
|
|
170
|
+
)
|
|
171
|
+
lender_manager_config = next(
|
|
172
|
+
u
|
|
173
|
+
for u in refs
|
|
174
|
+
if u.holds(
|
|
175
|
+
c.LENDER_MANAGER_CONFIG_NFT_POLICY,
|
|
176
|
+
c.LENDER_MANAGER_CONFIG_NFT_NAME,
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
scripts = ConfigDatum.from_cbor(config.datum or "")
|
|
180
|
+
am_spend = scripts.asset_manager_spend_script_hash.hex()
|
|
181
|
+
repayments = [u for u in inputs if _payment_script(u) == am_spend]
|
|
182
|
+
positions = []
|
|
183
|
+
for bond in ledger_order(
|
|
184
|
+
u for u in inputs if _payment_script(u) == c.LENDER_MANAGER_SPEND_SKH
|
|
185
|
+
):
|
|
186
|
+
names = {n for p, n, _ in bond.assets if p == c.LENDER_BOND_POLICY}
|
|
187
|
+
positions.append(
|
|
188
|
+
ClaimPosition(
|
|
189
|
+
bond=bond,
|
|
190
|
+
repayments=[
|
|
191
|
+
u
|
|
192
|
+
for u in repayments
|
|
193
|
+
if bytes(
|
|
194
|
+
AssetManagerDatumWithToken.from_cbor(
|
|
195
|
+
u.datum or "",
|
|
196
|
+
).owner_asset.asset_name,
|
|
197
|
+
).hex()
|
|
198
|
+
in names
|
|
199
|
+
],
|
|
200
|
+
),
|
|
201
|
+
)
|
|
202
|
+
used = {out_ref_of(u) for p in positions for u in (p.bond, *p.repayments)}
|
|
203
|
+
withdraw_bonds = LenderManagerConfigDatum.from_cbor(
|
|
204
|
+
lender_manager_config.datum or "",
|
|
205
|
+
).withdraw_bonds_action_script_hash.hex()
|
|
206
|
+
return cls(
|
|
207
|
+
positions=positions,
|
|
208
|
+
funding=[u for u in inputs if u.out_ref not in used],
|
|
209
|
+
config=config,
|
|
210
|
+
lender_manager_config=lender_manager_config,
|
|
211
|
+
lender_manager_spend_script_ref=script_ref_by_hash(
|
|
212
|
+
refs,
|
|
213
|
+
c.LENDER_MANAGER_SPEND_SKH,
|
|
214
|
+
),
|
|
215
|
+
lender_manager_withdraw_script_ref=script_ref_by_hash(
|
|
216
|
+
refs,
|
|
217
|
+
c.LENDER_MANAGER_WITHDRAW_SKH,
|
|
218
|
+
),
|
|
219
|
+
withdraw_bonds_script_ref=script_ref_by_hash(refs, withdraw_bonds),
|
|
220
|
+
asset_manager_spend_script_ref=script_ref_by_hash(refs, am_spend),
|
|
221
|
+
asset_manager_withdraw_script_ref=script_ref_by_hash(
|
|
222
|
+
refs,
|
|
223
|
+
scripts.repayment_policy_id.hex(),
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
@classmethod
|
|
228
|
+
def from_backend(
|
|
229
|
+
cls,
|
|
230
|
+
backend: AbstractBackend,
|
|
231
|
+
*,
|
|
232
|
+
lender_address: str,
|
|
233
|
+
bonds: Collection[bytes] | None = None,
|
|
234
|
+
funding: Sequence[Utxo] | None = None,
|
|
235
|
+
) -> ClaimSnapshot:
|
|
236
|
+
"""Resolve a claim of the repayments owed to ``lender_address``'s bonds.
|
|
237
|
+
|
|
238
|
+
The bonds are the lender bonds at the lender manager whose lender
|
|
239
|
+
authorisation is the key of ``lender_address``; the repayments are the
|
|
240
|
+
asset-manager UTxOs they own, the largest first, at most
|
|
241
|
+
:data:`MAX_REPAYMENTS_PER_CLAIM` of them. ``bonds`` (loan ids, which name the
|
|
242
|
+
bonds) limits the claim to those bonds. The lender's UTxOs fund the claim
|
|
243
|
+
unless ``funding`` is given. Refuses a lender with nothing to claim, a named
|
|
244
|
+
bond that is not the lender's at the lender manager, and a wallet with no
|
|
245
|
+
UTxO to fund the claim.
|
|
246
|
+
"""
|
|
247
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
248
|
+
config_datum,
|
|
249
|
+
)
|
|
250
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
251
|
+
lender_manager_config_datum,
|
|
252
|
+
)
|
|
253
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
254
|
+
resolve_claim_positions,
|
|
255
|
+
)
|
|
256
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
257
|
+
resolve_config_utxo,
|
|
258
|
+
)
|
|
259
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
260
|
+
resolve_lender_manager_config_utxo,
|
|
261
|
+
)
|
|
262
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
263
|
+
resolve_script,
|
|
264
|
+
)
|
|
265
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.resolve import (
|
|
266
|
+
resolve_wallet_funding,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
payment = Address.decode(lender_address).payment_part
|
|
270
|
+
if not isinstance(payment, VerificationKeyHash):
|
|
271
|
+
raise NotImplementedError("only a key address can claim repayments")
|
|
272
|
+
config = resolve_config_utxo(backend)
|
|
273
|
+
scripts = config_datum(config)
|
|
274
|
+
lender_manager_config = resolve_lender_manager_config_utxo(backend)
|
|
275
|
+
positions = resolve_claim_positions(
|
|
276
|
+
backend,
|
|
277
|
+
scripts,
|
|
278
|
+
lender_pkh=payment.payload,
|
|
279
|
+
bonds=bonds,
|
|
280
|
+
)
|
|
281
|
+
if not positions:
|
|
282
|
+
raise ValueError(f"{lender_address} has no repayments to claim")
|
|
283
|
+
spent = [u for p in positions for u in (p.bond, *p.repayments)]
|
|
284
|
+
resolved = (
|
|
285
|
+
list(funding)
|
|
286
|
+
if funding is not None
|
|
287
|
+
else resolve_wallet_funding(backend, lender_address, exclude=spent)
|
|
288
|
+
)
|
|
289
|
+
if funding is None and not resolved:
|
|
290
|
+
raise ValueError(f"no UTxOs at {lender_address} fund the claim")
|
|
291
|
+
return cls(
|
|
292
|
+
positions=positions,
|
|
293
|
+
funding=resolved,
|
|
294
|
+
config=config,
|
|
295
|
+
lender_manager_config=lender_manager_config,
|
|
296
|
+
lender_manager_spend_script_ref=resolve_script(
|
|
297
|
+
backend,
|
|
298
|
+
c.LENDER_MANAGER_SPEND_SKH,
|
|
299
|
+
),
|
|
300
|
+
lender_manager_withdraw_script_ref=resolve_script(
|
|
301
|
+
backend,
|
|
302
|
+
c.LENDER_MANAGER_WITHDRAW_SKH,
|
|
303
|
+
),
|
|
304
|
+
withdraw_bonds_script_ref=resolve_script(
|
|
305
|
+
backend,
|
|
306
|
+
lender_manager_config_datum(
|
|
307
|
+
lender_manager_config,
|
|
308
|
+
).withdraw_bonds_action_script_hash,
|
|
309
|
+
),
|
|
310
|
+
asset_manager_spend_script_ref=resolve_script(
|
|
311
|
+
backend,
|
|
312
|
+
scripts.asset_manager_spend_script_hash,
|
|
313
|
+
),
|
|
314
|
+
asset_manager_withdraw_script_ref=resolve_script(
|
|
315
|
+
backend,
|
|
316
|
+
scripts.repayment_policy_id,
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def require_sole_lender_manager_action(tx_builder: TransactionBuilder) -> None:
|
|
322
|
+
"""Raise if ``tx_builder`` already spends from or dispatches the lender manager.
|
|
323
|
+
|
|
324
|
+
``WithdrawBonds`` requires the lender of every spent lender-manager UTxO to sign,
|
|
325
|
+
and one dispatch redeemer names one action for the whole transaction.
|
|
326
|
+
"""
|
|
327
|
+
spends = any(
|
|
328
|
+
isinstance(u.output.address.payment_part, ScriptHash)
|
|
329
|
+
and u.output.address.payment_part.payload.hex() == c.LENDER_MANAGER_SPEND_SKH
|
|
330
|
+
for u in tx_builder.inputs
|
|
331
|
+
)
|
|
332
|
+
dispatches = reward_address(c.LENDER_MANAGER_WITHDRAW_SKH) in (
|
|
333
|
+
tx_builder.withdrawals or {}
|
|
334
|
+
)
|
|
335
|
+
if spends or dispatches:
|
|
336
|
+
raise ValueError(
|
|
337
|
+
"a claim must be the only lender-manager action in its transaction",
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def build_claim(tx_builder: TransactionBuilder, *, snapshot: ClaimSnapshot) -> None:
|
|
342
|
+
"""Add a claim of every repayment of ``snapshot`` to ``tx_builder``.
|
|
343
|
+
|
|
344
|
+
Each bond UTxO returns to the lender manager unchanged; the repayments land in
|
|
345
|
+
the caller's change. Funding inputs are recorded for Ogmios evaluation. The
|
|
346
|
+
caller balances, signs (with every bond's lender key) and submits.
|
|
347
|
+
|
|
348
|
+
Everything else the caller wants among the transaction's reference inputs must
|
|
349
|
+
be added before this call, which fills the config indexes last. Discard the
|
|
350
|
+
builder if this raises.
|
|
351
|
+
"""
|
|
352
|
+
require_sole_lender_manager_action(tx_builder)
|
|
353
|
+
positions = snapshot.ordered_positions
|
|
354
|
+
_check_claim(positions)
|
|
355
|
+
_add_spends(tx_builder, snapshot=snapshot, positions=positions)
|
|
356
|
+
|
|
357
|
+
tx_builder.reference_inputs.add(to_pycardano_utxo(snapshot.config))
|
|
358
|
+
tx_builder.reference_inputs.add(to_pycardano_utxo(snapshot.lender_manager_config))
|
|
359
|
+
dispatch = LenderManagerWithdrawRedeemer(
|
|
360
|
+
config_ref_input_index=0,
|
|
361
|
+
action=LenderManagerActionWithdrawBonds(),
|
|
362
|
+
)
|
|
363
|
+
release = AssetManagerWithdrawRedeemer(config_ref_input_index=0)
|
|
364
|
+
for script_ref, redeemer in (
|
|
365
|
+
(snapshot.lender_manager_withdraw_script_ref, dispatch),
|
|
366
|
+
# The action reads no redeemer.
|
|
367
|
+
(snapshot.withdraw_bonds_script_ref, LoanSpendRedeemer()),
|
|
368
|
+
(snapshot.asset_manager_withdraw_script_ref, release),
|
|
369
|
+
):
|
|
370
|
+
tx_builder.add_withdrawal_script(
|
|
371
|
+
to_pycardano_utxo(script_ref),
|
|
372
|
+
Redeemer(redeemer),
|
|
373
|
+
)
|
|
374
|
+
add_zero_withdrawals(
|
|
375
|
+
tx_builder,
|
|
376
|
+
[
|
|
377
|
+
c.LENDER_MANAGER_WITHDRAW_SKH,
|
|
378
|
+
snapshot.withdraw_bonds_script_hash,
|
|
379
|
+
bytes(
|
|
380
|
+
ConfigDatum.from_cbor(snapshot.config.datum or "").repayment_policy_id,
|
|
381
|
+
).hex(),
|
|
382
|
+
],
|
|
383
|
+
)
|
|
384
|
+
signers = list(tx_builder.required_signers or [])
|
|
385
|
+
for signer in dict.fromkeys(VerificationKeyHash(p.owner_pkh) for p in positions):
|
|
386
|
+
if signer not in signers:
|
|
387
|
+
signers.append(signer)
|
|
388
|
+
tx_builder.required_signers = signers
|
|
389
|
+
for position in positions:
|
|
390
|
+
tx_builder.add_output(_returned_bond(position))
|
|
391
|
+
|
|
392
|
+
refs = ref_index(tx_builder)
|
|
393
|
+
dispatch.config_ref_input_index = refs[out_ref_of(snapshot.lender_manager_config)]
|
|
394
|
+
release.config_ref_input_index = refs[out_ref_of(snapshot.config)]
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def _check_claim(positions: Sequence[ClaimPosition]) -> None:
|
|
398
|
+
"""Raise for a claim the contracts or the transaction budget would refuse."""
|
|
399
|
+
if not positions:
|
|
400
|
+
raise ValueError("a claim needs at least one lender bond")
|
|
401
|
+
if sum(len(p.repayments) for p in positions) > MAX_REPAYMENTS_PER_CLAIM:
|
|
402
|
+
raise ValueError(
|
|
403
|
+
f"a claim spends at most {MAX_REPAYMENTS_PER_CLAIM} repayments; claim the "
|
|
404
|
+
"rest in another transaction",
|
|
405
|
+
)
|
|
406
|
+
for position in positions:
|
|
407
|
+
position.check()
|
|
408
|
+
spent = [out_ref_of(u) for p in positions for u in (p.bond, *p.repayments)]
|
|
409
|
+
if len(set(spent)) != len(spent):
|
|
410
|
+
raise ValueError("a claim names each bond and repayment once")
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _add_spends(
|
|
414
|
+
tx_builder: TransactionBuilder,
|
|
415
|
+
*,
|
|
416
|
+
snapshot: ClaimSnapshot,
|
|
417
|
+
positions: Sequence[ClaimPosition],
|
|
418
|
+
) -> None:
|
|
419
|
+
"""Spend the bonds, their repayments and the funding not among them."""
|
|
420
|
+
for position in positions:
|
|
421
|
+
tx_builder.add_script_input(
|
|
422
|
+
to_pycardano_utxo(position.bond),
|
|
423
|
+
script=to_pycardano_utxo(snapshot.lender_manager_spend_script_ref),
|
|
424
|
+
redeemer=Redeemer(LoanSpendRedeemer()),
|
|
425
|
+
)
|
|
426
|
+
for repayment in position.repayments:
|
|
427
|
+
tx_builder.add_script_input(
|
|
428
|
+
to_pycardano_utxo(repayment),
|
|
429
|
+
script=to_pycardano_utxo(snapshot.asset_manager_spend_script_ref),
|
|
430
|
+
redeemer=Redeemer(LoanSpendRedeemer()),
|
|
431
|
+
)
|
|
432
|
+
spent = {out_ref_of(u) for p in positions for u in (p.bond, *p.repayments)}
|
|
433
|
+
for funding in snapshot.funding:
|
|
434
|
+
if funding.out_ref not in spent:
|
|
435
|
+
tx_builder.add_input(to_pycardano_utxo(funding))
|
|
436
|
+
snapshot.add_actor_additional_utxo(ogmios_entry(funding))
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _returned_bond(position: ClaimPosition) -> TransactionOutput:
|
|
440
|
+
"""The bond UTxO back at the lender manager, as spent.
|
|
441
|
+
|
|
442
|
+
``WithdrawBonds`` checks no output, so a bond whose ADA no longer covers its
|
|
443
|
+
output's minimum is topped up to it.
|
|
444
|
+
"""
|
|
445
|
+
output = to_pycardano_utxo(position.bond).output
|
|
446
|
+
output.amount.coin = max(output.amount.coin, min_ada(output))
|
|
447
|
+
return output
|
|
@@ -19,6 +19,7 @@ from charli3_dendrite.dataclasses.models import Assets
|
|
|
19
19
|
from charli3_dendrite.lending.fluidtokens.transactions._common import reward_address
|
|
20
20
|
from charli3_dendrite.lending.fluidtokens.transactions.utxos import Utxo
|
|
21
21
|
from charli3_dendrite.lending.fluidtokens_v4 import constants as c
|
|
22
|
+
from charli3_dendrite.lending.fluidtokens_v4.datums import AuthCardanoSignature
|
|
22
23
|
from charli3_dendrite.lending.transactions.infra import EvalContext
|
|
23
24
|
from charli3_dendrite.lending.units import constr
|
|
24
25
|
from charli3_dendrite.utility import asset_to_value
|
|
@@ -72,6 +73,18 @@ def settled_min_ada(address: Address, assets: dict[str, int], datum: Datum) -> i
|
|
|
72
73
|
lovelace = needed
|
|
73
74
|
|
|
74
75
|
|
|
76
|
+
def signing_key(auth: Datum, what: str) -> bytes:
|
|
77
|
+
"""The key hash of an ``AuthorizationMethod`` that is a signature.
|
|
78
|
+
|
|
79
|
+
Raises ``NotImplementedError`` for any other authorisation: this library signs
|
|
80
|
+
with wallet keys only. ``what`` names the owned thing in the message.
|
|
81
|
+
"""
|
|
82
|
+
alt, fields = constr(auth)
|
|
83
|
+
if alt != AuthCardanoSignature.CONSTR_ID:
|
|
84
|
+
raise NotImplementedError(f"only a {what} owned by a key is supported")
|
|
85
|
+
return bytes(fields[0])
|
|
86
|
+
|
|
87
|
+
|
|
75
88
|
def sole_nft_name(utxo: Utxo, policy: str, what: str) -> bytes:
|
|
76
89
|
"""The name of the one NFT of ``policy`` a ``what`` UTxO holds."""
|
|
77
90
|
names = [n for p, n, q in utxo.assets if p == policy and q == 1]
|
|
@@ -32,7 +32,6 @@ from charli3_dendrite.lending.fluidtokens.transactions.utxos import Utxo
|
|
|
32
32
|
from charli3_dendrite.lending.fluidtokens.transactions.utxos import ogmios_entry
|
|
33
33
|
from charli3_dendrite.lending.fluidtokens.transactions.utxos import to_pycardano_utxo
|
|
34
34
|
from charli3_dendrite.lending.fluidtokens_v4 import constants as c
|
|
35
|
-
from charli3_dendrite.lending.fluidtokens_v4.datums import AuthCardanoSignature
|
|
36
35
|
from charli3_dendrite.lending.fluidtokens_v4.datums import AuthCardanoWithdrawScript
|
|
37
36
|
from charli3_dendrite.lending.fluidtokens_v4.datums import PoolDatum
|
|
38
37
|
from charli3_dendrite.lending.fluidtokens_v4.datums import PoolManagerDatum
|
|
@@ -42,6 +41,7 @@ from charli3_dendrite.lending.fluidtokens_v4.transactions.common import (
|
|
|
42
41
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import out_ref_of
|
|
43
42
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import pool_nft_name
|
|
44
43
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import script_hash_of
|
|
44
|
+
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import signing_key
|
|
45
45
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import sole_nft_name
|
|
46
46
|
from charli3_dendrite.lending.fluidtokens_v4.transactions.common import (
|
|
47
47
|
withdraw_redeemer_position,
|
|
@@ -77,10 +77,7 @@ def owner_pkh(manager: PoolManagerDatum) -> bytes:
|
|
|
77
77
|
Raises ``NotImplementedError`` for an owner that is not a key: such a pool cannot
|
|
78
78
|
be edited or cancelled with a wallet signature.
|
|
79
79
|
"""
|
|
80
|
-
|
|
81
|
-
if alt != AuthCardanoSignature.CONSTR_ID:
|
|
82
|
-
raise NotImplementedError("only a pool manager owned by a key is supported")
|
|
83
|
-
return bytes(fields[0])
|
|
80
|
+
return signing_key(manager.pool_owner_auth, "pool manager")
|
|
84
81
|
|
|
85
82
|
|
|
86
83
|
@dataclass
|