Skip to content

Commit 3db046b

Browse files
Robert 'Probie' Offnernewhoggy
Robert 'Probie' Offner
authored andcommitted
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 b22aae8 commit 3db046b

File tree

2 files changed

+29
-21
lines changed

2 files changed

+29
-21
lines changed

cardano-api/ChangeLog.md

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

1515
- **Breaking change** - Reduce exposed modules in cardano-api ([PR4546](https://github.com/input-output-hk/cardano-node/pull/4546))
1616

17+
- Auto-balance multi asset transactions ([PR 4450](https://github.com/input-output-hk/cardano-node/pull/4450))
18+
1719
### Bugs
1820

1921
- 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

+27-21
Original file line numberDiff line numberDiff line change
@@ -769,11 +769,6 @@ data TxBodyErrorAutoBalance =
769769
-- | One or more of the scripts were expected to fail validation, but none did.
770770
| TxBodyScriptBadScriptValidity
771771

772-
-- | The balance of the non-ada assets is not zero. The 'Value' here is
773-
-- that residual non-zero balance. The 'makeTransactionBodyAutoBalance'
774-
-- function only automatically balances ada, not other assets.
775-
| TxBodyErrorAssetBalanceWrong Value
776-
777772
-- | There is not enough ada to cover both the outputs and the fees.
778773
-- The transaction should be changed to provide more input ada, or
779774
-- otherwise adjusted to need less (e.g. outputs, script etc).
@@ -832,13 +827,6 @@ instance Error TxBodyErrorAutoBalance where
832827
displayError TxBodyScriptBadScriptValidity =
833828
"One or more of the scripts were expected to fail validation, but none did."
834829

835-
displayError (TxBodyErrorAssetBalanceWrong _value) =
836-
"The transaction does not correctly balance in its non-ada assets. "
837-
++ "The balance between inputs and outputs should sum to zero. "
838-
++ "The actual balance is: "
839-
++ "TODO: move the Value renderer and parser from the CLI into the API and use them here"
840-
-- TODO: do this ^^
841-
842830
displayError (TxBodyErrorAdaBalanceNegative lovelace) =
843831
"The transaction does not balance in its use of ada. The net balance "
844832
++ "of the transaction is negative: " ++ show lovelace ++ " lovelace. "
@@ -977,13 +965,30 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
977965
-- output and fee. Yes this means this current code will only work for
978966
-- final fee of less than around 4000 ada (2^32-1 lovelace) and change output
979967
-- of less than around 18 trillion ada (2^64-1 lovelace).
968+
-- However, since at this point we know how much non-Ada change to give
969+
-- we can use the true values for that.
970+
971+
let outgoingNonAda = mconcat [filterValue isNotAda v | (TxOut _ (TxOutValue _ v) _ _) <- txOuts txbodycontent]
972+
let incomingNonAda = mconcat [filterValue isNotAda v | (TxOut _ (TxOutValue _ v) _ _) <- Map.elems $ unUTxO utxo]
973+
let mintedNonAda = case txMintValue txbodycontent1 of
974+
TxMintNone -> mempty
975+
TxMintValue _ v _ -> v
976+
let nonAdaChange = mconcat
977+
[ incomingNonAda
978+
, mintedNonAda
979+
, negateValue outgoingNonAda
980+
]
981+
982+
let changeTxOut = case multiAssetSupportedInEra cardanoEra of
983+
Left _ -> lovelaceToTxOutValue $ Lovelace (2^(64 :: Integer)) - 1
984+
Right multiAsset -> TxOutValue multiAsset (lovelaceToValue (Lovelace (2^(64 :: Integer)) - 1) <> nonAdaChange)
980985

981986
let (dummyCollRet, dummyTotColl) = maybeDummyTotalCollAndCollReturnOutput txbodycontent changeaddr
982987
txbody1 <- first TxBodyError $ -- TODO: impossible to fail now
983988
createAndValidateTransactionBody txbodycontent1 {
984989
txFee = TxFeeExplicit explicitTxFees $ Lovelace (2^(32 :: Integer) - 1),
985990
txOuts = TxOut changeaddr
986-
(lovelaceToTxOutValue $ Lovelace (2^(64 :: Integer)) - 1)
991+
changeTxOut
987992
TxOutDatumNone ReferenceScriptNone
988993
: txOuts txbodycontent,
989994
txReturnCollateral = dummyCollRet,
@@ -1015,13 +1020,7 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
10151020

10161021
-- check if the balance is positive or negative
10171022
-- in one case we can produce change, in the other the inputs are insufficient
1018-
case balance of
1019-
TxOutAdaOnly _ _ -> balanceCheck balance
1020-
TxOutValue _ v ->
1021-
case valueToLovelace v of
1022-
Nothing -> Left $ TxBodyErrorNonAdaAssetsUnbalanced v
1023-
Just _ -> balanceCheck balance
1024-
1023+
balanceCheck balance
10251024

10261025
--TODO: we could add the extra fee for the CBOR encoding of the change,
10271026
-- now that we know the magnitude of the change: i.e. 1-8 bytes extra.
@@ -1147,7 +1146,7 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
11471146

11481147
balanceCheck :: TxOutValue era -> Either TxBodyErrorAutoBalance ()
11491148
balanceCheck balance
1150-
| txOutValueToLovelace balance == 0 = return ()
1149+
| txOutValueToLovelace balance == 0 && onlyAda (txOutValueToValue balance) = return ()
11511150
| txOutValueToLovelace balance < 0 =
11521151
Left . TxBodyErrorAdaBalanceNegative $ txOutValueToLovelace balance
11531152
| otherwise =
@@ -1157,6 +1156,13 @@ makeTransactionBodyAutoBalance eraInMode systemstart history pparams
11571156
Left err -> Left err
11581157
Right _ -> Right ()
11591158

1159+
isNotAda :: AssetId -> Bool
1160+
isNotAda AdaAssetId = False
1161+
isNotAda _ = True
1162+
1163+
onlyAda :: Value -> Bool
1164+
onlyAda = null . valueToList . filterValue isNotAda
1165+
11601166
checkMinUTxOValue
11611167
:: TxOut CtxTx era
11621168
-> ProtocolParameters

0 commit comments

Comments
 (0)