Copyright | © 2021 IOHK |
---|---|
License | Apache-2.0 |
Safe Haskell | None |
Language | Haskell2010 |
Provides an algorithm for producing a balanced coin selection with change, where the fee is paid for.
This module uses the Random-Round-Robin coin selection algorithm for multi-asset UTxO sets.
See documentation for the
performSelection
function for more details on
how to perform a selection.
Synopsis
- type PerformSelection m f ctx = SelectionConstraints ctx -> SelectionParamsOf f ctx -> m ( Either ( SelectionBalanceError ctx) ( SelectionResultOf f ctx))
- performSelection :: forall m ctx. ( HasCallStack , MonadRandom m, SelectionContext ctx) => PerformSelection m [] ctx
- performSelectionEmpty :: forall m ctx. Functor m => PerformSelection m NonEmpty ctx -> PerformSelection m [] ctx
-
data
SelectionConstraints
ctx =
SelectionConstraints
{
- assessTokenBundleSize :: TokenBundle -> TokenBundleSizeAssessment
- computeMinimumAdaQuantity :: Address ctx -> TokenMap -> Coin
- computeMinimumCost :: SelectionSkeleton ctx -> Coin
- computeSelectionLimit :: [( Address ctx, TokenBundle )] -> SelectionLimit
- maximumLengthChangeAddress :: Address ctx
- maximumOutputAdaQuantity :: Coin
- maximumOutputTokenQuantity :: TokenQuantity
- nullAddress :: Address ctx
- type SelectionParams = SelectionParamsOf []
-
data
SelectionParamsOf
f ctx =
SelectionParams
{
- outputsToCover :: !(f ( Address ctx, TokenBundle ))
- utxoAvailable :: !( UTxOSelection ( UTxO ctx))
- extraCoinSource :: ! Coin
- extraCoinSink :: ! Coin
- assetsToMint :: ! TokenMap
- assetsToBurn :: ! TokenMap
- selectionStrategy :: SelectionStrategy
-
data
SelectionSkeleton
ctx =
SelectionSkeleton
{
- skeletonInputCount :: ! Int
- skeletonOutputs :: ![( Address ctx, TokenBundle )]
- skeletonChange :: ![ Set AssetId ]
- type SelectionResult = SelectionResultOf []
-
data
SelectionResultOf
f ctx =
SelectionResult
{
- inputsSelected :: !( NonEmpty ( UTxO ctx, TokenBundle ))
- extraCoinSource :: ! Coin
- extraCoinSink :: ! Coin
- outputsCovered :: !(f ( Address ctx, TokenBundle ))
- changeGenerated :: ![ TokenBundle ]
- assetsToMint :: ! TokenMap
- assetsToBurn :: ! TokenMap
- data SelectionStrategy
- data SelectionBalanceError ctx
- data BalanceInsufficientError = BalanceInsufficientError { }
-
data
UnableToConstructChangeError
=
UnableToConstructChangeError
{
- requiredCost :: ! Coin
- shortfall :: ! Coin
- type SelectionLimit = SelectionLimitOf Int
-
data
SelectionLimitOf
a
- = NoLimit
- | MaximumInputLimit a
- selectionLimitExceeded :: IsUTxOSelection s u => s u -> SelectionLimit -> Bool
-
data
SelectionLimitReachedError
ctx =
SelectionLimitReachedError
{
- utxoBalanceRequired :: ! TokenBundle
- inputsSelected :: ![( UTxO ctx, TokenBundle )]
- outputsToCover :: !( NonEmpty ( Address ctx, TokenBundle ))
- reduceSelectionLimitBy :: SelectionLimit -> Int -> SelectionLimit
-
data
SelectionDelta
a
- = SelectionSurplus a
- | SelectionDeficit a
- selectionDeltaAllAssets :: Foldable f => SelectionResultOf f ctx -> SelectionDelta TokenBundle
- selectionDeltaCoin :: Foldable f => SelectionResultOf f ctx -> SelectionDelta Coin
- selectionHasValidSurplus :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Bool
- selectionSurplusCoin :: Foldable f => SelectionResultOf f ctx -> Coin
- selectionMinimumCost :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Coin
- selectionMaximumCost :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Coin
- selectionSkeleton :: Foldable f => SelectionResultOf f ctx -> SelectionSkeleton ctx
- data UTxOBalanceSufficiency
- data UTxOBalanceSufficiencyInfo = UTxOBalanceSufficiencyInfo { }
- computeBalanceInOut :: Foldable f => SelectionParamsOf f ctx -> ( TokenBundle , TokenBundle )
- computeDeficitInOut :: Foldable f => SelectionParamsOf f ctx -> ( TokenBundle , TokenBundle )
- computeUTxOBalanceAvailable :: SelectionParamsOf f ctx -> TokenBundle
- computeUTxOBalanceRequired :: Foldable f => SelectionParamsOf f ctx -> TokenBundle
- computeUTxOBalanceSufficiency :: Foldable f => SelectionParamsOf f ctx -> UTxOBalanceSufficiency
- computeUTxOBalanceSufficiencyInfo :: Foldable f => SelectionParamsOf f ctx -> UTxOBalanceSufficiencyInfo
- isUTxOBalanceSufficient :: Foldable f => SelectionParamsOf f ctx -> Bool
- runSelection :: forall m u. ( MonadRandom m, Ord u) => RunSelectionParams u -> m ( UTxOSelection u)
- runSelectionNonEmpty :: ( MonadRandom m, Ord u) => RunSelectionParams u -> m ( Maybe ( UTxOSelectionNonEmpty u))
- runSelectionNonEmptyWith :: Monad m => ( UTxOSelection u -> m ( Maybe ( UTxOSelectionNonEmpty u))) -> UTxOSelection u -> m ( Maybe ( UTxOSelectionNonEmpty u))
- data RunSelectionParams u = RunSelectionParams { }
- runSelectionStep :: forall m state state'. Monad m => SelectionLens m state state' -> state -> m ( Maybe state')
-
data
SelectionLens
m state state' =
SelectionLens
{
- currentQuantity :: state -> Natural
- updatedQuantity :: state' -> Natural
- selectQuantity :: state -> m ( Maybe state')
- minimumQuantity :: Natural
- selectionStrategy :: SelectionStrategy
- assetSelectionLens :: ( MonadRandom m, Ord u) => SelectionLimit -> SelectionStrategy -> ( AssetId , TokenQuantity ) -> SelectionLens m ( UTxOSelection u) ( UTxOSelectionNonEmpty u)
- coinSelectionLens :: ( MonadRandom m, Ord u) => SelectionLimit -> SelectionStrategy -> Coin -> SelectionLens m ( UTxOSelection u) ( UTxOSelectionNonEmpty u)
-
data
MakeChangeCriteria
minCoinFor bundleSizeAssessor =
MakeChangeCriteria
{
- minCoinFor :: minCoinFor
- bundleSizeAssessor :: bundleSizeAssessor
- requiredCost :: Coin
- extraCoinSource :: Coin
- extraCoinSink :: Coin
- inputBundles :: NonEmpty TokenBundle
- outputBundles :: NonEmpty TokenBundle
- assetsToMint :: TokenMap
- assetsToBurn :: TokenMap
- maximumOutputAdaQuantity :: Coin
- maximumOutputTokenQuantity :: TokenQuantity
- makeChange :: MakeChangeCriteria ( TokenMap -> Coin ) TokenBundleSizeAssessor -> Either UnableToConstructChangeError [ TokenBundle ]
- makeChangeForCoin :: HasCallStack => NonEmpty Coin -> Coin -> NonEmpty Coin
- makeChangeForUserSpecifiedAsset :: NonEmpty TokenMap -> ( AssetId , TokenQuantity ) -> NonEmpty TokenMap
- makeChangeForNonUserSpecifiedAsset :: NonEmpty a -> ( AssetId , NonEmpty TokenQuantity ) -> NonEmpty TokenMap
- makeChangeForNonUserSpecifiedAssets :: NonEmpty a -> Map AssetId ( NonEmpty TokenQuantity ) -> NonEmpty TokenMap
- assignCoinsToChangeMaps :: HasCallStack => Coin -> ( TokenMap -> Coin ) -> NonEmpty ( TokenMap , Coin ) -> Either Coin [ TokenBundle ]
- collateNonUserSpecifiedAssetQuantities :: NonEmpty TokenMap -> Set AssetId -> Map AssetId ( NonEmpty TokenQuantity )
- addMintValueToChangeMaps :: ( AssetId , TokenQuantity ) -> NonEmpty TokenMap -> NonEmpty TokenMap
- addMintValuesToChangeMaps :: TokenMap -> NonEmpty TokenMap -> NonEmpty TokenMap
- removeBurnValueFromChangeMaps :: ( AssetId , TokenQuantity ) -> NonEmpty TokenMap -> NonEmpty TokenMap
- removeBurnValuesFromChangeMaps :: TokenMap -> NonEmpty TokenMap -> NonEmpty TokenMap
- reduceTokenQuantities :: TokenQuantity -> NonEmpty TokenQuantity -> NonEmpty TokenQuantity
- splitBundleIfAssetCountExcessive :: TokenBundle -> ( TokenBundle -> Bool ) -> NonEmpty TokenBundle
- splitBundlesWithExcessiveAssetCounts :: NonEmpty TokenBundle -> ( TokenBundle -> Bool ) -> NonEmpty TokenBundle
- splitBundlesWithExcessiveTokenQuantities :: NonEmpty TokenBundle -> TokenQuantity -> NonEmpty TokenBundle
- groupByKey :: forall k v. Ord k => [(k, v)] -> Map k ( NonEmpty v)
- ungroupByKey :: forall k v. Map k ( NonEmpty v) -> [(k, v)]
- runRoundRobin :: s -> (s' -> s) -> [s -> Maybe s'] -> s
- runRoundRobinM :: Monad m => s -> (s' -> s) -> [s -> m ( Maybe s')] -> m s
-
newtype
AssetCount
a =
AssetCount
{
- unAssetCount :: a
- distance :: Natural -> Natural -> Natural
- mapMaybe :: (a -> Maybe b) -> NonEmpty a -> [b]
- balanceMissing :: BalanceInsufficientError -> TokenBundle
Performing a selection
type PerformSelection m f ctx = SelectionConstraints ctx -> SelectionParamsOf f ctx -> m ( Either ( SelectionBalanceError ctx) ( SelectionResultOf f ctx)) Source #
performSelection :: forall m ctx. ( HasCallStack , MonadRandom m, SelectionContext ctx) => PerformSelection m [] ctx Source #
Performs a coin selection and generates change bundles in one step.
Provided that
isUTxOBalanceSufficient
returns
True
for the given
selection criteria, this function guarantees to return a
SelectionResult
for which
selectionHasValidSurplus
returns
True
.
performSelectionEmpty :: forall m ctx. Functor m => PerformSelection m NonEmpty ctx -> PerformSelection m [] ctx Source #
Transforms a coin selection function that requires a non-empty list of outputs into a function that accepts an empty list of outputs.
If the original list is already non-empty, this function does not alter the parameters or the result in any way, such that:
params == transformParams params result == transformResult result
If the original list is empty, this function:
-
applies a balance-preserving transformation to the parameters, adding a single minimal ada-only output to act as a change generation target, such that:
computeUTxOBalanceSufficiencyInfo params == computeUTxOBalanceSufficiencyInfo (transformParams params)
-
applies an inverse transformation to the result, removing the output, such that:
selectionSurplus result == selectionSurplus (transformResult result)
selectionHasValidSurplus constraints result ==> selectionHasValidSurplus constraints (transformResult result)
data SelectionConstraints ctx Source #
Specifies all constraints required for coin selection.
Selection constraints:
- place limits on the coin selection algorithm, enabling it to produce selections that are acceptable to the ledger.
- are dependent on the current set of protocol parameters.
- are not specific to a given selection.
SelectionConstraints | |
|
Instances
type SelectionParams = SelectionParamsOf [] Source #
data SelectionParamsOf f ctx Source #
Specifies all parameters that are specific to a given selection.
SelectionParams | |
|
Instances
data SelectionSkeleton ctx Source #
A skeleton selection that can be used to estimate the cost of a final selection.
Change outputs are deliberately stripped of their asset quantities, as the fee estimation function must be agnostic to the magnitudes of these quantities.
Increasing or decreasing the quantity of a particular asset in a change output must not change the estimated cost of a selection.
SelectionSkeleton | |
|
Instances
type SelectionResult = SelectionResultOf [] Source #
data SelectionResultOf f ctx Source #
The result of performing a successful selection.
SelectionResult | |
|
Instances
data SelectionStrategy Source #
Indicates a choice of selection strategy.
A
SelectionStrategy
determines
how much
of each asset the selection
algorithm will attempt to select from the available UTxO set, relative to
the minimum amount necessary to make the selection balance.
The default
SelectionStrategy
is
SelectionStrategyOptimal
, which when
specified will cause the selection algorithm to attempt to select around
twice
the minimum possible amount of each asset from the available
UTxO set, making it possible to generate change outputs that are roughly
the same sizes and shapes as the user-specified outputs.
Specifying
SelectionStrategyMinimal
will cause the selection algorithm to
only select
just enough
of each asset from the available UTxO set to
meet the minimum amount. The selection process will terminate as soon as
the minimum amount of each asset is covered.
The "optimal" strategy is recommended for most situations, as using this strategy will help to ensure that a wallet's UTxO distribution can evolve over time to resemble the typical distribution of payments made by the wallet owner. This increases the likelihood that future selections will succeed, and lowers the amortized cost of future transactions.
The "minimal" strategy is recommended only for situations where it is not possible to create a selection with the "optimal" strategy. It is advised to use this strategy only when necessary, as it increases the likelihood of generating change outputs that are much smaller than user-specified outputs. If this strategy is used regularly, the UTxO set can evolve to a state where the distribution no longer resembles the typical distribution of payments made by the user. This increases the likelihood that future selections will not succeed, and increases the amortized cost of future transactions.
Instances
Bounded SelectionStrategy Source # | |
Enum SelectionStrategy Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance succ :: SelectionStrategy -> SelectionStrategy Source # pred :: SelectionStrategy -> SelectionStrategy Source # toEnum :: Int -> SelectionStrategy Source # fromEnum :: SelectionStrategy -> Int Source # enumFrom :: SelectionStrategy -> [ SelectionStrategy ] Source # enumFromThen :: SelectionStrategy -> SelectionStrategy -> [ SelectionStrategy ] Source # enumFromTo :: SelectionStrategy -> SelectionStrategy -> [ SelectionStrategy ] Source # enumFromThenTo :: SelectionStrategy -> SelectionStrategy -> SelectionStrategy -> [ SelectionStrategy ] Source # |
|
Eq SelectionStrategy Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance (==) :: SelectionStrategy -> SelectionStrategy -> Bool Source # (/=) :: SelectionStrategy -> SelectionStrategy -> Bool Source # |
|
Show SelectionStrategy Source # | |
|
data SelectionBalanceError ctx Source #
Represents the set of errors that may occur while performing a selection.
BalanceInsufficient BalanceInsufficientError | |
SelectionLimitReached ( SelectionLimitReachedError ctx) | |
UnableToConstructChange UnableToConstructChangeError | |
EmptyUTxO |
Instances
data BalanceInsufficientError Source #
Indicates that the balance of available UTxO entries is insufficient to cover the balance required.
BalanceInsufficientError | |
|
Instances
Eq BalanceInsufficientError Source # | |
Show BalanceInsufficientError Source # | |
|
|
Generic BalanceInsufficientError Source # | |
|
|
type Rep BalanceInsufficientError Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance
type
Rep
BalanceInsufficientError
=
D1
('
MetaData
"BalanceInsufficientError" "Cardano.Wallet.CoinSelection.Internal.Balance" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"BalanceInsufficientError" '
PrefixI
'
True
) (
S1
('
MetaSel
('
Just
"utxoBalanceAvailable") '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
TokenBundle
)
:*:
S1
('
MetaSel
('
Just
"utxoBalanceRequired") '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
TokenBundle
)))
|
data UnableToConstructChangeError Source #
UnableToConstructChangeError | |
|
Instances
Eq UnableToConstructChangeError Source # | |
Show UnableToConstructChangeError Source # | |
|
|
Generic UnableToConstructChangeError Source # | |
type Rep UnableToConstructChangeError Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance
type
Rep
UnableToConstructChangeError
=
D1
('
MetaData
"UnableToConstructChangeError" "Cardano.Wallet.CoinSelection.Internal.Balance" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"UnableToConstructChangeError" '
PrefixI
'
True
) (
S1
('
MetaSel
('
Just
"requiredCost") '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
Coin
)
:*:
S1
('
MetaSel
('
Just
"shortfall") '
NoSourceUnpackedness
'
SourceStrict
'
DecidedStrict
) (
Rec0
Coin
)))
|
Selection limits
type SelectionLimit = SelectionLimitOf Int Source #
Specifies a limit to adhere to when performing a selection.
data SelectionLimitOf a Source #
NoLimit |
Indicates that there is no limit. |
MaximumInputLimit a |
Indicates a maximum limit on the number of inputs to select. |
Instances
selectionLimitExceeded :: IsUTxOSelection s u => s u -> SelectionLimit -> Bool Source #
Indicates whether or not the given selection limit has been exceeded.
data SelectionLimitReachedError ctx Source #
Indicates that the balance of selected UTxO entries was insufficient to cover the balance required while remaining within the selection limit.
SelectionLimitReachedError | |
|
Instances
reduceSelectionLimitBy :: SelectionLimit -> Int -> SelectionLimit Source #
Reduces a selection limit by a given reduction amount.
If the given reduction amount is positive, then this function will reduce the selection limit by that amount.
If the given reduction amount is zero or negative, then this function will return the original limit unchanged.
Querying selections
data SelectionDelta a Source #
Indicates the difference between total input value and total output value
of a
SelectionResult
.
There are two possibilities:
Indicates a surplus, when the total input value is greater than or equal to the total output value.
Indicates a deficit, when the total input value is NOT greater than or equal to the total output value.
Instances
Functor SelectionDelta Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance fmap :: (a -> b) -> SelectionDelta a -> SelectionDelta b Source # (<$) :: a -> SelectionDelta b -> SelectionDelta a Source # |
|
Eq a => Eq ( SelectionDelta a) Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance (==) :: SelectionDelta a -> SelectionDelta a -> Bool Source # (/=) :: SelectionDelta a -> SelectionDelta a -> Bool Source # |
|
Show a => Show ( SelectionDelta a) Source # | |
|
|
Buildable a => Buildable ( SelectionDelta a) Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance build :: SelectionDelta a -> Builder Source # |
selectionDeltaAllAssets :: Foldable f => SelectionResultOf f ctx -> SelectionDelta TokenBundle Source #
Calculates the selection delta for all assets.
See
SelectionDelta
.
selectionDeltaCoin :: Foldable f => SelectionResultOf f ctx -> SelectionDelta Coin Source #
Calculates the ada selection delta.
See
SelectionDelta
.
selectionHasValidSurplus :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Bool Source #
Indicates whether or not a selection result has a valid surplus.
selectionSurplusCoin :: Foldable f => SelectionResultOf f ctx -> Coin Source #
Calculates the ada selection surplus, assuming there is a surplus.
If there is a surplus, then this function returns that surplus. If there is a deficit, then this function returns zero.
Use
selectionDeltaCoin
if you wish to handle the case where there is
a deficit.
selectionMinimumCost :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Coin Source #
Computes the minimum required cost of a selection.
selectionMaximumCost :: Foldable f => SelectionConstraints ctx -> SelectionResultOf f ctx -> Coin Source #
Computes the maximum acceptable cost of a selection.
This function acts as a safety limit to ensure that fees of selections
produced by
performSelection
are not excessively high.
Ideally, we'd always be able to generate selections with fees that are
precisely equal to
selectionMinimumCost
. However, in some situations
it may be necessary to exceed this cost very slightly.
This function provides a conservative upper bound to a selection cost that we can reference from within property tests.
See
selectionHasValidSurplus
.
selectionSkeleton :: Foldable f => SelectionResultOf f ctx -> SelectionSkeleton ctx Source #
Converts a selection into a skeleton.
Querying parameters
data UTxOBalanceSufficiency Source #
Indicates whether the balance of available UTxO entries is sufficient.
UTxOBalanceSufficient |
Indicates that the UTxO balance is sufficient. |
UTxOBalanceInsufficient |
Indicates that the UTxO balance is insufficient. |
Instances
data UTxOBalanceSufficiencyInfo Source #
Gives more information about UTxO balance sufficiency.
UTxOBalanceSufficiencyInfo | |
|
Instances
Eq UTxOBalanceSufficiencyInfo Source # | |
Show UTxOBalanceSufficiencyInfo Source # | |
|
|
Generic UTxOBalanceSufficiencyInfo Source # | |
|
|
type Rep UTxOBalanceSufficiencyInfo Source # | |
Defined in Cardano.Wallet.CoinSelection.Internal.Balance
type
Rep
UTxOBalanceSufficiencyInfo
=
D1
('
MetaData
"UTxOBalanceSufficiencyInfo" "Cardano.Wallet.CoinSelection.Internal.Balance" "cardano-wallet-core-2022.7.1-AGKhlyz9liLKN3QqZD1gj" '
False
) (
C1
('
MetaCons
"UTxOBalanceSufficiencyInfo" '
PrefixI
'
True
) ((
S1
('
MetaSel
('
Just
"available") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
TokenBundle
)
:*:
S1
('
MetaSel
('
Just
"required") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
TokenBundle
))
:*:
(
S1
('
MetaSel
('
Just
"difference") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
TokenBundle
)
:*:
S1
('
MetaSel
('
Just
"sufficiency") '
NoSourceUnpackedness
'
NoSourceStrictness
'
DecidedLazy
) (
Rec0
UTxOBalanceSufficiency
))))
|
computeBalanceInOut :: Foldable f => SelectionParamsOf f ctx -> ( TokenBundle , TokenBundle ) Source #
computeDeficitInOut :: Foldable f => SelectionParamsOf f ctx -> ( TokenBundle , TokenBundle ) Source #
computeUTxOBalanceAvailable :: SelectionParamsOf f ctx -> TokenBundle Source #
Computes the balance of UTxO entries available for selection.
computeUTxOBalanceRequired :: Foldable f => SelectionParamsOf f ctx -> TokenBundle Source #
Computes the balance of UTxO entries required to be selected.
computeUTxOBalanceSufficiency :: Foldable f => SelectionParamsOf f ctx -> UTxOBalanceSufficiency Source #
Computes the UTxO balance sufficiency.
See
UTxOBalanceSufficiency
.
computeUTxOBalanceSufficiencyInfo :: Foldable f => SelectionParamsOf f ctx -> UTxOBalanceSufficiencyInfo Source #
Computes information about the UTxO balance sufficiency.
isUTxOBalanceSufficient :: Foldable f => SelectionParamsOf f ctx -> Bool Source #
Indicates whether or not the UTxO balance is sufficient.
The balance of available UTxO entries is sufficient if (and only if) it is greater than or equal to the required balance.
Running a selection (without making change)
runSelection :: forall m u. ( MonadRandom m, Ord u) => RunSelectionParams u -> m ( UTxOSelection u) Source #
runSelectionNonEmpty :: ( MonadRandom m, Ord u) => RunSelectionParams u -> m ( Maybe ( UTxOSelectionNonEmpty u)) Source #
runSelectionNonEmptyWith :: Monad m => ( UTxOSelection u -> m ( Maybe ( UTxOSelectionNonEmpty u))) -> UTxOSelection u -> m ( Maybe ( UTxOSelectionNonEmpty u)) Source #
data RunSelectionParams u Source #
Parameters for
runSelection
.
RunSelectionParams | |
|
Instances
Running a selection step
runSelectionStep :: forall m state state'. Monad m => SelectionLens m state state' -> state -> m ( Maybe state') Source #
Runs just a single step of a coin selection.
It returns an updated state if (and only if) the updated selection represents an improvement over the selection in the previous state.
An improvement, for a given token quantity, is defined in the following way:
- If the total selected token quantity of the previous selection had not yet reached 100% of the output token quantity, any additional selection is considered to be an improvement.
- If the total selected token quantity of the previous selection had already reached or surpassed 100% of the output token quantity, any additional selection is considered to be an improvement if and only if it takens the total selected token quantity closer to the target token quantity, but not further away.
data SelectionLens m state state' Source #
Provides a lens on the current selection state.
A
SelectionLens
gives
runSelectionStep
just the information it needs to
make a decision, and no more.
SelectionLens | |
|
assetSelectionLens :: ( MonadRandom m, Ord u) => SelectionLimit -> SelectionStrategy -> ( AssetId , TokenQuantity ) -> SelectionLens m ( UTxOSelection u) ( UTxOSelectionNonEmpty u) Source #
:: ( MonadRandom m, Ord u) | |
=> SelectionLimit | |
-> SelectionStrategy | |
-> Coin |
Minimum coin quantity. |
-> SelectionLens m ( UTxOSelection u) ( UTxOSelectionNonEmpty u) |
Making change
data MakeChangeCriteria minCoinFor bundleSizeAssessor Source #
Criteria for the
makeChange
function.
MakeChangeCriteria | |
|
Instances
:: MakeChangeCriteria ( TokenMap -> Coin ) TokenBundleSizeAssessor |
Criteria for making change. |
-> Either UnableToConstructChangeError [ TokenBundle ] |
Generated change bundles. |
Constructs change bundles for a set of selected inputs and outputs.
Returns
Nothing
if the specified inputs do not provide enough ada to
satisfy the minimum delta and minimum ada quantities of the change bundles
generated.
This function will generate runtime errors if:
- The total balance of all outputs is not less than or equal to the total balance of all inputs.
- The total ada balance of all outputs is zero.
Pre-condition (1) should be satisfied by any result produced by the
runSelection
function.
Pre-condition (2) should be satisfied by assigning a minimum ada quantity to every output token bundle.
:: HasCallStack | |
=> NonEmpty Coin |
A list of weights for the distribution. Conveniently captures both the weights, and the number of elements amongst which the surplus ada quantity should be distributed. |
-> Coin |
A surplus ada quantity to be distributed. |
-> NonEmpty Coin |
Constructs a list of ada change outputs based on the given distribution.
If the sum of weights in given distribution is equal to zero, this function throws a runtime error.
The length of the output list is always the same as the length of the input
list, and the sum of its quantities is always exactly equal to the
Coin
value given as the second argument.
makeChangeForUserSpecifiedAsset Source #
:: NonEmpty TokenMap |
A list of weights for the distribution. Conveniently captures both the weights, and the number of elements amongst which the quantity should be distributed. |
-> ( AssetId , TokenQuantity ) |
A surplus token quantity to distribute. |
-> NonEmpty TokenMap |
Constructs change outputs for a user-specified asset: an asset that was present in the original set of outputs.
If the given asset does not appear in the given distribution, this function returns a list of empty token maps. Otherwise, the given token quantity is partitioned into a list of quantities that are proportional to the weights within the given input distribution, modulo rounding.
The length of the output list is always the same as the the length of the input list, and the sum of its quantities is either zero, or exactly equal to the token quantity in the second argument.
makeChangeForNonUserSpecifiedAsset Source #
:: NonEmpty a |
Determines the number of change maps to create. |
-> ( AssetId , NonEmpty TokenQuantity ) |
An asset quantity to distribute. |
-> NonEmpty TokenMap |
The resultant change maps. |
Constructs change outputs for a non-user-specified asset: an asset that was not present in the original set of outputs.
This function constructs a list of change outputs by preserving the input distribution as much as possible. Note that only the length of the first argument is used.
The length of the output list is always the same as the length of the input list, and the sum of its quantities is always exactly equal to the sum of all token quantities given in the second argument.
The resultant list is sorted into ascending order when maps are compared
with the
leq
function.
makeChangeForNonUserSpecifiedAssets Source #
:: NonEmpty a |
Determines the number of change maps to create. |
-> Map AssetId ( NonEmpty TokenQuantity ) |
A map of asset quantities to distribute. |
-> NonEmpty TokenMap |
The resultant change maps. |
Constructs change outputs for all non-user-specified assets: assets that were not present in the original set of outputs.
The resultant list is sorted into ascending order when maps are compared
with the
leq
function.
assignCoinsToChangeMaps Source #
:: HasCallStack | |
=> Coin |
The total quantity of ada available, including any extra source of ada. |
-> ( TokenMap -> Coin ) |
A function to calculate the minimum required ada quantity for any token map. |
-> NonEmpty ( TokenMap , Coin ) |
A list of pre-computed asset change maps paired with original output coins, sorted into an order that ensures all empty token maps are at the start of the list. |
-> Either Coin [ TokenBundle ] |
Resulting change bundles, or the shortfall quantity if there was not enough ada available to assign a minimum ada quantity to all non-empty token maps. |
Assigns coin quantities to a list of pre-computed asset change maps.
Each pre-computed asset change map must be paired with the original coin value of its corresponding output.
This function:
- expects the list of pre-computed asset change maps to be sorted in an order that ensures all empty token maps are at the start of the list.
- attempts to assign a minimum ada quantity to every change map, but iteratively drops empty change maps from the start of the list if the amount of ada is insufficient to cover them all.
- continues dropping empty change maps from the start of the list until it is possible to assign a minimum ada value to all remaining entries.
- returns a list that is identical in length to the input list if (and only if) it was possible to assign a minimum ada quantity to all change maps.
- returns a list that is shorter than the input list if it was only possible to assign a minimum ada quantity to a suffix of the given list.
- fails if (and only if) there was not enough ada available to assign the minimum ada quantity to all non-empty change maps.
collateNonUserSpecifiedAssetQuantities Source #
:: NonEmpty TokenMap |
Token maps of all selected inputs. |
-> Set AssetId |
Set of all assets in user-specified outputs. |
-> Map AssetId ( NonEmpty TokenQuantity ) |
Generates a map of all non-user-specified assets and their quantities.
Each key in the resulting map corresponds to an asset that was NOT included in the original set of user-specified outputs, but that was nevertheless selected during the selection process.
The value associated with each key corresponds to the complete list of all discrete non-zero quantities of that asset present in the selected inputs.
addMintValueToChangeMaps :: ( AssetId , TokenQuantity ) -> NonEmpty TokenMap -> NonEmpty TokenMap Source #
Adds a minted asset quantity to a list of change maps.
This function always adds the given quantity to the final change map in the given list.
Example:
Suppose we have the following list of change maps:
If we add 4 tokens of asset A , we obtain the following result:
- [ ( B , 7)
- [( A , 1), ( B , 8)
- [( A , 2), ( B , 9)
- [( A , 3), ( B , 9)
- [( A , 8), ( B , 12)
- -- Increased by 4
Provided that the specified change maps are in ascending partial order, this function guarantees that the resulting change maps will also be in ascending partial order.
The length of the given list is preserved in the output list.
addMintValuesToChangeMaps Source #
:: TokenMap |
Map of minted values |
-> NonEmpty TokenMap |
Change maps |
-> NonEmpty TokenMap |
Change maps with minted values |
Adds minted values for multiple assets to a list of change maps.
Plural of
addMintValueToChangeMaps
.
removeBurnValueFromChangeMaps Source #
:: ( AssetId , TokenQuantity ) |
Asset quantity reduction target |
-> NonEmpty TokenMap |
Change maps with quantities of the given asset to be reduced |
-> NonEmpty TokenMap |
Change maps with reduced quantities of the given asset |
Removes a burned asset quantity from a list of change maps.
For a given asset
a
and reduction target
t
, this function traverses the
given list from left to right, reducing the quantity of asset
a
in each
change map until the reduction target
t
has been met, or until the list
is exhausted.
For each change map
m
under consideration:
-
if the quantity
q
of asseta
in mapm
is less than or equal to the remaining required reductionr
, it will be replaced with a zero (effectively eliminating asseta
from the map). -
if the quantity
q
of asseta
in mapm
is greater than the remaining required reductionr
, it will be replaced with the absolute difference betweenq
andr
.
If the total quantity of the given asset in the given change maps is greater than the specified reduction target, the total reduction will be equal to the specified reduction target. Otherwise, the given asset will be completely eliminated from all change maps.
Example:
Suppose we have the following list of change maps:
If our target is to reduce the quantity of asset A by 4, then we should obtain the following result:
- [ ( B , 7)
- -- Unable to reduce (already 0)
- [ ( B , 8)
- -- Reduced by 1 (and eliminated from map)
- [ ( B , 9)
- -- Reduced by 2 (and eliminated from map)
- [( A , 2), ( B , 9)
- -- Reduced by 1
- [( A , 4), ( B , 12)
Provided that the specified change maps are in ascending partial order, this function guarantees that the resulting change maps will also be in ascending partial order.
The length of the given list is preserved in the output list.
removeBurnValuesFromChangeMaps Source #
:: TokenMap |
Map of burned values |
-> NonEmpty TokenMap |
Change maps |
-> NonEmpty TokenMap |
Change maps with burned values removed |
Removes burned values for multiple assets from a list of change maps.
Plural of
removeBurnValueFromChangeMaps
.
reduceTokenQuantities Source #
:: TokenQuantity |
Reduction target |
-> NonEmpty TokenQuantity |
List of quantities to reduce |
-> NonEmpty TokenQuantity |
The list of reduced quantities |
Reduces the total value of the given list of token quantities by the given reduction target.
This function traverses the given list of quantities from left to right, reducing each quantity in turn until the total reduction is equal to the given reduction target, or until the list is exhausted.
For each quantity
q
under consideration:
-
if
q
is less than or equal to the remaining required reductionr
, it will be replaced with a zero. -
if
q
is greater than the remaining required reductionr
, it will be replaced with the absolute difference betweenq
andr
.
If the total value in the list is less than the reduction target, the result will be a list of zeros.
Provided the given list is in ascending order, the resulting list is also guaranteed to be in ascending order.
The length of the given list is preserved in the output.
Splitting bundles
splitBundleIfAssetCountExcessive Source #
:: TokenBundle |
The token bundle suspected to have an excessive number of assets. |
-> ( TokenBundle -> Bool ) |
A function that returns
|
-> NonEmpty TokenBundle |
Splits a bundle into smaller bundles if its asset count is excessive when
measured with the given
isExcessive
indicator function.
Returns a list of smaller bundles for which
isExcessive
returns
False
.
splitBundlesWithExcessiveAssetCounts Source #
:: NonEmpty TokenBundle |
Token bundles. |
-> ( TokenBundle -> Bool ) |
A function that returns
|
-> NonEmpty TokenBundle |
Splits bundles with excessive asset counts into smaller bundles.
Only token bundles where the
isExcessive
indicator function returns
True
will be split.
Returns a list of smaller bundles for which
isExcessive
returns
False
.
If none of the bundles in the given list has an excessive asset count, this function will return the original list.
splitBundlesWithExcessiveTokenQuantities Source #
:: NonEmpty TokenBundle |
Token bundles. |
-> TokenQuantity |
Maximum allowable token quantity. |
-> NonEmpty TokenBundle |
The partitioned bundles. |
Splits bundles with excessive token quantities into smaller bundles.
Only token bundles containing quantities that exceed the maximum token quantity will be split.
If none of the bundles in the given list contain a quantity that exceeds the maximum token quantity, this function will return the original list.
Grouping and ungrouping
ungroupByKey :: forall k v. Map k ( NonEmpty v) -> [(k, v)] Source #
Round-robin processing
runRoundRobin :: s -> (s' -> s) -> [s -> Maybe s'] -> s Source #
runRoundRobinM :: Monad m => s -> (s' -> s) -> [s -> m ( Maybe s')] -> m s Source #
Utility classes
newtype AssetCount a Source #
AssetCount | |
|
Instances
Utility functions
balanceMissing :: BalanceInsufficientError -> TokenBundle Source #
Calculate the missing balance from a
BalanceInsufficientError
.