{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}

module Cardano.Ledger.Plutus.ToPlutusData where

import Cardano.Ledger.BaseTypes (
  BoundedRational (boundRational, unboundRational),
  EpochInterval (..),
  NonNegativeInterval,
  ProtVer (..),
  UnitInterval,
 )
import Cardano.Ledger.Binary.Version (Version, getVersion, mkVersion)
import Cardano.Ledger.Coin (Coin (..))
import Cardano.Ledger.Plutus.CostModels (
  CostModels,
  flattenCostModels,
  mkCostModelsLenient,
 )
import Cardano.Ledger.Plutus.ExUnits (ExUnits (..), Prices (..))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Ratio ((%))
import Data.Word
import GHC.Real (Ratio ((:%)))
import Numeric.Natural (Natural)
import PlutusLedgerApi.Common (Data (..))

-- ===============================================================

-- ToPlutusData class, and instances for parameterized data types List, Map.

class ToPlutusData x where
  toPlutusData :: x -> Data
  fromPlutusData :: Data -> Maybe x
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData a => ToPlutusData [a] where
  toPlutusData :: [a] -> Data
toPlutusData [a]
xs = [Data] -> Data
List (forall a b. (a -> b) -> [a] -> [b]
map forall x. ToPlutusData x => x -> Data
toPlutusData [a]
xs)
  fromPlutusData :: Data -> Maybe [a]
fromPlutusData (List [Data]
xs) = forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData [Data]
xs
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance (Ord a, ToPlutusData a, ToPlutusData b) => ToPlutusData (Map a b) where
  toPlutusData :: Map a b -> Data
toPlutusData Map a b
m = [(Data, Data)] -> Data
Map forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (\(a
a, b
b) -> (forall x. ToPlutusData x => x -> Data
toPlutusData a
a, forall x. ToPlutusData x => x -> Data
toPlutusData b
b)) (forall k a. Map k a -> [(k, a)]
Map.toAscList Map a b
m)
  fromPlutusData :: Data -> Maybe (Map a b)
fromPlutusData (Map [(Data, Data)]
pairs) =
    forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
      forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\(Data
k, Data
v) -> (,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
k forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
v) [(Data, Data)]
pairs
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

-- ==========================================================
-- ToPlutusData instances for concrete types needed for PParamUpdates

instance ToPlutusData Version where
  toPlutusData :: Version -> Data
toPlutusData Version
v = Integer -> Data
I (forall i. Integral i => Version -> i
getVersion @Integer Version
v)
  fromPlutusData :: Data -> Maybe Version
fromPlutusData (I Integer
n) = forall i (m :: * -> *). (Integral i, MonadFail m) => i -> m Version
mkVersion @Integer Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData ProtVer where
  toPlutusData :: ProtVer -> Data
toPlutusData ProtVer
pv = [Data] -> Data
List [forall x. ToPlutusData x => x -> Data
toPlutusData (ProtVer -> Version
pvMajor ProtVer
pv), forall x. ToPlutusData x => x -> Data
toPlutusData (ProtVer -> Natural
pvMinor ProtVer
pv)]
  fromPlutusData :: Data -> Maybe ProtVer
fromPlutusData (List [Data
major, Data
minor]) = Version -> Natural -> ProtVer
ProtVer forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
major forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
minor
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData UnitInterval where
  toPlutusData :: UnitInterval -> Data
toPlutusData UnitInterval
x = [Data] -> Data
List [Integer -> Data
I Integer
num, Integer -> Data
I Integer
denom]
    where
      (Integer
num :% Integer
denom) = forall r. BoundedRational r => r -> Ratio Integer
unboundRational UnitInterval
x
  fromPlutusData :: Data -> Maybe UnitInterval
fromPlutusData (List [I Integer
num, I Integer
denom]) = forall r. BoundedRational r => Ratio Integer -> Maybe r
boundRational (Integer
num forall a. Integral a => a -> a -> Ratio a
% Integer
denom)
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData NonNegativeInterval where
  toPlutusData :: NonNegativeInterval -> Data
toPlutusData NonNegativeInterval
x = [Data] -> Data
List [Integer -> Data
I Integer
num, Integer -> Data
I Integer
denom]
    where
      (Integer
num :% Integer
denom) = forall r. BoundedRational r => r -> Ratio Integer
unboundRational NonNegativeInterval
x
  fromPlutusData :: Data -> Maybe NonNegativeInterval
fromPlutusData (List [I Integer
num, I Integer
denom]) = forall r. BoundedRational r => Ratio Integer -> Maybe r
boundRational (Integer
num forall a. Integral a => a -> a -> Ratio a
% Integer
denom)
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData CostModels where
  toPlutusData :: CostModels -> Data
toPlutusData CostModels
costModels = forall x. ToPlutusData x => x -> Data
toPlutusData forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Integral a => a -> Integer
toInteger forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CostModels -> Map Word8 [Int64]
flattenCostModels CostModels
costModels
  fromPlutusData :: Data -> Maybe CostModels
fromPlutusData Data
costModelsData = do
    Map Word8 [Integer]
costModels :: Map.Map Word8 [Integer] <- forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
costModelsData
    forall (m :: * -> *).
MonadFail m =>
Map Word8 [Int64] -> m CostModels
mkCostModelsLenient (forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (forall a b. (a -> b) -> [a] -> [b]
map forall a. Num a => Integer -> a
fromInteger) Map Word8 [Integer]
costModels)

instance ToPlutusData ExUnits where
  toPlutusData :: ExUnits -> Data
toPlutusData (ExUnits Natural
a Natural
b) = [Data] -> Data
List [forall x. ToPlutusData x => x -> Data
toPlutusData Natural
a, forall x. ToPlutusData x => x -> Data
toPlutusData Natural
b]
  fromPlutusData :: Data -> Maybe ExUnits
fromPlutusData (List [Data
x, Data
y]) = Natural -> Natural -> ExUnits
ExUnits forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
x forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
y
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData Prices where
  toPlutusData :: Prices -> Data
toPlutusData Prices
p = [Data] -> Data
List [forall x. ToPlutusData x => x -> Data
toPlutusData (Prices -> NonNegativeInterval
prMem Prices
p), forall x. ToPlutusData x => x -> Data
toPlutusData (Prices -> NonNegativeInterval
prSteps Prices
p)]
  fromPlutusData :: Data -> Maybe Prices
fromPlutusData (List [Data
x, Data
y]) = NonNegativeInterval -> NonNegativeInterval -> Prices
Prices forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
x forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall x. ToPlutusData x => Data -> Maybe x
fromPlutusData Data
y
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

deriving instance ToPlutusData Coin

instance ToPlutusData Word32 where
  toPlutusData :: Word32 -> Data
toPlutusData Word32
w32 = Integer -> Data
I (forall a. Integral a => a -> Integer
toInteger @Word32 Word32
w32)
  fromPlutusData :: Data -> Maybe Word32
fromPlutusData (I Integer
n)
    | Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound @Word32) =
        forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger @Word32 Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData Word16 where
  toPlutusData :: Word16 -> Data
toPlutusData Word16
w16 = Integer -> Data
I (forall a. Integral a => a -> Integer
toInteger @Word16 Word16
w16)
  fromPlutusData :: Data -> Maybe Word16
fromPlutusData (I Integer
n) | Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound @Word16) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger @Word16 Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData Word8 where
  toPlutusData :: Word8 -> Data
toPlutusData Word8
w8 = Integer -> Data
I (forall a. Integral a => a -> Integer
toInteger @Word8 Word8
w8)
  fromPlutusData :: Data -> Maybe Word8
fromPlutusData (I Integer
n) | Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound @Word8) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger @Word8 Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

deriving instance ToPlutusData EpochInterval

instance ToPlutusData Natural where
  toPlutusData :: Natural -> Data
toPlutusData Natural
nat = Integer -> Data
I (forall a. Integral a => a -> Integer
toInteger @Natural Natural
nat)
  fromPlutusData :: Data -> Maybe Natural
fromPlutusData (I Integer
n) | Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger @Natural Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData Integer where
  toPlutusData :: Integer -> Data
toPlutusData Integer
n = Integer -> Data
I Integer
n
  fromPlutusData :: Data -> Maybe Integer
fromPlutusData (I Integer
n) = forall a. a -> Maybe a
Just Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing

instance ToPlutusData Word where
  toPlutusData :: Word -> Data
toPlutusData Word
w = Integer -> Data
I (forall a. Integral a => a -> Integer
toInteger @Word Word
w)
  fromPlutusData :: Data -> Maybe Word
fromPlutusData (I Integer
n) | Integer
n forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
n forall a. Ord a => a -> a -> Bool
<= forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound @Word) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger @Word Integer
n
  fromPlutusData Data
_ = forall a. Maybe a
Nothing