@@ -384,7 +384,6 @@ import Cardano.Ledger.Plutus.Language qualified as Plutus
384
384
import Cardano.Ledger.Val qualified as L
385
385
import Ouroboros.Consensus.HardFork.History qualified as Consensus
386
386
387
- import Control.Monad
388
387
import Data.Bifunctor (bimap , first , second )
389
388
import Data.Bitraversable (bitraverse )
390
389
import Data.ByteString.Short (ShortByteString )
@@ -651,8 +650,9 @@ estimateBalancedTxBody
651
650
balanceTxOut = TxOut changeaddr balance TxOutDatumNone ReferenceScriptNone
652
651
653
652
-- Step 6. Check all txouts have the min required UTxO value
654
- forM_ (txOuts txbodycontent1) $
655
- \ txout -> first TxFeeEstimationBalanceError $ checkMinUTxOValue sbe pparams txout
653
+ first (TxFeeEstimationBalanceError . uncurry TxBodyErrorMinUTxONotMet )
654
+ . mapM_ (checkMinUTxOValue sbe pparams)
655
+ $ txOuts txbodycontent1
656
656
657
657
-- check if the balance is positive or negative
658
658
-- in one case we can produce change, in the other the inputs are insufficient
@@ -1377,7 +1377,7 @@ makeTransactionBodyAutoBalance
1377
1377
1378
1378
-- Initial change is only used for execution units evaluation, so we don't require minimum UTXO requirement
1379
1379
-- to be satisfied at this point
1380
- _ <- balanceCheck sbe pp SkipMinUtxoCheck initialChangeTxOut
1380
+ _ <- checkNonNegative sbe pp initialChangeTxOut
1381
1381
1382
1382
-- Tx body used only for evaluating execution units. Because txout exact
1383
1383
-- values do not matter much here, we are using an initial change value,
@@ -1479,7 +1479,9 @@ makeTransactionBodyAutoBalance
1479
1479
}
1480
1480
let balance = evaluateTransactionBalance sbe pp poolids stakeDelegDeposits drepDelegDeposits utxo txbody2
1481
1481
balanceTxOut = TxOut changeaddr balance TxOutDatumNone ReferenceScriptNone
1482
- forM_ (txOuts txbodycontent1) $ \ txout -> checkMinUTxOValue sbe pp txout
1482
+ first (uncurry TxBodyErrorMinUTxONotMet )
1483
+ . mapM_ (checkMinUTxOValue sbe pp)
1484
+ $ txOuts txbodycontent1
1483
1485
1484
1486
-- check if change meets txout criteria, and include if non-zero
1485
1487
finalTxOuts <- checkAndIncludeChange sbe pp balanceTxOut (txOuts txbodycontent1)
@@ -1525,60 +1527,52 @@ checkAndIncludeChange
1525
1527
-> TxOut CtxTx era
1526
1528
-> [TxOut CtxTx era ]
1527
1529
-> Either (TxBodyErrorAutoBalance era ) [TxOut CtxTx era ]
1528
- checkAndIncludeChange sbe pp change rest = do
1529
- isChangeEmpty <- balanceCheck sbe pp DoMinUtxoCheck change
1530
- pure $
1531
- if isChangeEmpty == Empty
1532
- then rest
1530
+ checkAndIncludeChange sbe pp change@ (TxOut _ changeValue _ _) rest = do
1531
+ isChangeEmpty <- checkNonNegative sbe pp change
1532
+ if isChangeEmpty == Empty
1533
+ then pure rest
1534
+ else do
1535
+ let coin = txOutValueToLovelace changeValue
1536
+ first ((coin & ) . uncurry TxBodyErrorAdaBalanceTooSmall ) $
1537
+ checkMinUTxOValue sbe pp change
1533
1538
-- We append change at the end so a client can predict the indexes of the outputs.
1534
- -- Note that if this function will append change with 0 ADA, and non-ada assets in it.
1535
- else rest <> [change]
1539
+ pure $ rest <> [change]
1536
1540
1537
1541
checkMinUTxOValue
1538
1542
:: ShelleyBasedEra era
1539
1543
-> Ledger. PParams (ShelleyLedgerEra era )
1540
1544
-> TxOut CtxTx era
1541
- -> Either (TxBodyErrorAutoBalance era ) ()
1545
+ -> Either (TxOutInAnyEra , Coin ) ()
1546
+ -- ^ @Left (offending txout, minimum required utxo)@ or @Right ()@ when txout is ok
1542
1547
checkMinUTxOValue sbe bpp txout@ (TxOut _ v _ _) = do
1543
1548
let minUTxO = calculateMinimumUTxO sbe bpp txout
1544
1549
if txOutValueToLovelace v >= minUTxO
1545
1550
then Right ()
1546
- else Left $ TxBodyErrorMinUTxONotMet (txOutInAnyEra (toCardanoEra sbe) txout) minUTxO
1551
+ else Left (txOutInAnyEra (toCardanoEra sbe) txout, minUTxO)
1547
1552
1548
1553
data IsEmpty = Empty | NonEmpty
1549
1554
deriving (Eq , Show )
1550
1555
1551
- data DoMinUtxoCheck = SkipMinUtxoCheck | DoMinUtxoCheck
1552
- deriving (Eq , Show )
1553
-
1554
- balanceCheck
1556
+ checkNonNegative
1555
1557
:: ShelleyBasedEra era
1556
1558
-> Ledger. PParams (ShelleyLedgerEra era )
1557
- -> DoMinUtxoCheck
1558
- -- ^ whether to fail on minimum utxo value check
1559
1559
-> TxOut CtxTx era
1560
1560
-> Either (TxBodyErrorAutoBalance era ) IsEmpty
1561
1561
-- ^ result of check if txout is empty
1562
- balanceCheck sbe bpparams doCheckMinUtxo txout@ (TxOut _ balance _ _) = do
1562
+ checkNonNegative sbe bpparams txout@ (TxOut _ balance _ _) = do
1563
1563
let outValue@ (L. MaryValue coin multiAsset) = toMaryValue $ txOutValueToValue balance
1564
1564
isPositiveValue = L. pointwise (>) outValue mempty
1565
1565
if
1566
1566
| L. isZero outValue -> pure Empty -- empty TxOut - ok, it's removed at the end
1567
- | L. isZero coin -> -- no ADA, just non-ADA assets
1567
+ | L. isZero coin ->
1568
+ -- no ADA, just non-ADA assets: positive lovelace is required in such case
1568
1569
Left $
1569
1570
TxBodyErrorAdaBalanceTooSmall
1570
1571
(TxOutInAnyEra (toCardanoEra sbe) txout)
1571
1572
(calculateMinimumUTxO sbe bpparams txout)
1572
1573
coin
1573
1574
| not isPositiveValue -> Left $ TxBodyErrorBalanceNegative coin multiAsset
1574
- | otherwise ->
1575
- case checkMinUTxOValue sbe bpparams txout of
1576
- Left (TxBodyErrorMinUTxONotMet txOutAny minUTxO)
1577
- | doCheckMinUtxo == DoMinUtxoCheck ->
1578
- Left $ TxBodyErrorAdaBalanceTooSmall txOutAny minUTxO coin
1579
- | otherwise -> pure NonEmpty
1580
- Left err -> Left err
1581
- Right _ -> pure NonEmpty
1575
+ | otherwise -> pure NonEmpty
1582
1576
1583
1577
-- Calculation taken from validateInsufficientCollateral:
1584
1578
-- https://github.com/input-output-hk/cardano-ledger/blob/389b266d6226dedf3d2aec7af640b3ca4984c5ea/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxo.hs#L335
0 commit comments