Skip to content

Commit

Permalink
Eliminate more primitive types from balanceTx type signature. (#4134)
Browse files Browse the repository at this point in the history
## Issue

ADP-3157 (follow-on from #4130)

## Summary

This PR replaces the use of `Cardano.Wallet.Primitive` types with
equivalent ledger types in the type signature of `balanceTransaction`.
  • Loading branch information
jonathanknowles authored Sep 29, 2023
2 parents 13c8cb9 + 16ff71b commit f5aaf2f
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 157 deletions.
24 changes: 16 additions & 8 deletions lib/balance-tx/lib/Cardano/Wallet/Shelley/Compatibility/Ledger.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
module Cardano.Wallet.Shelley.Compatibility.Ledger
(
-- * Conversions from wallet types to ledger specification types
toLedgerCoin
toLedgerAddress
, toLedgerCoin
, toLedgerTokenBundle
, toLedgerTokenPolicyId
, toLedgerTokenName
, toLedgerTokenQuantity
, toLedgerTimelockScript

-- * Conversions from ledger specification types to wallet types
, toWalletAddress
, toWalletCoin
, toWalletTokenBundle
, toWalletTokenPolicyId
Expand Down Expand Up @@ -289,13 +291,19 @@ instance Convert TxIn (Ledger.TxIn StandardCrypto) where
--------------------------------------------------------------------------------

instance Convert Address (Ledger.Addr StandardCrypto) where
toLedger (Address bytes ) = case Ledger.deserialiseAddr bytes of
Just addr -> addr
Nothing -> error $ unwords
[ "toLedger @Address: Invalid address:"
, pretty (Address bytes)
]
toWallet = Address . Ledger.serialiseAddr
toLedger = toLedgerAddress
toWallet = toWalletAddress

toLedgerAddress :: Address -> Ledger.Addr StandardCrypto
toLedgerAddress (Address bytes) = case Ledger.deserialiseAddr bytes of
Just addr -> addr
Nothing -> error $ unwords
[ "toLedger @Address: Invalid address:"
, pretty (Address bytes)
]

toWalletAddress :: Ledger.Addr StandardCrypto -> Address
toWalletAddress = Address . Ledger.serialiseAddr

--------------------------------------------------------------------------------
-- Conversions for 'TxOut'
Expand Down
2 changes: 1 addition & 1 deletion lib/balance-tx/lib/Cardano/Wallet/Write/Tx.hs
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ type TxOutInBabbage = Babbage.BabbageTxOut (Babbage.BabbageEra StandardCrypto)
type Address = Ledger.Addr StandardCrypto

type Script = AlonzoScript
type Value = MaryValue
type Value = MaryValue StandardCrypto

unsafeAddressFromBytes :: ByteString -> Address
unsafeAddressFromBytes bytes = case Ledger.deserialiseAddr bytes of
Expand Down
50 changes: 28 additions & 22 deletions lib/balance-tx/lib/Cardano/Wallet/Write/Tx/Balance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ import Cardano.Wallet.Primitive.Types.Tx.Constraints
import Cardano.Wallet.Write.ProtocolParameters
( ProtocolParameters (..) )
import Cardano.Wallet.Write.Tx
( Coin (..)
( Address
, Coin (..)
, FeePerByte (..)
, IsRecentEra (..)
, KeyWitnessCount (..)
Expand All @@ -130,6 +131,7 @@ import Cardano.Wallet.Write.Tx
, TxIn
, TxOut
, UTxO (..)
, Value
, computeMinimumCoinForTxOut
, evaluateMinimumFee
, evaluateTransactionBalance
Expand Down Expand Up @@ -301,11 +303,11 @@ data ErrBalanceTxUnableToCreateChangeError =
-- that would be necessary to balance the transaction.
--
data ErrBalanceTxAssetsInsufficientError = ErrBalanceTxAssetsInsufficientError
{ available :: W.TokenBundle
{ available :: Value
-- ^ The total sum of all assets available.
, required :: W.TokenBundle
, required :: Value
-- ^ The total sum of all assets required.
, shortfall :: W.TokenBundle
, shortfall :: Value
-- ^ The total shortfall between available and required assets.
}
deriving (Eq, Generic, Show)
Expand Down Expand Up @@ -956,7 +958,7 @@ selectAssets era (ProtocolParameters pp) utxoAssumptions outs redeemers
, minimumCollateralPercentage =
withConstraints era $ pp ^. ppCollateralPercentageL
, maximumLengthChangeAddress =
maxLengthChangeAddress changeGen
W.toWalletAddress $ maxLengthChangeAddress changeGen
}

selectionParams = SelectionParams
Expand Down Expand Up @@ -1038,7 +1040,7 @@ selectAssets era (ProtocolParameters pp) utxoAssumptions outs redeemers
extraBytes = 8

data ChangeAddressGen s = ChangeAddressGen
{ getChangeAddressGen :: s -> (W.Address, s)
{ getChangeAddressGen :: s -> (Address, s)

-- | Returns the longest address that the wallet can generate for a given
-- key.
Expand All @@ -1052,7 +1054,7 @@ data ChangeAddressGen s = ChangeAddressGen
-- - never be used for anything besides its length and validity properties.
-- - never be used as a payment target within a real transaction.
--
, maxLengthChangeAddress :: W.Address
, maxLengthChangeAddress :: Address
}

-- | Augments the given outputs with new outputs. These new outputs correspond
Expand All @@ -1066,7 +1068,7 @@ assignChangeAddresses
assignChangeAddresses (ChangeAddressGen genChange _) sel = runState $ do
changeOuts <- forM (view #change sel) $ \bundle -> do
addr <- state genChange
pure $ W.TxOut addr bundle
pure $ W.TxOut (W.toWalletAddress addr) bundle
pure $ (sel :: SelectionOf W.TokenBundle) { change = changeOuts }

-- | Convert a 'Cardano.Value' into a positive and negative component. Useful
Expand Down Expand Up @@ -1450,9 +1452,9 @@ coinSelectionErrorToBalanceTxError = \case
BalanceInsufficient e ->
ErrBalanceTxAssetsInsufficient $
ErrBalanceTxAssetsInsufficientError
{ available = view #utxoBalanceAvailable e
, required = view #utxoBalanceRequired e
, shortfall = view #utxoBalanceShortfall e
{ available = W.toLedger (view #utxoBalanceAvailable e)
, required = W.toLedger (view #utxoBalanceRequired e)
, shortfall = W.toLedger (view #utxoBalanceShortfall e)
}
UnableToConstructChange
UnableToConstructChangeError {shortfall, requiredCost} ->
Expand Down Expand Up @@ -1500,20 +1502,20 @@ data ErrBalanceTxOutputErrorInfo

data ErrBalanceTxOutputAdaQuantityInsufficientError =
ErrBalanceTxOutputAdaQuantityInsufficientError
{ minimumExpectedCoin :: W.Coin
, output :: (W.Address, W.TokenBundle)
{ minimumExpectedCoin :: Coin
, output :: (Address, Value)
}
deriving (Eq, Generic, Show)

newtype ErrBalanceTxOutputSizeExceedsLimitError =
ErrBalanceTxOutputSizeExceedsLimitError
{ outputThatExceedsLimit :: (W.Address, W.TokenBundle)
{ outputThatExceedsLimit :: (Address, Value)
}
deriving (Eq, Generic, Show)

data ErrBalanceTxOutputTokenQuantityExceedsLimitError =
ErrBalanceTxOutputTokenQuantityExceedsLimitError
{ address :: W.Address
{ address :: Address
-- ^ The address to which this token quantity was to be sent.
, asset :: W.AssetId
-- ^ The asset identifier to which this token quantity corresponds.
Expand Down Expand Up @@ -1557,11 +1559,13 @@ validateTxOutputSize
:: SelectionConstraints
-> (W.Address, W.TokenBundle)
-> Maybe ErrBalanceTxOutputSizeExceedsLimitError
validateTxOutputSize cs out = case sizeAssessment of
validateTxOutputSize cs out@(address, bundle) = case sizeAssessment of
TokenBundleSizeWithinLimit ->
Nothing
TokenBundleSizeExceedsLimit ->
Just $ ErrBalanceTxOutputSizeExceedsLimitError out
Just $
ErrBalanceTxOutputSizeExceedsLimitError
(W.toLedger address, W.toLedger bundle)
where
sizeAssessment :: TokenBundleSizeAssessment
sizeAssessment =
Expand All @@ -1578,7 +1582,7 @@ validateTxOutputTokenQuantities
validateTxOutputTokenQuantities out =
[ ErrBalanceTxOutputTokenQuantityExceedsLimitError
{address, asset, quantity, quantityMaxBound = txOutMaxTokenQuantity}
| let address = fst out
| let address = W.toLedgerAddress $ fst out
, (asset, quantity) <- W.TokenMap.toFlatList $ (snd out) ^. #tokens
, quantity > txOutMaxTokenQuantity
]
Expand All @@ -1592,18 +1596,20 @@ validateTxOutputAdaQuantity
:: SelectionConstraints
-> (W.Address, W.TokenBundle)
-> Maybe ErrBalanceTxOutputAdaQuantityInsufficientError
validateTxOutputAdaQuantity constraints output
validateTxOutputAdaQuantity constraints output@(address, bundle)
| isBelowMinimum =
Just ErrBalanceTxOutputAdaQuantityInsufficientError
{minimumExpectedCoin, output}
{ minimumExpectedCoin
, output = (W.toLedger address, W.toLedger bundle)
}
| otherwise =
Nothing
where
isBelowMinimum :: Bool
isBelowMinimum = uncurry (constraints ^. #isBelowMinimumAdaQuantity) output

minimumExpectedCoin :: W.Coin
minimumExpectedCoin =
minimumExpectedCoin :: Coin
minimumExpectedCoin = W.toLedgerCoin $
(constraints ^. #computeMinimumAdaQuantity)
(fst output)
(snd output ^. #tokens)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Prelude
import Cardano.CoinSelection.Size
( TokenBundleSizeAssessment (..), TokenBundleSizeAssessor (..) )
import Cardano.Ledger.Api
( StandardCrypto, ppMaxValSizeL, ppProtocolVersionL )
( ppMaxValSizeL, ppProtocolVersionL )
import Cardano.Ledger.BaseTypes
( ProtVer (pvMajor) )
import Cardano.Ledger.Binary
Expand Down Expand Up @@ -56,7 +56,7 @@ computeTokenBundleSerializedLengthBytes
-> TxSize
computeTokenBundleSerializedLengthBytes tb ver = serSize (toLedger tb)
where
serSize :: Value StandardCrypto -> TxSize
serSize :: Value -> TxSize
serSize v = maybe err TxSize
. intCastMaybe
. BL.length
Expand Down
19 changes: 12 additions & 7 deletions lib/wallet/api/http/Cardano/Wallet/Api/Http/Server/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ import Cardano.Wallet.Primitive.Types.TokenMap
import Cardano.Wallet.Primitive.Types.Tx.SealedTx
( serialisedTx )
import Cardano.Wallet.Shelley.Compatibility.Ledger
( toWalletCoin )
( Convert (toWallet), toWalletAddress, toWalletCoin, toWalletTokenBundle )
import Cardano.Wallet.Transaction
( ErrSignTx (..) )
import Cardano.Wallet.Write.Tx.Balance
Expand Down Expand Up @@ -503,7 +503,8 @@ instance IsServerError ErrBalanceTx where
apiError err403 NotEnoughMoney $ mconcat
[ "I can't process this payment as there are not "
, "enough funds available in the wallet. I am "
, "missing: ", pretty . Flat $ e ^. #shortfall
, "missing: "
, pretty . Flat . toWalletTokenBundle $ e ^. #shortfall
]
ErrBalanceTxAssignRedeemers err -> toServerError err
ErrBalanceTxConflictingNetworks ->
Expand Down Expand Up @@ -924,9 +925,13 @@ instance IsServerError ErrBalanceTxOutputError where
, show index
]
, txOutputLovelaceSpecified =
Coin.toQuantity $ TokenBundle.getCoin $ snd $ view #output e
Coin.toQuantity
$ TokenBundle.getCoin
$ toWallet
$ snd
$ view #output e
, txOutputLovelaceRequiredMinimum =
Coin.toQuantity $ view #minimumExpectedCoin e
Coin.toQuantity $ toWalletCoin $ view #minimumExpectedCoin e
}
ErrBalanceTxOutputSizeExceedsLimit e ->
toServerError e
Expand All @@ -948,9 +953,9 @@ instance IsServerError ErrBalanceTxOutputSizeExceedsLimitError
[ "One of the outputs you've specified contains too many assets. "
, "Try splitting these assets across two or more outputs. "
, "Destination address: "
, pretty (fst output)
, pretty (toWalletAddress (fst output))
, ". Asset count: "
, pretty (TokenMap.size $ snd output ^. #tokens)
, pretty (TokenMap.size $ toWalletTokenBundle (snd output) ^. #tokens)
, "."
]
where
Expand All @@ -963,7 +968,7 @@ instance IsServerError ErrBalanceTxOutputTokenQuantityExceedsLimitError
, "maximum quantity allowed in a single transaction output. Try "
, "splitting this quantity across two or more outputs. "
, "Destination address: "
, pretty (view #address e)
, pretty (toWalletAddress (view #address e))
, ". Token policy identifier: "
, pretty (view (#asset . #tokenPolicyId) e)
, ". Asset name: "
Expand Down
12 changes: 7 additions & 5 deletions lib/wallet/src/Cardano/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ import Cardano.Wallet.Shelley.Compatibility
, fromCardanoWdrls
)
import Cardano.Wallet.Shelley.Compatibility.Ledger
( toWallet, toWalletCoin )
( toLedgerAddress, toWallet, toWalletCoin )
import Cardano.Wallet.Shelley.Transaction
( txWitnessTagForKey )
import Cardano.Wallet.Transaction
Expand Down Expand Up @@ -555,6 +555,8 @@ import Control.Tracer
( Tracer, contramap, traceWith )
import Crypto.Hash
( Blake2b_256, hash )
import Data.Bifunctor
( first )
import Data.ByteString
( ByteString )
import Data.DBVar
Expand Down Expand Up @@ -3712,16 +3714,16 @@ defaultChangeAddressGen
-> ChangeAddressGen s
defaultChangeAddressGen arg =
ChangeAddressGen
(genChange arg)
(maxLengthAddressFor (keyFlavorFromState @s))
(first toLedgerAddress <$> genChange arg)
(toLedgerAddress $ maxLengthAddressFor (keyFlavorFromState @s))

-- WARNING: Must never be used to create real transactions for submission to the
-- blockchain as funds sent to a dummy change address would be irrecoverable.
dummyChangeAddressGen :: forall s. WalletFlavor s => ChangeAddressGen s
dummyChangeAddressGen =
ChangeAddressGen
(maxLengthAddressFor (keyFlavorFromState @s),)
(maxLengthAddressFor (keyFlavorFromState @s))
(toLedgerAddress $ maxLengthAddressFor (keyFlavorFromState @s),)
(toLedgerAddress $ maxLengthAddressFor (keyFlavorFromState @s))

utxoAssumptionsForWallet
:: forall s
Expand Down
Loading

0 comments on commit f5aaf2f

Please sign in to comment.