Skip to content

Commit 19a2154

Browse files
author
Robert 'Probie' Offner
committed
Auto-balance multiasset transactions
Previously we gave up when the non-Ada part of a transaction wasn't balanced. We now balance the transaction and correctly update the fee accordingly (since the fee will be higher). We also return an error in the case where the is non-Ada change, but not at least minUTxO change (e.g. in the case where the Ada is already balanced). Resolves: #3068
1 parent 0e67413 commit 19a2154

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

cardano-api/ChangeLog.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Append, not prepend change output when balancing a transaction ([PR 4343](https://github.com/input-output-hk/cardano-node/pull/4343))
88

9+
- Auto-balance multi asset transactions ([PR 4450](https://github.com/input-output-hk/cardano-node/pull/4450))
10+
911
### Bugs
1012

1113
- Allow reading text envelopes from pipes ([PR 4384](https://github.com/input-output-hk/cardano-node/pull/4384))

cardano-api/src/Cardano/Api/Fees.hs

+20-9
Original file line numberDiff line numberDiff line change
@@ -971,13 +971,23 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
971971
-- output and fee. Yes this means this current code will only work for
972972
-- final fee of less than around 4000 ada (2^32-1 lovelace) and change output
973973
-- of less than around 18 trillion ada (2^64-1 lovelace).
974+
-- However, since at this point we know how much non-Ada change to give
975+
-- we can use the true values for that.
976+
977+
let outgoingNonAda = mconcat [filterValue isNotAda v | (TxOut _ (TxOutValue _ v) _ _) <- txOuts txbodycontent]
978+
let incomingNonAda = mconcat [filterValue isNotAda v | (TxOut _ (TxOutValue _ v) _ _) <- Map.elems $ unUTxO utxo]
979+
let nonAdaChange = incomingNonAda <> negateValue outgoingNonAda
980+
981+
let changeTxOut = case multiAssetSupportedInEra cardanoEra of
982+
Left _ -> lovelaceToTxOutValue $ Lovelace (2^(64 :: Integer)) - 1
983+
Right multiAsset -> TxOutValue multiAsset (lovelaceToValue (Lovelace (2^(64 :: Integer)) -1) <> nonAdaChange)
974984

975985
let (dummyCollRet, dummyTotColl) = maybeDummyTotalCollAndCollReturnOutput txbodycontent changeaddr
976986
txbody1 <- first TxBodyError $ -- TODO: impossible to fail now
977987
makeTransactionBody txbodycontent1 {
978988
txFee = TxFeeExplicit explicitTxFees $ Lovelace (2^(32 :: Integer) - 1),
979989
txOuts = TxOut changeaddr
980-
(lovelaceToTxOutValue $ Lovelace (2^(64 :: Integer)) - 1)
990+
changeTxOut
981991
TxOutDatumNone ReferenceScriptNone
982992
: txOuts txbodycontent,
983993
txReturnCollateral = dummyCollRet,
@@ -1009,13 +1019,7 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
10091019

10101020
-- check if the balance is positive or negative
10111021
-- in one case we can produce change, in the other the inputs are insufficient
1012-
case balance of
1013-
TxOutAdaOnly _ _ -> balanceCheck balance
1014-
TxOutValue _ v ->
1015-
case valueToLovelace v of
1016-
Nothing -> Left $ TxBodyErrorNonAdaAssetsUnbalanced v
1017-
Just _ -> balanceCheck balance
1018-
1022+
balanceCheck balance
10191023

10201024
--TODO: we could add the extra fee for the CBOR encoding of the change,
10211025
-- now that we know the magnitude of the change: i.e. 1-8 bytes extra.
@@ -1135,7 +1139,7 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
11351139

11361140
balanceCheck :: TxOutValue era -> Either TxBodyErrorAutoBalance ()
11371141
balanceCheck balance
1138-
| txOutValueToLovelace balance == 0 = return ()
1142+
| txOutValueToLovelace balance == 0 && onlyAda (txOutValueToValue balance) = return ()
11391143
| txOutValueToLovelace balance < 0 =
11401144
Left . TxBodyErrorAdaBalanceNegative $ txOutValueToLovelace balance
11411145
| otherwise =
@@ -1145,6 +1149,13 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
11451149
Left err -> Left err
11461150
Right _ -> Right ()
11471151

1152+
isNotAda :: AssetId -> Bool
1153+
isNotAda AdaAssetId = False
1154+
isNotAda _ = True
1155+
1156+
onlyAda :: Value -> Bool
1157+
onlyAda = null . valueToList . filterValue isNotAda
1158+
11481159
checkMinUTxOValue
11491160
:: TxOut CtxTx era
11501161
-> ProtocolParameters

0 commit comments

Comments
 (0)