@@ -643,13 +643,16 @@ estimateBalancedTxBody
643
643
balance =
644
644
evaluateTransactionBalance sbe pparams poolids stakeDelegDeposits drepDelegDeposits fakeUTxO txbody2
645
645
balanceTxOut = TxOut changeaddr balance TxOutDatumNone ReferenceScriptNone
646
- -- check if the balance is positive or negative
647
- -- in one case we can produce change, in the other the inputs are insufficient
648
- first TxFeeEstimationBalanceError $ balanceCheck sbe pparams balanceTxOut
649
646
650
647
-- Step 6. Check all txouts have the min required UTxO value
651
648
forM_ (txOuts txbodycontent1) $
652
- \ txout -> first TxFeeEstimationBalanceError $ checkMinUTxOValue sbe txout pparams
649
+ \ txout -> first TxFeeEstimationBalanceError $ checkMinUTxOValue sbe pparams txout
650
+
651
+ -- check if the balance is positive or negative
652
+ -- in one case we can produce change, in the other the inputs are insufficient
653
+ finalTxOuts <-
654
+ first TxFeeEstimationBalanceError $
655
+ checkAndIncludeChange sbe pparams balanceTxOut (txOuts txbodycontent1)
653
656
654
657
-- Step 7.
655
658
@@ -661,10 +664,7 @@ estimateBalancedTxBody
661
664
let finalTxBodyContent =
662
665
txbodycontent1
663
666
{ txFee = TxFeeExplicit sbe fee
664
- , txOuts =
665
- accountForNoChange
666
- balanceTxOut
667
- (txOuts txbodycontent)
667
+ , txOuts = finalTxOuts
668
668
, txReturnCollateral = retColl
669
669
, txTotalCollateral = reqCol
670
670
}
@@ -1471,11 +1471,10 @@ makeTransactionBodyAutoBalance
1471
1471
}
1472
1472
let balance = evaluateTransactionBalance sbe pp poolids stakeDelegDeposits drepDelegDeposits utxo txbody2
1473
1473
balanceTxOut = TxOut changeaddr balance TxOutDatumNone ReferenceScriptNone
1474
- forM_ (txOuts txbodycontent1) $ \ txout -> checkMinUTxOValue sbe txout pp
1474
+ forM_ (txOuts txbodycontent1) $ \ txout -> checkMinUTxOValue sbe pp txout
1475
1475
1476
- -- check if the balance is positive or negative
1477
- -- in one case we can produce change, in the other the inputs are insufficient
1478
- balanceCheck sbe pp balanceTxOut
1476
+ -- check if change meets txout criteria, and include if non-zero
1477
+ finalTxOuts <- checkAndIncludeChange sbe pp balanceTxOut (txOuts txbodycontent1)
1479
1478
1480
1479
-- TODO: we could add the extra fee for the CBOR encoding of the change,
1481
1480
-- now that we know the magnitude of the change: i.e. 1-8 bytes extra.
@@ -1487,10 +1486,7 @@ makeTransactionBodyAutoBalance
1487
1486
let finalTxBodyContent =
1488
1487
txbodycontent1
1489
1488
{ txFee = TxFeeExplicit sbe fee
1490
- , txOuts =
1491
- accountForNoChange
1492
- balanceTxOut
1493
- (txOuts txbodycontent)
1489
+ , txOuts = finalTxOuts
1494
1490
, txReturnCollateral = retColl
1495
1491
, txTotalCollateral = reqCol
1496
1492
}
@@ -1510,26 +1506,36 @@ makeTransactionBodyAutoBalance
1510
1506
era :: CardanoEra era
1511
1507
era = toCardanoEra sbe
1512
1508
1513
- -- | In the event of spending the exact amount of lovelace in
1509
+ -- | In the event of spending the exact amount of lovelace and non-ada assets in
1514
1510
-- the specified input(s), this function excludes the change
1515
1511
-- output. Note that this does not save any fees because by default
1516
1512
-- the fee calculation includes a change address for simplicity and
1517
1513
-- we make no attempt to recalculate the tx fee without a change address.
1518
- accountForNoChange :: TxOut CtxTx era -> [TxOut CtxTx era ] -> [TxOut CtxTx era ]
1519
- accountForNoChange change@ (TxOut _ balance _ _) rest =
1520
- case txOutValueToLovelace balance of
1521
- L. Coin 0 -> rest
1522
- -- We append change at the end so a client can predict the indexes
1523
- -- of the outputs
1524
- _ -> rest ++ [change]
1514
+ checkAndIncludeChange
1515
+ :: ShelleyBasedEra era
1516
+ -> Ledger. PParams (ShelleyLedgerEra era )
1517
+ -> TxOut CtxTx era
1518
+ -> [TxOut CtxTx era ]
1519
+ -> Either (TxBodyErrorAutoBalance era ) [TxOut CtxTx era ]
1520
+ checkAndIncludeChange sbe pp change@ (TxOut _ balance _ _) rest = do
1521
+ let outValue = toMaryValue $ txOutValueToValue balance
1522
+ if L. isZero outValue
1523
+ then pure rest
1524
+ else do
1525
+ -- check if the balance is positive or negative
1526
+ -- in one case we can produce change, in the other the inputs are insufficient
1527
+ balanceCheck sbe pp change
1528
+ -- We append change at the end so a client can predict the indexes of the outputs.
1529
+ -- Note that if this function will append change with 0 ADA, and non-ada assets in it.
1530
+ pure $ rest <> [change]
1525
1531
1526
1532
checkMinUTxOValue
1527
1533
:: ShelleyBasedEra era
1528
- -> TxOut CtxTx era
1529
1534
-> Ledger. PParams (ShelleyLedgerEra era )
1535
+ -> TxOut CtxTx era
1530
1536
-> Either (TxBodyErrorAutoBalance era ) ()
1531
- checkMinUTxOValue sbe txout@ (TxOut _ v _ _) bpp = do
1532
- let minUTxO = calculateMinimumUTxO sbe txout bpp
1537
+ checkMinUTxOValue sbe bpp txout@ (TxOut _ v _ _) = do
1538
+ let minUTxO = calculateMinimumUTxO sbe bpp txout
1533
1539
if txOutValueToLovelace v >= minUTxO
1534
1540
then Right ()
1535
1541
else Left $ TxBodyErrorMinUTxONotMet (txOutInAnyEra (toCardanoEra sbe) txout) minUTxO
@@ -1543,10 +1549,16 @@ balanceCheck sbe bpparams txout@(TxOut _ balance _ _) = do
1543
1549
let outValue@ (L. MaryValue coin multiAsset) = toMaryValue $ txOutValueToValue balance
1544
1550
isPositiveValue = L. pointwise (>) outValue mempty
1545
1551
if
1546
- | L. isZero outValue -> pure () -- empty TxOut
1552
+ | L. isZero outValue -> pure () -- empty TxOut - ok, it's removed at the end
1553
+ | L. isZero coin -> -- no ADA, just non-ADA assets
1554
+ Left $
1555
+ TxBodyErrorAdaBalanceTooSmall
1556
+ (TxOutInAnyEra (toCardanoEra sbe) txout)
1557
+ (calculateMinimumUTxO sbe bpparams txout)
1558
+ coin
1547
1559
| not isPositiveValue -> Left $ TxBodyErrorBalanceNegative coin multiAsset
1548
1560
| otherwise ->
1549
- case checkMinUTxOValue sbe txout bpparams of
1561
+ case checkMinUTxOValue sbe bpparams txout of
1550
1562
Left (TxBodyErrorMinUTxONotMet txOutAny minUTxO) ->
1551
1563
Left $ TxBodyErrorAdaBalanceTooSmall txOutAny minUTxO coin
1552
1564
Left err -> Left err
@@ -1891,10 +1903,10 @@ traverseScriptWitnesses =
1891
1903
calculateMinimumUTxO
1892
1904
:: HasCallStack
1893
1905
=> ShelleyBasedEra era
1894
- -> TxOut CtxTx era
1895
1906
-> Ledger. PParams (ShelleyLedgerEra era )
1907
+ -> TxOut CtxTx era
1896
1908
-> L. Coin
1897
- calculateMinimumUTxO sbe txout pp =
1909
+ calculateMinimumUTxO sbe pp txout =
1898
1910
shelleyBasedEraConstraints sbe $
1899
1911
let txOutWithMinCoin = L. setMinCoinTxOut pp (toShelleyTxOutAny sbe txout)
1900
1912
in txOutWithMinCoin ^. L. coinTxOutL
0 commit comments