diff --git a/src/Internal/BalanceTx/BalanceTx.purs b/src/Internal/BalanceTx/BalanceTx.purs index fec897cef..01659630a 100644 --- a/src/Internal/BalanceTx/BalanceTx.purs +++ b/src/Internal/BalanceTx/BalanceTx.purs @@ -39,8 +39,10 @@ import Cardano.Types , _witnessSet ) import Cardano.Types.Address (Address) +import Cardano.Types.Address (getPaymentCredential) as Address import Cardano.Types.BigNum as BigNum import Cardano.Types.Coin as Coin +import Cardano.Types.Credential (asPubKeyHash) as Credential import Cardano.Types.OutputDatum (OutputDatum(OutputDatum)) import Cardano.Types.TransactionBody (_collateral, _votingProposals) import Cardano.Types.TransactionInput (TransactionInput) @@ -152,6 +154,7 @@ import Data.Map (Map) import Data.Map ( empty , filter + , filterKeys , insert , isEmpty , lookup @@ -292,7 +295,14 @@ setTransactionCollateral changeAddr availableUtxos transaction = do "Filtered collateral UTxOs do not cover the minimum required \ \collateral, reselecting collateral using CTL algorithm." (pprintUtxoMap (TransactionUnspentOutput.toUtxoMap spendableUtxos)) - selectCollateral availableUtxos + let + isPkhUtxo txOut = isJust do + cred <- Address.getPaymentCredential $ (unwrap txOut).address + Credential.asPubKeyHash $ unwrap cred + availableUtxos' <- liftContract $ + Map.filter isPkhUtxo <<< Map.filterKeys isSpendable <$> + filterLockedUtxos availableUtxos + selectCollateral availableUtxos' else pure spendableUtxos -- otherwise, get all the utxos, filter out unspendable, and select -- collateral using internal algo, that is also used in KeyWallet diff --git a/test/Testnet/Contract.purs b/test/Testnet/Contract.purs index 7bf1b3d65..bcfdb3823 100644 --- a/test/Testnet/Contract.purs +++ b/test/Testnet/Contract.purs @@ -166,7 +166,7 @@ import Data.Either (Either(Left, Right), hush, isLeft, isRight) import Data.Foldable (fold, foldM, length) import Data.Lens (view) import Data.Map as Map -import Data.Maybe (Maybe(Just, Nothing), fromJust, fromMaybe, isJust) +import Data.Maybe (Maybe(Just, Nothing), fromJust, fromMaybe, isJust, maybe) import Data.Newtype (unwrap, wrap) import Data.Traversable (traverse, traverse_) import Data.Tuple (Tuple(Tuple)) @@ -223,7 +223,7 @@ suite = do withWallets distribution \alice -> do withKeyWallet alice ManyAssets.contract test - "#1509 - Collateral set to one of the inputs in mustNotSpendUtxosWithOutRefs " + "#1509 - Collateral set to one of the inputs in mustNotSpendUtxosWithOutRefs" do let someUtxos = @@ -253,6 +253,57 @@ suite = do ) res `shouldSatisfy` isLeft + test + "#1581 - Fallback to CTL collateral selection when all collateral inputs are non-spendable" + do + let + distribution = + [ BigNum.fromInt 10_000_000 + , BigNum.fromInt 10_000_000 + ] + withWallets distribution \alice -> + withKeyWallet alice do + validator <- AlwaysSucceeds.alwaysSucceedsScript + let vhash = validatorHash validator + logInfo' "Attempt to lock value" + txId <- AlwaysSucceeds.payToAlwaysSucceeds vhash + awaitTxConfirmed txId + logInfo' "Try to spend locked values" + + scriptAddress <- mkAddress (wrap $ ScriptHashCredential vhash) + Nothing + utxos <- utxosAt scriptAddress + scriptUtxo <- + liftM + ( error + ( "The id " + <> show txId + <> " does not have output locked at: " + <> show scriptAddress + ) + ) + $ head (lookupTxHash txId utxos) + + unbalancedTx <- buildTx + [ SpendOutput scriptUtxo $ Just $ PlutusScriptOutput + (ScriptValue validator) + RedeemerDatum.unit + (Just $ DatumValue PlutusData.unit) + ] + + collUtxos <- getWalletCollateral + let + balancerConstraints = + maybe + mempty + (mustNotSpendUtxosWithOutRefs <<< Map.keys <<< toUtxoMap) + collUtxos + + balancedTx <- balanceTx unbalancedTx (toUtxoMap [ scriptUtxo ]) + balancerConstraints + balancedSignedTx <- signTransaction balancedTx + submitAndLog balancedSignedTx + test "#1480 - test that does nothing but fails" do let someUtxos =