Skip to content

Commit

Permalink
Translate possible cases of ErrBalanceTx to ErrCreatePayment
Browse files Browse the repository at this point in the history
  • Loading branch information
Anviking committed Dec 19, 2024
1 parent 6564b89 commit 7dfc904
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.Wallet.Deposit.Pure.State.Payment
Expand All @@ -9,12 +10,16 @@ module Cardano.Wallet.Deposit.Pure.State.Payment
, createPaymentTxBody
, CurrentEraResolvedTx
, resolveCurrentEraTx
, translateBalanceTxError
) where

import Prelude hiding
( lookup
)

import Cardano.Ledger.Val
( isAdaOnly
)
import Cardano.Wallet.Deposit.Pure.State.Submissions
( availableUTxO
)
Expand All @@ -29,8 +34,18 @@ import Cardano.Wallet.Deposit.Read
( Address
)
import Cardano.Wallet.Deposit.Write
( Tx
( Coin
, Tx
, TxBody (..)
, Value
)
import Cardano.Wallet.Read
( AssetID (AdaID)
, Coin (..)
, fromEraValue
, injectCoin
, lookupAssetID
, toMaryValue
)
import Control.Monad.Trans.Except
( runExceptT
Expand All @@ -41,10 +56,18 @@ import Data.Bifunctor
import Data.Digest.CRC32
( crc32
)
import Data.Fixed
( E6
, Fixed
)
import Data.Text
( Text
)
import Data.Text.Class.Extended
( ToText (..)
)

import qualified Cardano.Read.Ledger.Value as Read.L
import qualified Cardano.Wallet.Deposit.Pure.Address as Address
import qualified Cardano.Wallet.Deposit.Read as Read
import qualified Cardano.Wallet.Deposit.Write as Write
Expand All @@ -55,15 +78,108 @@ import qualified Data.Text as T

data ErrCreatePayment
= ErrCreatePaymentNotRecentEra (Read.EraValue Read.Era)
| ErrCreatePaymentBalanceTx (Write.ErrBalanceTx Write.Conway)
| ErrNotEnoughAda { shortfall :: Value }
| ErrEmptyUTxO

| ErrTxOutAdaInsufficient { outputIx :: Int, suggestedMinimum :: Coin }

-- | The final balanced tx was too big. Either because the payload was too
-- big to begin with, or because we failed to select enough inputs without
-- making it too big, e.g. due to the UTxO containing lots of dust.
--
-- We should ideally split out 'TooManyPayments' from this error.
-- We should ideally also be able to create payments even when dust causes
-- us to need preparatory txs.
| ErrTxMaxSizeLimitExceeded
deriving (Eq, Show)

translateBalanceTxError :: Write.ErrBalanceTx Write.Conway -> ErrCreatePayment
translateBalanceTxError = \case
Write.ErrBalanceTxAssetsInsufficient
Write.ErrBalanceTxAssetsInsufficientError{shortfall} ->
ErrNotEnoughAda
{ shortfall = fromLedgerValue shortfall
}
Write.ErrBalanceTxMaxSizeLimitExceeded ->
ErrTxMaxSizeLimitExceeded
Write.ErrBalanceTxExistingKeyWitnesses _ ->
impossible "ErrBalanceTxExistingKeyWitnesses"
Write.ErrBalanceTxExistingCollateral ->
impossible "ErrBalanceTxExistingCollateral"
Write.ErrBalanceTxExistingTotalCollateral ->
impossible "ErrBalanceTxExistingTotalCollateral"
Write.ErrBalanceTxExistingReturnCollateral ->
impossible "ErrBalanceTxExistingReturnCollateral"
Write.ErrBalanceTxInsufficientCollateral _ ->
impossible "ErrBalanceTxInsufficientCollateral"
Write.ErrBalanceTxAssignRedeemers _ ->
impossible "ErrBalanceTxAssignRedeemers"
Write.ErrBalanceTxInternalError e ->
impossible $ show e
Write.ErrBalanceTxInputResolutionConflicts _ ->
-- We are never creating partialTxs with pre-selected inputs, which
-- means this is impossible.
impossible "conflicting input resolution"
Write.ErrBalanceTxUnresolvedInputs _ ->
-- We are never creating partialTxs with pre-selected inputs, which
-- means this is impossible.
impossible "unresolved inputs"
Write.ErrBalanceTxUnresolvedRefunds _ ->
impossible "unresolved refunds"
Write.ErrBalanceTxOutputError (Write.ErrBalanceTxOutputErrorOf ix (Write.ErrBalanceTxOutputAdaQuantityInsufficient{minimumExpectedCoin})) ->
ErrTxOutAdaInsufficient { outputIx = ix, suggestedMinimum = minimumExpectedCoin }
Write.ErrBalanceTxOutputError (Write.ErrBalanceTxOutputErrorOf _ix (Write.ErrBalanceTxOutputSizeExceedsLimit{})) ->
impossible "value can't be too big if there are no assets"
Write.ErrBalanceTxOutputError (Write.ErrBalanceTxOutputErrorOf _ix (Write.ErrBalanceTxOutputTokenQuantityExceedsLimit{})) ->
impossible "tokenQuantity can't be too big if there are no tokens"
Write.ErrBalanceTxUnableToCreateChange
Write.ErrBalanceTxUnableToCreateChangeError{shortfall} ->
ErrNotEnoughAda
{ shortfall = injectCoin shortfall
}
Write.ErrBalanceTxUnableToCreateInput ->
ErrEmptyUTxO

where
fromLedgerValue v = fromEraValue (Read.L.Value v :: Read.L.Value Write.Conway)

impossible :: String -> a
impossible reason = error $ "impossible: translateBalanceTxError: " <> reason


instance ToText ErrCreatePayment where
toText = \case
ErrCreatePaymentNotRecentEra era ->
"Cannot create a payment in the era: " <> T.pack (show era)
ErrCreatePaymentBalanceTx err ->
"Cannot create a payment: " <> T.pack (show err)
ErrNotEnoughAda{shortfall} -> T.unwords
[ "Insufficient funds. Shortfall: ", prettyValue shortfall
]
ErrEmptyUTxO -> "Wallet has no funds"
ErrTxOutAdaInsufficient{outputIx, suggestedMinimum} -> T.unwords
[ "Ada amount in output " <> T.pack (show outputIx)
, "is below the required minimum."
, "Suggested minimum amount:", prettyCoin suggestedMinimum
]
ErrTxMaxSizeLimitExceeded -> T.unwords
[ "Exceeded the maximum size limit when creating the transaction."
, "Potential solutions:"
, "1) Make fewer payments at the same time."
, "2) Send smaller amounts of ada in total."
, "3) Fund wallet with more ada."
, "4) Make preparatory payments to yourself to coalesce dust into"
, "larger UTxOs."
]
where
prettyValue :: Value -> Text
prettyValue v
| isAdaOnly (toMaryValue v) = prettyCoin (CoinC $ lookupAssetID AdaID v)
| otherwise = T.pack (show v)

prettyCoin :: Coin -> Text
prettyCoin c = T.pack (show c') <> ""
where
c' :: Fixed E6
c' = toEnum $ fromEnum c

type CurrentEraResolvedTx = ResolvedTx Read.Conway

Expand Down Expand Up @@ -93,7 +209,7 @@ createPaymentTxBody
state =
case Read.theEra :: Read.Era era of
Read.Conway ->
first ErrCreatePaymentBalanceTx
first translateBalanceTxError
$ flip resolveCurrentEraTx state
<$> createPaymentConway
pparams
Expand Down
11 changes: 11 additions & 0 deletions lib/customer-deposit-wallet/src/Cardano/Wallet/Deposit/Write.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Cardano.Wallet.Deposit.Write
, TxBody (..)
, TxIn
, TxOut
, Coin

-- * Transaction balancing
, Write.IsRecentEra
Expand All @@ -31,6 +32,13 @@ module Cardano.Wallet.Deposit.Write
, toConwayUTxO
, Write.PartialTx (..)
, Write.ErrBalanceTx (..)
, Write.ErrBalanceTxAssetsInsufficientError (..)
, Write.ErrBalanceTxInsufficientCollateralError (..)
, Write.ErrBalanceTxInternalError (..)
, Write.ErrBalanceTxOutputError (..)
, Write.ErrBalanceTxOutputErrorInfo (..)
, Write.ErrBalanceTxUnableToCreateChangeError (..)
, Write.ErrAssignRedeemers (..)
, Write.balanceTx

-- * Signing
Expand All @@ -53,6 +61,9 @@ module Cardano.Wallet.Deposit.Write

import Prelude

import Cardano.Ledger.Coin
( Coin
)
import Cardano.Read.Ledger.Tx.Output
( Output (..)
)
Expand Down

0 comments on commit 7dfc904

Please sign in to comment.