charli3_dendrite 1.5.17.dev0__tar.gz → 1.5.18.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.17.dev0 → charli3_dendrite-1.5.18.dev0}/PKG-INFO +1 -1
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/pyproject.toml +2 -2
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/cardanoswaps.py +388 -56
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/ob_base.py +14 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/saturnswap.py +54 -12
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/LICENSE +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/README.md +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/backend_base.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/blockfrost/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/blockfrost/models.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/dbsync/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/dbsync/models.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/ogmios_kupo/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/ogmios_kupo/models.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/backend/utils.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dataclasses/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dataclasses/datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dataclasses/models.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/amm_base.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/amm_types.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/cswap.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/dano.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/minswap.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/muesli.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/multi_asset.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/spectrum.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/splash.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/sundae.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/sundae_v4.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/sundae_v4_deployments.json +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/vyfi.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/amm/wingriders.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/core/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/core/base.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/core/errors.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/axo.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/chadswap.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/djed.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/dexs/ob/geniusyield.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/base.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/constants.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/loader.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/market.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/math.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/aggregator_datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/deployments.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/forward.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/leaves.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/locator.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/lp_pricing.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/recipes.json +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/redeemer.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/reproduce.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/oracles/structured_datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/state.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/build.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/context.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/create_loan.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/increase_loan.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/loan_ids.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/modify_collateral.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_redeemer.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/oracle_synth.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/topup_withdraw.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/danogo/transactions/verify.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/constants.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/loader.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/market.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/math.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/feeds.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/fluid_api.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/oracles/witness.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/state.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/_common.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/borrow_terms.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/change_collateral.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/context.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/datum_synth.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/lend.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/pool.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/recast.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/request.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/resolve.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens/transactions/utxos.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/constants.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/datums.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/indexing.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/loader.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/market.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/rates.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/state.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/borrow.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/builder.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/change_collateral.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/claim.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/common.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/lender_bond.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_action.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/loan_terms.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/oracle.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_action.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_cancel.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_create.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_edit.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/pool_terms.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/recast.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/redeemers.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/repay.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/fluidtokens_v4/transactions/resolve.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/markets.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/math.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/normalized.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/charli3.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/dex_pooled.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/fluid.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/models.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/orcfax.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/oracles/qtoken.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/plutus.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/rates.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/registry.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/transactions/__init__.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/transactions/base.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/transactions/infra.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/transactions/snapshot.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.dev0}/src/charli3_dendrite/lending/units.py +0 -0
- {charli3_dendrite-1.5.17.dev0 → charli3_dendrite-1.5.18.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.18-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.18-dev0"
|
|
54
54
|
parse = """(?x)
|
|
55
55
|
(?P<major>\\d+)\\.
|
|
56
56
|
(?P<minor>\\d+)\\.
|
|
@@ -11,13 +11,17 @@ on-chain ``SwapDatum`` and exposes it through the standard order-book interface
|
|
|
11
11
|
are implemented separately.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
+
import dataclasses
|
|
14
15
|
import hashlib
|
|
15
16
|
import time
|
|
16
17
|
from dataclasses import dataclass
|
|
17
18
|
from decimal import Decimal
|
|
19
|
+
from types import SimpleNamespace
|
|
18
20
|
from typing import Union
|
|
21
|
+
from typing import cast
|
|
19
22
|
|
|
20
23
|
from pycardano import Address
|
|
24
|
+
from pycardano import ChainContext
|
|
21
25
|
from pycardano import Network
|
|
22
26
|
from pycardano import PlutusData
|
|
23
27
|
from pycardano import PlutusV2Script
|
|
@@ -28,8 +32,10 @@ from pycardano import TransactionId
|
|
|
28
32
|
from pycardano import TransactionInput
|
|
29
33
|
from pycardano import TransactionOutput
|
|
30
34
|
from pycardano import UTxO
|
|
35
|
+
from pycardano import VerificationKeyHash
|
|
31
36
|
from pycardano import plutus_script_hash
|
|
32
37
|
from pycardano.utils import min_lovelace
|
|
38
|
+
from pycardano.utils import min_lovelace_post_alonzo
|
|
33
39
|
|
|
34
40
|
from charli3_dendrite.backend import get_backend
|
|
35
41
|
from charli3_dendrite.dataclasses.datums import OrderDatum
|
|
@@ -37,6 +43,7 @@ from charli3_dendrite.dataclasses.datums import PlutusNone
|
|
|
37
43
|
from charli3_dendrite.dataclasses.models import Assets
|
|
38
44
|
from charli3_dendrite.dataclasses.models import OrderType
|
|
39
45
|
from charli3_dendrite.dataclasses.models import PoolSelector
|
|
46
|
+
from charli3_dendrite.dexs.core.errors import InvalidPoolError
|
|
40
47
|
from charli3_dendrite.dexs.ob.ob_base import AbstractOrderBookState
|
|
41
48
|
from charli3_dendrite.dexs.ob.ob_base import AbstractOrderState
|
|
42
49
|
from charli3_dendrite.dexs.ob.ob_base import BuyOrderBook
|
|
@@ -154,6 +161,51 @@ def _unit(policy: bytes, name: bytes) -> str:
|
|
|
154
161
|
return policy.hex() + name.hex()
|
|
155
162
|
|
|
156
163
|
|
|
164
|
+
# A staked swap address used only for its size when sizing an output whose owner
|
|
165
|
+
# is not known: every base address (payment + staking credential) serializes to
|
|
166
|
+
# the same 57 bytes, so the credentials themselves never affect the result.
|
|
167
|
+
_SIZING_ADDRESS = Address(
|
|
168
|
+
payment_part=ScriptHash(bytes.fromhex(SWAP_VALIDATOR_HASH)),
|
|
169
|
+
staking_part=VerificationKeyHash(bytes(28)),
|
|
170
|
+
network=Network.MAINNET,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Lovelace balances in [2**16, 2**32) share one CBOR width (a 4-byte argument).
|
|
174
|
+
# Every realistic min-UTxO falls in that range, so sizing starts from a balance
|
|
175
|
+
# inside it and only re-sizes when the minimum lands outside.
|
|
176
|
+
_SIZING_COIN = 1_000_000
|
|
177
|
+
_SIZING_COIN_WIDTH = range(2**16, 2**32)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _min_lovelace_at(output: TransactionOutput, coins_per_utxo_byte: int) -> int:
|
|
181
|
+
"""The ledger min-UTxO of ``output`` at ``coins_per_utxo_byte``.
|
|
182
|
+
|
|
183
|
+
pycardano's rule reads only ``protocol_param.coins_per_utxo_byte`` from the
|
|
184
|
+
chain context, so callers without a context can size outputs too.
|
|
185
|
+
"""
|
|
186
|
+
context = SimpleNamespace(
|
|
187
|
+
protocol_param=SimpleNamespace(coins_per_utxo_byte=coins_per_utxo_byte),
|
|
188
|
+
)
|
|
189
|
+
return min_lovelace_post_alonzo(output, cast(ChainContext, context))
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _self_funded_min_lovelace(
|
|
193
|
+
output: TransactionOutput,
|
|
194
|
+
coins_per_utxo_byte: int,
|
|
195
|
+
) -> int:
|
|
196
|
+
"""The min-UTxO of ``output`` when its lovelace balance is that minimum.
|
|
197
|
+
|
|
198
|
+
The balance's own CBOR width is part of the output size, so a minimum whose
|
|
199
|
+
width differs from the starting balance's is re-sized at the balance it names.
|
|
200
|
+
"""
|
|
201
|
+
output.amount.coin = _SIZING_COIN
|
|
202
|
+
needed = _min_lovelace_at(output, coins_per_utxo_byte)
|
|
203
|
+
if needed in _SIZING_COIN_WIDTH:
|
|
204
|
+
return needed
|
|
205
|
+
output.amount.coin = needed
|
|
206
|
+
return max(needed, _min_lovelace_at(output, coins_per_utxo_byte))
|
|
207
|
+
|
|
208
|
+
|
|
157
209
|
@dataclass
|
|
158
210
|
class CardanoSwapsRational(PlutusData):
|
|
159
211
|
"""A positive rational price (numerator / denominator)."""
|
|
@@ -251,6 +303,218 @@ class CardanoSwapsSwapDatum(OrderDatum):
|
|
|
251
303
|
"""A resting swap order."""
|
|
252
304
|
return OrderType.swap
|
|
253
305
|
|
|
306
|
+
def price(self) -> tuple[int, int]:
|
|
307
|
+
"""The ask-per-offer ``swap_price`` as ``(numerator, denominator)``.
|
|
308
|
+
|
|
309
|
+
The beacon policy only mints for a strictly positive price, but any datum
|
|
310
|
+
can sit in a UTxO, so a zero or negative component is rejected here rather
|
|
311
|
+
than surfacing as a division error in the pricing and fill math.
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
InvalidPoolError: ``swap_price`` is not a positive rational.
|
|
315
|
+
"""
|
|
316
|
+
num = self.swap_price.numerator
|
|
317
|
+
den = self.swap_price.denominator
|
|
318
|
+
if num <= 0 or den <= 0:
|
|
319
|
+
raise InvalidPoolError(
|
|
320
|
+
f"Cardano-Swaps swap_price must be positive, got {num}/{den}.",
|
|
321
|
+
)
|
|
322
|
+
return num, den
|
|
323
|
+
|
|
324
|
+
def required_ask(self, offer_taken: int) -> int:
|
|
325
|
+
"""The least ask the validator accepts for taking ``offer_taken`` of the offer.
|
|
326
|
+
|
|
327
|
+
The validator checks ``offer_taken * numerator <= ask_given * denominator``,
|
|
328
|
+
so the minimum is ``ceil(offer_taken * numerator / denominator)``.
|
|
329
|
+
|
|
330
|
+
Raises:
|
|
331
|
+
InvalidPoolError: ``swap_price`` is not a positive rational.
|
|
332
|
+
"""
|
|
333
|
+
num, den = self.price()
|
|
334
|
+
return -(-offer_taken * num // den)
|
|
335
|
+
|
|
336
|
+
def beacon_assets(self, quantity: int = 1) -> Assets:
|
|
337
|
+
"""The pair, offer and ask beacons, each at ``quantity``."""
|
|
338
|
+
return Assets(
|
|
339
|
+
root={
|
|
340
|
+
BEACON_POLICY_ID + self.pair_beacon.hex(): quantity,
|
|
341
|
+
BEACON_POLICY_ID + self.offer_beacon.hex(): quantity,
|
|
342
|
+
BEACON_POLICY_ID + self.ask_beacon.hex(): quantity,
|
|
343
|
+
},
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
def continuation_datum(
|
|
347
|
+
self,
|
|
348
|
+
tx_hash: bytes,
|
|
349
|
+
output_index: int,
|
|
350
|
+
) -> "CardanoSwapsSwapDatum":
|
|
351
|
+
"""This datum with ``prev_input`` pointing at the consumed ``tx_hash#index``.
|
|
352
|
+
|
|
353
|
+
The validator requires a fill's continuing output to carry the spent datum
|
|
354
|
+
unchanged except for ``prev_input``, which must reference the spent UTxO.
|
|
355
|
+
"""
|
|
356
|
+
return dataclasses.replace(
|
|
357
|
+
self,
|
|
358
|
+
prev_input=CardanoSwapsSomeOutRef(
|
|
359
|
+
value=CardanoSwapsOutputReference(
|
|
360
|
+
transaction_id=CardanoSwapsTxId(tx_hash=tx_hash),
|
|
361
|
+
output_index=output_index,
|
|
362
|
+
),
|
|
363
|
+
),
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def continuation_min_lovelace(
|
|
367
|
+
self,
|
|
368
|
+
held: Assets,
|
|
369
|
+
coins_per_utxo_byte: int,
|
|
370
|
+
*,
|
|
371
|
+
prev_output_index: int = 0,
|
|
372
|
+
address: Address | None = None,
|
|
373
|
+
) -> int:
|
|
374
|
+
"""The min-UTxO of a continuing output of this swap that holds ``held``.
|
|
375
|
+
|
|
376
|
+
The output carries the three beacons, the native tokens in ``held`` (its
|
|
377
|
+
lovelace entry is ignored) and :meth:`continuation_datum` for a spent
|
|
378
|
+
output at ``prev_output_index``. That ``Some`` reference makes it larger
|
|
379
|
+
than the resting output, whose ``prev_input`` is ``None``, so a resting
|
|
380
|
+
UTxO sized only for itself cannot fund its own continuation.
|
|
381
|
+
|
|
382
|
+
The lovelace balance is sized as the minimum itself: the balance a
|
|
383
|
+
continuation is left with once an ADA offer is fully drawn.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
held: The offer and/or ask quantities the continuation holds.
|
|
387
|
+
coins_per_utxo_byte: The ``coins_per_utxo_byte`` protocol parameter.
|
|
388
|
+
prev_output_index: The output index of the spent UTxO, which the
|
|
389
|
+
continuation's ``prev_input`` records.
|
|
390
|
+
address: The swap address; defaults to a staked address of the same
|
|
391
|
+
size as every base address.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
The lovelace the continuing output must hold.
|
|
395
|
+
"""
|
|
396
|
+
tokens = Assets(
|
|
397
|
+
root={
|
|
398
|
+
unit: quantity
|
|
399
|
+
for unit, quantity in held.items()
|
|
400
|
+
if unit != "lovelace" and quantity > 0
|
|
401
|
+
},
|
|
402
|
+
)
|
|
403
|
+
output = TransactionOutput(
|
|
404
|
+
address=address if address is not None else _SIZING_ADDRESS,
|
|
405
|
+
amount=asset_to_value(self.beacon_assets(1) + tokens),
|
|
406
|
+
datum=self.continuation_datum(bytes(32), prev_output_index),
|
|
407
|
+
)
|
|
408
|
+
return _self_funded_min_lovelace(output, coins_per_utxo_byte)
|
|
409
|
+
|
|
410
|
+
def claimable_offer(
|
|
411
|
+
self,
|
|
412
|
+
gross: int,
|
|
413
|
+
coins_per_utxo_byte: int,
|
|
414
|
+
*,
|
|
415
|
+
held_ask: int = 0,
|
|
416
|
+
prev_output_index: int = 0,
|
|
417
|
+
address: Address | None = None,
|
|
418
|
+
) -> int:
|
|
419
|
+
"""The offer a taker can draw from a swap UTxO holding ``gross`` of it.
|
|
420
|
+
|
|
421
|
+
A token offer's min-ADA is a separate lovelace balance, so all of
|
|
422
|
+
``gross`` is claimable. An ADA offer's lovelace also funds the UTxO's
|
|
423
|
+
min-UTxO: a fill must leave the continuing output its minimum, which is
|
|
424
|
+
largest when the output holds the most ask. That is sized as the ask
|
|
425
|
+
already held (``held_ask``) plus the ask for drawing all of ``gross``, an
|
|
426
|
+
upper bound on any single fill, so a fill of the returned amount always
|
|
427
|
+
leaves the continuation funded.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
gross: The offer balance held in the swap UTxO.
|
|
431
|
+
coins_per_utxo_byte: The ``coins_per_utxo_byte`` protocol parameter.
|
|
432
|
+
held_ask: The ask already accumulated in the swap UTxO.
|
|
433
|
+
prev_output_index: The swap UTxO's own output index, which the
|
|
434
|
+
continuation's ``prev_input`` records.
|
|
435
|
+
address: The swap address, when known.
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
The claimable offer quantity, floored at 0.
|
|
439
|
+
|
|
440
|
+
Raises:
|
|
441
|
+
InvalidPoolError: ``swap_price`` is not a positive rational.
|
|
442
|
+
"""
|
|
443
|
+
self.price()
|
|
444
|
+
if self.offer_unit() != "lovelace":
|
|
445
|
+
return gross
|
|
446
|
+
full_ask = held_ask + self.required_ask(gross)
|
|
447
|
+
floor = self.continuation_min_lovelace(
|
|
448
|
+
Assets(root={self.ask_unit(): full_ask}),
|
|
449
|
+
coins_per_utxo_byte,
|
|
450
|
+
prev_output_index=prev_output_index,
|
|
451
|
+
address=address,
|
|
452
|
+
)
|
|
453
|
+
return max(0, gross - floor)
|
|
454
|
+
|
|
455
|
+
def carrier_lovelace(
|
|
456
|
+
self,
|
|
457
|
+
offer_quantity: int,
|
|
458
|
+
coins_per_utxo_byte: int,
|
|
459
|
+
*,
|
|
460
|
+
prev_output_index: int = 0,
|
|
461
|
+
address: Address | None = None,
|
|
462
|
+
) -> int:
|
|
463
|
+
"""The lovelace a new swap offering ``offer_quantity`` funds for its min-UTxO.
|
|
464
|
+
|
|
465
|
+
It is sized for the largest continuation the swap can reach, so no fill
|
|
466
|
+
has to top the output up and the whole offer stays claimable:
|
|
467
|
+
|
|
468
|
+
* ADA offer: funded on top of the offer. A full fill leaves the output
|
|
469
|
+
holding only this carrier, the beacons and the full ask, and
|
|
470
|
+
:meth:`claimable_offer` sizes that ask on the whole balance, so the
|
|
471
|
+
carrier is the fixed point ``c = min_utxo(required_ask(offer + c))``.
|
|
472
|
+
Then ``claimable_offer(offer + c) == offer``.
|
|
473
|
+
* Token offer: funded as the output's whole lovelace balance. A
|
|
474
|
+
continuation holds at most the full offer and, when the ask is also a
|
|
475
|
+
token, the full ask, so both are sized in.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
offer_quantity: The offered quantity.
|
|
479
|
+
coins_per_utxo_byte: The ``coins_per_utxo_byte`` protocol parameter.
|
|
480
|
+
prev_output_index: The output index the swap UTxO is created at.
|
|
481
|
+
address: The swap address, when known.
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
The carrier lovelace.
|
|
485
|
+
|
|
486
|
+
Raises:
|
|
487
|
+
InvalidPoolError: ``swap_price`` is not a positive rational.
|
|
488
|
+
"""
|
|
489
|
+
self.price()
|
|
490
|
+
ask_unit = self.ask_unit()
|
|
491
|
+
if self.offer_unit() == "lovelace":
|
|
492
|
+
# The minimum grows with the ask's CBOR width, which grows with the
|
|
493
|
+
# carrier, so iterate from zero; the sequence never decreases and the
|
|
494
|
+
# width takes only a few values, so it settles within a few steps.
|
|
495
|
+
carrier = 0
|
|
496
|
+
while True:
|
|
497
|
+
needed = self.continuation_min_lovelace(
|
|
498
|
+
Assets(
|
|
499
|
+
root={ask_unit: self.required_ask(offer_quantity + carrier)},
|
|
500
|
+
),
|
|
501
|
+
coins_per_utxo_byte,
|
|
502
|
+
prev_output_index=prev_output_index,
|
|
503
|
+
address=address,
|
|
504
|
+
)
|
|
505
|
+
if needed <= carrier:
|
|
506
|
+
return carrier
|
|
507
|
+
carrier = needed
|
|
508
|
+
held = {self.offer_unit(): offer_quantity}
|
|
509
|
+
if ask_unit != "lovelace":
|
|
510
|
+
held[ask_unit] = self.required_ask(offer_quantity)
|
|
511
|
+
return self.continuation_min_lovelace(
|
|
512
|
+
Assets(root=held),
|
|
513
|
+
coins_per_utxo_byte,
|
|
514
|
+
prev_output_index=prev_output_index,
|
|
515
|
+
address=address,
|
|
516
|
+
)
|
|
517
|
+
|
|
254
518
|
|
|
255
519
|
class CardanoSwapsOrderState(AbstractOrderState):
|
|
256
520
|
"""A resting Cardano-Swaps v2 one-way swap UTxO.
|
|
@@ -336,24 +600,61 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
336
600
|
|
|
337
601
|
@property
|
|
338
602
|
def price(self) -> tuple[int, int]:
|
|
339
|
-
"""Ask-per-offer price as ``(numerator, denominator)``.
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
603
|
+
"""Ask-per-offer price as ``(numerator, denominator)``.
|
|
604
|
+
|
|
605
|
+
A UTxO whose datum has a non-positive ``swap_price`` still parses, so a
|
|
606
|
+
caller can skip it on this error instead of failing a whole book.
|
|
607
|
+
|
|
608
|
+
Raises:
|
|
609
|
+
InvalidPoolError: the datum's ``swap_price`` is not a positive rational.
|
|
610
|
+
"""
|
|
611
|
+
return self.order_datum.price()
|
|
344
612
|
|
|
345
613
|
@property
|
|
346
614
|
def available(self) -> Assets:
|
|
347
|
-
"""
|
|
615
|
+
"""The offer balance held in the UTxO.
|
|
348
616
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
617
|
+
The contract has no separate offered-amount field, so the held balance is
|
|
618
|
+
the only signal. For an ADA offer it includes the lovelace the continuing
|
|
619
|
+
output must keep as its min-UTxO, so it is an upper bound on what a fill
|
|
620
|
+
can take; :meth:`claimable_offer` nets that out, and :meth:`swap_utxo`
|
|
621
|
+
rejects a fill that takes more.
|
|
354
622
|
"""
|
|
355
623
|
return Assets(root={self.out_unit: self.assets[self.out_unit]})
|
|
356
624
|
|
|
625
|
+
def required_ask(self, offer_taken: int) -> int:
|
|
626
|
+
"""The ask a fill taking ``offer_taken`` of the offer pays into the swap.
|
|
627
|
+
|
|
628
|
+
This is exactly what :meth:`swap_utxo` deposits into the continuing output.
|
|
629
|
+
|
|
630
|
+
Raises:
|
|
631
|
+
InvalidPoolError: the datum's ``swap_price`` is not a positive rational.
|
|
632
|
+
"""
|
|
633
|
+
return self.order_datum.required_ask(offer_taken)
|
|
634
|
+
|
|
635
|
+
def claimable_offer(self, coins_per_utxo_byte: int) -> int:
|
|
636
|
+
"""The most of the offer one fill of this UTxO can take.
|
|
637
|
+
|
|
638
|
+
:meth:`CardanoSwapsSwapDatum.claimable_offer` over this UTxO's offer
|
|
639
|
+
balance and accumulated ask, sized at its own output index (which the
|
|
640
|
+
continuation's ``prev_input`` records) and at its address when known. A
|
|
641
|
+
:meth:`swap_utxo` fill of this amount always leaves the continuing output
|
|
642
|
+
funded.
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
coins_per_utxo_byte: The ``coins_per_utxo_byte`` protocol parameter.
|
|
646
|
+
|
|
647
|
+
Raises:
|
|
648
|
+
InvalidPoolError: the datum's ``swap_price`` is not a positive rational.
|
|
649
|
+
"""
|
|
650
|
+
return self.order_datum.claimable_offer(
|
|
651
|
+
self.assets[self.out_unit],
|
|
652
|
+
coins_per_utxo_byte,
|
|
653
|
+
held_ask=self.assets[self.in_unit],
|
|
654
|
+
prev_output_index=self.tx_index,
|
|
655
|
+
address=Address.decode(self.address) if self.address is not None else None,
|
|
656
|
+
)
|
|
657
|
+
|
|
357
658
|
@property
|
|
358
659
|
def tvl(self) -> int:
|
|
359
660
|
"""Total value locked in the order (the available offer asset)."""
|
|
@@ -508,13 +809,7 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
508
809
|
@staticmethod
|
|
509
810
|
def _beacon_mint_assets(datum: CardanoSwapsSwapDatum, quantity: int) -> Assets:
|
|
510
811
|
"""The three beacons (pair/offer/ask) at +1 (CREATE) or -1 (CLOSE)."""
|
|
511
|
-
return
|
|
512
|
-
root={
|
|
513
|
-
BEACON_POLICY_ID + datum.pair_beacon.hex(): quantity,
|
|
514
|
-
BEACON_POLICY_ID + datum.offer_beacon.hex(): quantity,
|
|
515
|
-
BEACON_POLICY_ID + datum.ask_beacon.hex(): quantity,
|
|
516
|
-
},
|
|
517
|
-
)
|
|
812
|
+
return datum.beacon_assets(quantity)
|
|
518
813
|
|
|
519
814
|
@staticmethod
|
|
520
815
|
def _accumulate_mint(tx_builder: TransactionBuilder, mint_assets: Assets) -> None:
|
|
@@ -544,6 +839,11 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
544
839
|
beacon-tagged swap address carrying the offer asset, the three beacons
|
|
545
840
|
and an inline ``SwapDatum``. No swap-UTxO is spent.
|
|
546
841
|
|
|
842
|
+
The output's lovelace is funded for the largest continuation the swap
|
|
843
|
+
reaches (see :meth:`CardanoSwapsSwapDatum.carrier_lovelace`), sized at the
|
|
844
|
+
output index this output is added at, so the whole offer can be taken by
|
|
845
|
+
:meth:`swap_utxo` without the taker topping the output up.
|
|
846
|
+
|
|
547
847
|
Args:
|
|
548
848
|
owner_address: The owner's address; its staking credential identifies
|
|
549
849
|
the owner and is carried onto the swap address.
|
|
@@ -558,6 +858,9 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
558
858
|
|
|
559
859
|
Returns:
|
|
560
860
|
The swap output and its inline ``SwapDatum``.
|
|
861
|
+
|
|
862
|
+
Raises:
|
|
863
|
+
ValueError: ``price`` is not a positive rational.
|
|
561
864
|
"""
|
|
562
865
|
offer_unit = offer.unit()
|
|
563
866
|
ask_unit = ask.unit()
|
|
@@ -565,6 +868,8 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
565
868
|
ask_id, ask_name = cls._split_unit(ask_unit)
|
|
566
869
|
|
|
567
870
|
num, den = price
|
|
871
|
+
if num <= 0 or den <= 0:
|
|
872
|
+
raise ValueError(f"price must be a positive rational, got {num}/{den}.")
|
|
568
873
|
exp = (
|
|
569
874
|
CardanoSwapsSomeInt(value=expiration)
|
|
570
875
|
if expiration is not None
|
|
@@ -599,31 +904,23 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
599
904
|
amount=asset_to_value(output_assets),
|
|
600
905
|
datum=datum,
|
|
601
906
|
)
|
|
907
|
+
# The validator derives an ADA offer's ``offer_taken`` as
|
|
908
|
+
# ``lovelace_in - lovelace_out``, so a fill can never draw the UTxO below
|
|
909
|
+
# the min-UTxO of its continuation, whose ``prev_input`` records the spent
|
|
910
|
+
# UTxO. Fund a carrier for that continuation: on top of an ADA offer, or
|
|
911
|
+
# as the lovelace of a token offer. Its first fill spends this output at
|
|
912
|
+
# the index it is added at. The maker reclaims the carrier on CLOSE.
|
|
913
|
+
carrier = datum.carrier_lovelace(
|
|
914
|
+
offer.quantity(),
|
|
915
|
+
tx_builder.context.protocol_param.coins_per_utxo_byte,
|
|
916
|
+
prev_output_index=len(tx_builder.outputs),
|
|
917
|
+
address=swap_address,
|
|
918
|
+
)
|
|
602
919
|
if offer_unit == "lovelace":
|
|
603
|
-
# ADA offer: the offered asset IS the UTxO's min-ADA, and the
|
|
604
|
-
# validator derives ``offer_taken = lovelace_in - lovelace_out``, so a
|
|
605
|
-
# taker can never draw the UTxO below its min-ADA floor — the tail of
|
|
606
|
-
# the stated offer would be un-fillable. Fund a SEPARATE carrier on
|
|
607
|
-
# top of the offer, sized to the FINAL full-fill state (3 beacons +
|
|
608
|
-
# the fully-accumulated ask asset + inline datum), so the entire
|
|
609
|
-
# offer is drawable while the UTxO stays at/above that floor. The
|
|
610
|
-
# maker reclaims the carrier (plus the accumulated ask) on CLOSE.
|
|
611
|
-
full_ask = -(-offer.quantity() * num // den) # ceil(offer x price)
|
|
612
|
-
final_assets = cls._beacon_mint_assets(datum, 1) + Assets(
|
|
613
|
-
root={ask_unit: full_ask},
|
|
614
|
-
)
|
|
615
|
-
final_txo = TransactionOutput(
|
|
616
|
-
address=swap_address,
|
|
617
|
-
amount=asset_to_value(final_assets),
|
|
618
|
-
datum=datum,
|
|
619
|
-
)
|
|
620
|
-
carrier = min_lovelace(tx_builder.context, output=final_txo)
|
|
621
920
|
txo.amount.coin = offer.quantity() + carrier
|
|
622
921
|
else:
|
|
623
|
-
# Token offer: the offered token fully leaves on a fill and the
|
|
624
|
-
# min-ADA is a separate lovelace carrier (no phantom tail).
|
|
625
922
|
txo.amount.coin = max(
|
|
626
|
-
|
|
923
|
+
carrier,
|
|
627
924
|
min_lovelace(tx_builder.context, output=txo),
|
|
628
925
|
)
|
|
629
926
|
tx_builder.add_output(txo)
|
|
@@ -685,12 +982,25 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
685
982
|
``out_assets`` is the offer asset the taker receives; ``in_assets`` is the
|
|
686
983
|
ask asset they pay. Purity (only offer leaves, only ask is added) and the
|
|
687
984
|
``offer_taken * price_num <= ask_given * price_den`` price check are
|
|
688
|
-
enforced by the validator; this builder constructs a balanced fill.
|
|
985
|
+
enforced by the validator; this builder constructs a balanced fill. The
|
|
986
|
+
ask deposited is :meth:`required_ask` of the offer taken; ``in_assets``
|
|
987
|
+
only selects the ask asset.
|
|
988
|
+
|
|
989
|
+
A token offer's continuation is topped up to its min-UTxO when needed (the
|
|
990
|
+
validator lets a taker deposit ADA). An ADA offer's cannot be: the lovelace
|
|
991
|
+
left behind is what sets ``offer_taken``, so a fill that would leave the
|
|
992
|
+
continuation below its min-UTxO is rejected; :meth:`claimable_offer` is the
|
|
993
|
+
most a fill can take.
|
|
689
994
|
|
|
690
995
|
Returns:
|
|
691
996
|
``(continuing_output, continuing_datum)`` — the validator always
|
|
692
997
|
requires a continuing beacon output (a full fill simply leaves the
|
|
693
998
|
offer balance at ~0); only CLOSE removes the beacons.
|
|
999
|
+
|
|
1000
|
+
Raises:
|
|
1001
|
+
ValueError: the assets are not the offer and ask, or the fill takes
|
|
1002
|
+
more of the offer than the UTxO can release.
|
|
1003
|
+
InvalidPoolError: the datum's ``swap_price`` is not a positive rational.
|
|
694
1004
|
"""
|
|
695
1005
|
owner = owner_address if owner_address is not None else address_source
|
|
696
1006
|
|
|
@@ -703,11 +1013,14 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
703
1013
|
offer_unit = self.out_unit
|
|
704
1014
|
ask_unit = self.in_unit
|
|
705
1015
|
|
|
706
|
-
num, den = self.price
|
|
707
1016
|
offer_taken = out_assets.quantity()
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1017
|
+
held_offer = self.assets[offer_unit]
|
|
1018
|
+
if offer_taken <= 0 or offer_taken > held_offer:
|
|
1019
|
+
raise ValueError(
|
|
1020
|
+
f"out_assets must take between 1 and {held_offer} of the offer, "
|
|
1021
|
+
f"got {offer_taken}.",
|
|
1022
|
+
)
|
|
1023
|
+
ask_given = self.required_ask(offer_taken)
|
|
711
1024
|
|
|
712
1025
|
input_utxo = self._input_utxo(owner)
|
|
713
1026
|
|
|
@@ -728,12 +1041,9 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
728
1041
|
# no separate maker payment; the maker collects the accumulated ask on
|
|
729
1042
|
# CLOSE. The datum is identical to the input EXCEPT prev_input = consumed
|
|
730
1043
|
# TxOutRef.
|
|
731
|
-
cont_datum =
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
transaction_id=CardanoSwapsTxId(tx_hash=bytes.fromhex(self.tx_hash)),
|
|
735
|
-
output_index=self.tx_index,
|
|
736
|
-
),
|
|
1044
|
+
cont_datum = self.order_datum.continuation_datum(
|
|
1045
|
+
bytes.fromhex(self.tx_hash),
|
|
1046
|
+
self.tx_index,
|
|
737
1047
|
)
|
|
738
1048
|
|
|
739
1049
|
# Continuing value = consumed value, less the offer taken, plus the ask
|
|
@@ -759,10 +1069,15 @@ class CardanoSwapsOrderState(AbstractOrderState):
|
|
|
759
1069
|
amount=asset_to_value(cont_assets),
|
|
760
1070
|
datum=cont_datum,
|
|
761
1071
|
)
|
|
762
|
-
cont_txo.amount.coin
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1072
|
+
coin = cont_txo.amount.coin
|
|
1073
|
+
needed = min_lovelace(tx_builder.context, output=cont_txo)
|
|
1074
|
+
if offer_unit == "lovelace" and coin < needed:
|
|
1075
|
+
raise ValueError(
|
|
1076
|
+
f"Taking {offer_taken} lovelace leaves the continuing output "
|
|
1077
|
+
f"{coin} lovelace, below its min-UTxO of {needed}; "
|
|
1078
|
+
"claimable_offer() is the most a fill can take.",
|
|
1079
|
+
)
|
|
1080
|
+
cont_txo.amount.coin = max(coin, needed)
|
|
766
1081
|
tx_builder.add_output(cont_txo)
|
|
767
1082
|
|
|
768
1083
|
return cont_txo, cont_datum
|
|
@@ -865,7 +1180,11 @@ class CardanoSwapsOrderBook(AbstractOrderBookState):
|
|
|
865
1180
|
for order in orders:
|
|
866
1181
|
if order.inactive:
|
|
867
1182
|
continue
|
|
868
|
-
|
|
1183
|
+
try:
|
|
1184
|
+
num, denom = order.price
|
|
1185
|
+
except InvalidPoolError:
|
|
1186
|
+
# A malformed swap_price cannot be priced or filled.
|
|
1187
|
+
continue
|
|
869
1188
|
o = OrderBookOrder(
|
|
870
1189
|
price=num / denom,
|
|
871
1190
|
quantity=int(order.available.quantity()),
|
|
@@ -960,13 +1279,17 @@ class CardanoSwapsOrderBook(AbstractOrderBookState):
|
|
|
960
1279
|
fill is threaded the maker's real owner — the resting UTxO's staking
|
|
961
1280
|
credential, carried on the order's ``address`` — so the continuing output
|
|
962
1281
|
lands back at the correct beacon-tagged swap address (defaulting the owner
|
|
963
|
-
to the taker would reconstruct the wrong input and fail validation).
|
|
1282
|
+
to the taker would reconstruct the wrong input and fail validation). Each
|
|
1283
|
+
fill is capped at the order's claimable offer, so an ADA offer's
|
|
1284
|
+
continuation keeps its min-UTxO; an order with nothing claimable is
|
|
1285
|
+
skipped.
|
|
964
1286
|
"""
|
|
965
1287
|
if in_assets.unit() == self.assets.unit():
|
|
966
1288
|
book = self.sell_book_full
|
|
967
1289
|
else:
|
|
968
1290
|
book = self.buy_book_full
|
|
969
1291
|
|
|
1292
|
+
coins_per_utxo_byte = tx_builder.context.protocol_param.coins_per_utxo_byte
|
|
970
1293
|
in_remaining = Assets.model_validate(in_assets.model_dump())
|
|
971
1294
|
txo = None
|
|
972
1295
|
datum = None
|
|
@@ -980,6 +1303,15 @@ class CardanoSwapsOrderBook(AbstractOrderBookState):
|
|
|
980
1303
|
if order_out.quantity() <= 0 or order_in.quantity() <= 0:
|
|
981
1304
|
break
|
|
982
1305
|
|
|
1306
|
+
claimable = state.claimable_offer(coins_per_utxo_byte)
|
|
1307
|
+
if claimable <= 0:
|
|
1308
|
+
continue
|
|
1309
|
+
if order_out.quantity() > claimable:
|
|
1310
|
+
order_out = Assets(root={state.out_unit: claimable})
|
|
1311
|
+
order_in = Assets(
|
|
1312
|
+
root={state.in_unit: state.required_ask(claimable)},
|
|
1313
|
+
)
|
|
1314
|
+
|
|
983
1315
|
if state.address is None:
|
|
984
1316
|
raise ValueError(
|
|
985
1317
|
"Cardano-Swaps order-book fill requires each resting order's "
|
|
@@ -405,6 +405,20 @@ class AbstractOrderBookState(AbstractPairState):
|
|
|
405
405
|
|
|
406
406
|
return in_assets, 0
|
|
407
407
|
|
|
408
|
+
@property
|
|
409
|
+
def taker_fee_bps(self) -> int:
|
|
410
|
+
"""Taker fee, in basis points, that the book's level walk charges a fill.
|
|
411
|
+
|
|
412
|
+
The level walk (``get_amount_out`` / ``get_amount_in`` with ``apply_fee``)
|
|
413
|
+
charges the book's own ``fee``, so that is the fee reported here, or 0
|
|
414
|
+
when the book has none. A book whose walk leaves the fee to each order
|
|
415
|
+
overrides this.
|
|
416
|
+
"""
|
|
417
|
+
fee = self.fee
|
|
418
|
+
if isinstance(fee, list):
|
|
419
|
+
return max(fee, default=0)
|
|
420
|
+
return fee or 0
|
|
421
|
+
|
|
408
422
|
@classmethod
|
|
409
423
|
def reference_utxo(self) -> UTxO | None:
|
|
410
424
|
return None
|