module PlutusLedgerApi.V3.Orphans.Value (
  -- * Specialized Value wrappers
  MintValue (..),
  getMintValue,
) where

import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Coerce (coerce)
import Data.Set qualified as Set
import PlutusLedgerApi.Orphans.Common (getBlake2b244Hash)
import PlutusLedgerApi.V1 qualified as PLA
import PlutusLedgerApi.V1.Orphans.Value ()
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import PlutusTx.Prelude qualified as PlutusTx
import Test.QuickCheck (
  Arbitrary (arbitrary, shrink),
  Arbitrary1 (liftArbitrary, liftShrink),
  CoArbitrary,
  Function (function),
  Gen,
  NonZero (NonZero),
  chooseBoundedIntegral,
  chooseInt,
  functionMap,
  getNonEmpty,
  getNonZero,
  resize,
  scale,
  sized,
  vectorOf,
 )

{- | A 'PLA.Value' that contains only non-zero amounts but does not have zero Ada entry

= Note

This is designed to act as a modifier, and thus, we expose the constructor
even though it preserves invariants. If you use the constructor directly,
be /very/ certain that the Value being wrapped satisfies the invariants
described above: failing to do so means all guarantees of this type are off
the table.

@since WIP
-}
newtype MintValue = MintValue PLA.Value
  deriving
    ( -- | @since WIP
      MintValue -> MintValue -> Bool
(MintValue -> MintValue -> Bool)
-> (MintValue -> MintValue -> Bool) -> Eq MintValue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MintValue -> MintValue -> Bool
== :: MintValue -> MintValue -> Bool
$c/= :: MintValue -> MintValue -> Bool
/= :: MintValue -> MintValue -> Bool
Eq
    )
    via PLA.Value
  deriving stock
    ( -- | @since WIP
      Int -> MintValue -> ShowS
[MintValue] -> ShowS
MintValue -> String
(Int -> MintValue -> ShowS)
-> (MintValue -> String)
-> ([MintValue] -> ShowS)
-> Show MintValue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MintValue -> ShowS
showsPrec :: Int -> MintValue -> ShowS
$cshow :: MintValue -> String
show :: MintValue -> String
$cshowList :: [MintValue] -> ShowS
showList :: [MintValue] -> ShowS
Show
    )

-- | @since WIP
instance Arbitrary MintValue where
  {-# INLINEABLE arbitrary #-}
  arbitrary :: Gen MintValue
arbitrary =
    Value -> MintValue
MintValue (Value -> MintValue) -> Gen Value -> Gen MintValue
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> do
      -- Generate a set of currency symbols that aren't Ada
      Set CurrencySymbol
keySet <- [CurrencySymbol] -> Set CurrencySymbol
forall a. Ord a => [a] -> Set a
Set.fromList ([CurrencySymbol] -> Set CurrencySymbol)
-> Gen [CurrencySymbol] -> Gen (Set CurrencySymbol)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen CurrencySymbol -> Gen [CurrencySymbol]
forall a. Gen a -> Gen [a]
forall (f :: Type -> Type) a. Arbitrary1 f => Gen a -> Gen (f a)
liftArbitrary (BuiltinByteString -> CurrencySymbol
PLA.CurrencySymbol (BuiltinByteString -> CurrencySymbol)
-> (Blake2b244Hash -> BuiltinByteString)
-> Blake2b244Hash
-> CurrencySymbol
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Blake2b244Hash -> BuiltinByteString
getBlake2b244Hash (Blake2b244Hash -> CurrencySymbol)
-> Gen Blake2b244Hash -> Gen CurrencySymbol
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Blake2b244Hash
forall a. Arbitrary a => Gen a
arbitrary)
      let keyList :: [CurrencySymbol]
keyList = Set CurrencySymbol -> [CurrencySymbol]
forall a. Set a -> [a]
Set.toList Set CurrencySymbol
keySet
      -- For each key, generate a set of token name keys that aren't Ada
      [(CurrencySymbol, [(TokenName, Integer)])]
keyVals <- (CurrencySymbol -> Gen (CurrencySymbol, [(TokenName, Integer)]))
-> [CurrencySymbol]
-> Gen [(CurrencySymbol, [(TokenName, Integer)])]
forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: Type -> Type) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse ((Int -> Int)
-> Gen (CurrencySymbol, [(TokenName, Integer)])
-> Gen (CurrencySymbol, [(TokenName, Integer)])
forall a. (Int -> Int) -> Gen a -> Gen a
scale (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
8) (Gen (CurrencySymbol, [(TokenName, Integer)])
 -> Gen (CurrencySymbol, [(TokenName, Integer)]))
-> (CurrencySymbol -> Gen (CurrencySymbol, [(TokenName, Integer)]))
-> CurrencySymbol
-> Gen (CurrencySymbol, [(TokenName, Integer)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CurrencySymbol -> Gen (CurrencySymbol, [(TokenName, Integer)])
mkInner) [CurrencySymbol]
keyList

      -- It is possible to generate positive and negative quantity of the same asset so we have to
      -- prune zeros despite using NonZero generator
      Value -> Gen Value
forall a. a -> Gen a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Value -> Gen Value)
-> ([(CurrencySymbol, [(TokenName, Integer)])] -> Value)
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> Gen Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Value
pruneZeros (Value -> Value)
-> ([(CurrencySymbol, [(TokenName, Integer)])] -> Value)
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((CurrencySymbol, [(TokenName, Integer)]) -> Value)
-> [(CurrencySymbol, [(TokenName, Integer)])] -> Value
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: Type -> Type) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (\(CurrencySymbol
cs, [(TokenName, Integer)]
vals) -> ((TokenName, Integer) -> Value) -> [(TokenName, Integer)] -> Value
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: Type -> Type) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ((TokenName -> Integer -> Value) -> (TokenName, Integer) -> Value
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (CurrencySymbol -> TokenName -> Integer -> Value
Value.singleton CurrencySymbol
cs)) [(TokenName, Integer)]
vals) ([(CurrencySymbol, [(TokenName, Integer)])] -> Gen Value)
-> [(CurrencySymbol, [(TokenName, Integer)])] -> Gen Value
forall a b. (a -> b) -> a -> b
$ [(CurrencySymbol, [(TokenName, Integer)])]
keyVals
    where
      mkInner :: PLA.CurrencySymbol -> Gen (PLA.CurrencySymbol, [(PLA.TokenName, Integer)])
      mkInner :: CurrencySymbol -> Gen (CurrencySymbol, [(TokenName, Integer)])
mkInner CurrencySymbol
cs =
        (CurrencySymbol
cs,)
          ([(TokenName, Integer)]
 -> (CurrencySymbol, [(TokenName, Integer)]))
-> (NonEmptyList (TokenName, Integer) -> [(TokenName, Integer)])
-> NonEmptyList (TokenName, Integer)
-> (CurrencySymbol, [(TokenName, Integer)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set (TokenName, Integer) -> [(TokenName, Integer)]
forall a. Set a -> [a]
Set.toList
          (Set (TokenName, Integer) -> [(TokenName, Integer)])
-> (NonEmptyList (TokenName, Integer) -> Set (TokenName, Integer))
-> NonEmptyList (TokenName, Integer)
-> [(TokenName, Integer)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(TokenName, Integer)] -> Set (TokenName, Integer)
forall a. Ord a => [a] -> Set a
Set.fromList
          ([(TokenName, Integer)] -> Set (TokenName, Integer))
-> (NonEmptyList (TokenName, Integer) -> [(TokenName, Integer)])
-> NonEmptyList (TokenName, Integer)
-> Set (TokenName, Integer)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmptyList (TokenName, Integer) -> [(TokenName, Integer)]
forall a. NonEmptyList a -> [a]
getNonEmpty
          (NonEmptyList (TokenName, Integer)
 -> (CurrencySymbol, [(TokenName, Integer)]))
-> Gen (NonEmptyList (TokenName, Integer))
-> Gen (CurrencySymbol, [(TokenName, Integer)])
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen (TokenName, Integer) -> Gen (NonEmptyList (TokenName, Integer))
forall a. Gen a -> Gen (NonEmptyList a)
forall (f :: Type -> Type) a. Arbitrary1 f => Gen a -> Gen (f a)
liftArbitrary ((,) (TokenName -> Integer -> (TokenName, Integer))
-> Gen TokenName -> Gen (Integer -> (TokenName, Integer))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen TokenName
genNonAdaTokenName Gen (Integer -> (TokenName, Integer))
-> Gen Integer -> Gen (TokenName, Integer)
forall a b. Gen (a -> b) -> Gen a -> Gen b
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> (NonZero Integer -> Integer
forall a. NonZero a -> a
getNonZero (NonZero Integer -> Integer)
-> Gen (NonZero Integer) -> Gen Integer
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen (NonZero Integer)
forall a. Arbitrary a => Gen a
arbitrary))

      genNonAdaTokenName :: Gen PLA.TokenName
      genNonAdaTokenName :: Gen TokenName
genNonAdaTokenName = ([Word8] -> TokenName) -> Gen [Word8] -> Gen TokenName
forall a b. (a -> b) -> Gen a -> Gen b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (BuiltinByteString -> TokenName
PLA.TokenName (BuiltinByteString -> TokenName)
-> ([Word8] -> BuiltinByteString) -> [Word8] -> TokenName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HasToBuiltin a => a -> ToBuiltin a
PlutusTx.toBuiltin @ByteString (ByteString -> BuiltinByteString)
-> ([Word8] -> ByteString) -> [Word8] -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
BS.pack) (Gen [Word8] -> Gen TokenName)
-> ((Int -> Gen [Word8]) -> Gen [Word8])
-> (Int -> Gen [Word8])
-> Gen TokenName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Gen [Word8]) -> Gen [Word8]
forall a. (Int -> Gen a) -> Gen a
sized ((Int -> Gen [Word8]) -> Gen TokenName)
-> (Int -> Gen [Word8]) -> Gen TokenName
forall a b. (a -> b) -> a -> b
$ \Int
size -> do
        Int
len <- Int -> Gen Int -> Gen Int
forall a. HasCallStack => Int -> Gen a -> Gen a
resize Int
size (Gen Int -> Gen Int)
-> ((Int, Int) -> Gen Int) -> (Int, Int) -> Gen Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, Int) -> Gen Int
chooseInt ((Int, Int) -> Gen Int) -> (Int, Int) -> Gen Int
forall a b. (a -> b) -> a -> b
$ (Int
1, Int
32)
        Int -> Gen Word8 -> Gen [Word8]
forall a. Int -> Gen a -> Gen [a]
vectorOf Int
len (Gen Word8 -> Gen [Word8])
-> ((Word8, Word8) -> Gen Word8) -> (Word8, Word8) -> Gen [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8, Word8) -> Gen Word8
forall a. (Bounded a, Integral a) => (a, a) -> Gen a
chooseBoundedIntegral ((Word8, Word8) -> Gen [Word8]) -> (Word8, Word8) -> Gen [Word8]
forall a b. (a -> b) -> a -> b
$ (Word8
33, Word8
126)
  {-# INLINEABLE shrink #-}
  shrink :: MintValue -> [MintValue]
shrink (MintValue (Value.Value Map CurrencySymbol (Map TokenName Integer)
v)) =
    Value -> MintValue
MintValue (Value -> MintValue)
-> (Map CurrencySymbol (Map TokenName Integer) -> Value)
-> Map CurrencySymbol (Map TokenName Integer)
-> MintValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map CurrencySymbol (Map TokenName Integer) -> Value
Value.Value (Map CurrencySymbol (Map TokenName Integer) -> MintValue)
-> [Map CurrencySymbol (Map TokenName Integer)] -> [MintValue]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> do
      -- To ensure we don't break anything, we shrink in only two ways:
      --
      -- 1. Dropping keys (outer or inner)
      -- 2. Shrinking amounts
      --
      -- To make this a bit easier on ourselves, we first 'unpack' the Value
      -- completely, shrink the resulting (nested) list, then 'repack'. As neither
      -- of these changes affect order or uniqueness, we're safe.
      let asList :: [(CurrencySymbol, [(TokenName, Integer)])]
asList = (Map TokenName Integer -> [(TokenName, Integer)])
-> (CurrencySymbol, Map TokenName Integer)
-> (CurrencySymbol, [(TokenName, Integer)])
forall a b. (a -> b) -> (CurrencySymbol, a) -> (CurrencySymbol, b)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Map TokenName Integer -> [(TokenName, Integer)]
forall k v. Map k v -> [(k, v)]
AssocMap.toList ((CurrencySymbol, Map TokenName Integer)
 -> (CurrencySymbol, [(TokenName, Integer)]))
-> [(CurrencySymbol, Map TokenName Integer)]
-> [(CurrencySymbol, [(TokenName, Integer)])]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Map CurrencySymbol (Map TokenName Integer)
-> [(CurrencySymbol, Map TokenName Integer)]
forall k v. Map k v -> [(k, v)]
AssocMap.toList Map CurrencySymbol (Map TokenName Integer)
v
      [(CurrencySymbol, [(TokenName, Integer)])]
shrunk <- ((CurrencySymbol, [(TokenName, Integer)])
 -> [(CurrencySymbol, [(TokenName, Integer)])])
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> [[(CurrencySymbol, [(TokenName, Integer)])]]
forall a. (a -> [a]) -> [a] -> [[a]]
forall (f :: Type -> Type) a.
Arbitrary1 f =>
(a -> [a]) -> f a -> [f a]
liftShrink (\(CurrencySymbol
cs, [(TokenName, Integer)]
inner) -> (CurrencySymbol
cs,) ([(TokenName, Integer)]
 -> (CurrencySymbol, [(TokenName, Integer)]))
-> [[(TokenName, Integer)]]
-> [(CurrencySymbol, [(TokenName, Integer)])]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ((TokenName, Integer) -> [(TokenName, Integer)])
-> [(TokenName, Integer)] -> [[(TokenName, Integer)]]
forall a. (a -> [a]) -> [a] -> [[a]]
forall (f :: Type -> Type) a.
Arbitrary1 f =>
(a -> [a]) -> f a -> [f a]
liftShrink (\(TokenName
tn, Integer
amount) -> (TokenName
tn,) (Integer -> (TokenName, Integer))
-> (NonZero Integer -> Integer)
-> NonZero Integer
-> (TokenName, Integer)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonZero Integer -> Integer
forall a. NonZero a -> a
getNonZero (NonZero Integer -> (TokenName, Integer))
-> [NonZero Integer] -> [(TokenName, Integer)]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> NonZero Integer -> [NonZero Integer]
forall a. Arbitrary a => a -> [a]
shrink (Integer -> NonZero Integer
forall a. a -> NonZero a
NonZero Integer
amount)) [(TokenName, Integer)]
inner) [(CurrencySymbol, [(TokenName, Integer)])]
asList
      Map CurrencySymbol (Map TokenName Integer)
-> [Map CurrencySymbol (Map TokenName Integer)]
forall a. a -> [a]
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Map CurrencySymbol (Map TokenName Integer)
 -> [Map CurrencySymbol (Map TokenName Integer)])
-> ([(CurrencySymbol, [(TokenName, Integer)])]
    -> Map CurrencySymbol (Map TokenName Integer))
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> [Map CurrencySymbol (Map TokenName Integer)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(CurrencySymbol, Map TokenName Integer)]
-> Map CurrencySymbol (Map TokenName Integer)
forall k v. [(k, v)] -> Map k v
AssocMap.unsafeFromList ([(CurrencySymbol, Map TokenName Integer)]
 -> Map CurrencySymbol (Map TokenName Integer))
-> ([(CurrencySymbol, [(TokenName, Integer)])]
    -> [(CurrencySymbol, Map TokenName Integer)])
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> Map CurrencySymbol (Map TokenName Integer)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((CurrencySymbol, [(TokenName, Integer)])
 -> (CurrencySymbol, Map TokenName Integer))
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> [(CurrencySymbol, Map TokenName Integer)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (([(TokenName, Integer)] -> Map TokenName Integer)
-> (CurrencySymbol, [(TokenName, Integer)])
-> (CurrencySymbol, Map TokenName Integer)
forall a b. (a -> b) -> (CurrencySymbol, a) -> (CurrencySymbol, b)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap [(TokenName, Integer)] -> Map TokenName Integer
forall k v. [(k, v)] -> Map k v
AssocMap.unsafeFromList) ([(CurrencySymbol, [(TokenName, Integer)])]
 -> [Map CurrencySymbol (Map TokenName Integer)])
-> [(CurrencySymbol, [(TokenName, Integer)])]
-> [Map CurrencySymbol (Map TokenName Integer)]
forall a b. (a -> b) -> a -> b
$ [(CurrencySymbol, [(TokenName, Integer)])]
shrunk

-- | @since WIP
deriving via PLA.Value instance CoArbitrary MintValue

-- | @since WIP
instance Function MintValue where
  {-# INLINEABLE function #-}
  function :: forall b. (MintValue -> b) -> MintValue :-> b
function = (MintValue -> Value)
-> (Value -> MintValue) -> (MintValue -> b) -> MintValue :-> b
forall b a c.
Function b =>
(a -> b) -> (b -> a) -> (a -> c) -> a :-> c
functionMap MintValue -> Value
forall a b. Coercible a b => a -> b
coerce Value -> MintValue
MintValue

-- | @since WIP
getMintValue :: MintValue -> Value.Value
getMintValue :: MintValue -> Value
getMintValue = MintValue -> Value
forall a b. Coercible a b => a -> b
coerce

pruneZeros :: Value.Value -> Value.Value
pruneZeros :: Value -> Value
pruneZeros (Value.Value Map CurrencySymbol (Map TokenName Integer)
assets) =
  Map CurrencySymbol (Map TokenName Integer) -> Value
Value.Value (Map CurrencySymbol (Map TokenName Integer) -> Value)
-> Map CurrencySymbol (Map TokenName Integer) -> Value
forall a b. (a -> b) -> a -> b
$
    [(CurrencySymbol, Map TokenName Integer)]
-> Map CurrencySymbol (Map TokenName Integer)
forall k v. [(k, v)] -> Map k v
AssocMap.unsafeFromList ([(CurrencySymbol, Map TokenName Integer)]
 -> Map CurrencySymbol (Map TokenName Integer))
-> [(CurrencySymbol, Map TokenName Integer)]
-> Map CurrencySymbol (Map TokenName Integer)
forall a b. (a -> b) -> a -> b
$
      ((CurrencySymbol, Map TokenName Integer) -> Bool)
-> [(CurrencySymbol, Map TokenName Integer)]
-> [(CurrencySymbol, Map TokenName Integer)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ((CurrencySymbol, Map TokenName Integer) -> Bool)
-> (CurrencySymbol, Map TokenName Integer)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map TokenName Integer -> Bool
forall k v. Map k v -> Bool
AssocMap.null (Map TokenName Integer -> Bool)
-> ((CurrencySymbol, Map TokenName Integer)
    -> Map TokenName Integer)
-> (CurrencySymbol, Map TokenName Integer)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CurrencySymbol, Map TokenName Integer) -> Map TokenName Integer
forall a b. (a, b) -> b
snd) ([(CurrencySymbol, Map TokenName Integer)]
 -> [(CurrencySymbol, Map TokenName Integer)])
-> [(CurrencySymbol, Map TokenName Integer)]
-> [(CurrencySymbol, Map TokenName Integer)]
forall a b. (a -> b) -> a -> b
$ -- After removing tokens now we may have empty currency list, so clear that as well
        Map CurrencySymbol (Map TokenName Integer)
-> [(CurrencySymbol, Map TokenName Integer)]
forall k v. Map k v -> [(k, v)]
AssocMap.toList ((Map TokenName Integer -> Maybe (Map TokenName Integer))
-> Map CurrencySymbol (Map TokenName Integer)
-> Map CurrencySymbol (Map TokenName Integer)
forall a b k. (a -> Maybe b) -> Map k a -> Map k b
AssocMap.mapMaybe ([(TokenName, Integer)] -> Maybe (Map TokenName Integer)
forall k v. [(k, v)] -> Maybe (Map k v)
assocMapNonEmpty ([(TokenName, Integer)] -> Maybe (Map TokenName Integer))
-> (Map TokenName Integer -> [(TokenName, Integer)])
-> Map TokenName Integer
-> Maybe (Map TokenName Integer)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((TokenName, Integer) -> Bool)
-> [(TokenName, Integer)] -> [(TokenName, Integer)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0) (Integer -> Bool)
-> ((TokenName, Integer) -> Integer)
-> (TokenName, Integer)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TokenName, Integer) -> Integer
forall a b. (a, b) -> b
snd) ([(TokenName, Integer)] -> [(TokenName, Integer)])
-> (Map TokenName Integer -> [(TokenName, Integer)])
-> Map TokenName Integer
-> [(TokenName, Integer)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map TokenName Integer -> [(TokenName, Integer)]
forall k v. Map k v -> [(k, v)]
AssocMap.toList) Map CurrencySymbol (Map TokenName Integer)
assets) -- Remove all zero tokens
  where
    assocMapNonEmpty :: [(k, v)] -> Maybe (AssocMap.Map k v)
    assocMapNonEmpty :: forall k v. [(k, v)] -> Maybe (Map k v)
assocMapNonEmpty [] = Maybe (Map k v)
forall a. Maybe a
Nothing
    assocMapNonEmpty [(k, v)]
lst = Map k v -> Maybe (Map k v)
forall a. a -> Maybe a
Just (Map k v -> Maybe (Map k v)) -> Map k v -> Maybe (Map k v)
forall a b. (a -> b) -> a -> b
$ [(k, v)] -> Map k v
forall k v. [(k, v)] -> Map k v
AssocMap.unsafeFromList [(k, v)]
lst