Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project: cardano-api
pr: 1186
Comment thread
carbolymer marked this conversation as resolved.
kind:
- bugfix
- test
description: |
`makeTransactionBodyAutoBalance` now returns `TxBodyErrorBalanceNegative` when the transaction balance is negative, instead of crashing with an `Illegal Value in TxOut` runtime error from `toCompact` on a negative `Coin`. Added Hedgehog property tests covering withdrawal-funded transaction balancing for both success and failure cases.
15 changes: 12 additions & 3 deletions cardano-api/src/Cardano/Api/Experimental/Tx/Internal/Fee.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import Cardano.Ledger.Credential as Ledger (Credential)
import Cardano.Ledger.Val qualified as L

import Control.Monad
import Control.Monad.Except (throwError)
import Data.Bifunctor
import Data.Function (on, (&))
import Data.List (sortBy)
Expand Down Expand Up @@ -1433,9 +1434,17 @@ makeTransactionBodyAutoBalance
useEra
txbodycontent

let initialChangeTxOutValue :: Ledger.Value (LedgerEra era) =
evaluateTransactionBalance pp poolids stakeDelegDeposits drepDelegDeposits utxo txbodyForChange
initialChangeTxOut :: TxOut (LedgerEra era) =
-- Check the balance before constructing the TxOut. L.mkBasicTxOut calls toCompact, which throws an irrecoverable
-- error on negative Coin values, so checkNonNegative would never get to return Left for the negative case.
initialChangeTxOutValue :: Ledger.Value (LedgerEra era) <- do
let val = evaluateTransactionBalance pp poolids stakeDelegDeposits drepDelegDeposits utxo txbodyForChange
L.MaryValue initialCoin initialMultiAsset = obtainCommonConstraints (useEra @era) val
val
<$ unless
(obtainCommonConstraints (useEra @era) $ L.pointwise (>=) val mempty)
(throwError $ TxBodyErrorBalanceNegative initialCoin initialMultiAsset)

let initialChangeTxOut :: TxOut (LedgerEra era) =
obtainCommonConstraints (useEra @era) $
TxOut (L.mkBasicTxOut (toShelleyAddr changeaddr) initialChangeTxOutValue)

Expand Down
Loading
Loading