-- | Module, containing data types for Michelson value. module Michelson.Typed.Value ( Val (..) , ContractInp , ContractOut , CreateAccount (..) , CreateContract (..) , CVal (..) , Operation (..) , SetDelegate (..) , TransferTokens (..) , ToVal , FromVal , toVal , fromVal ) where import qualified Data.Map.Strict as Map import qualified Data.Set as Set import Data.Singletons (SingI) import Michelson.EqParam import Michelson.Typed.CValue (CVal(..), FromCVal, ToCVal, fromCVal, toCVal) import Michelson.Typed.T (T(..), ToT) import Tezos.Address (Address) import Tezos.Core (Mutez, Timestamp) import Tezos.Crypto (KeyHash, PublicKey, Signature) -- | Data type, representing operation, list of which is returned -- by Michelson contract (according to calling convention). -- -- These operations are to be further executed against system state -- after the contract execution. data Operation instr where OpTransferTokens :: Typeable p => TransferTokens instr p -> Operation instr OpSetDelegate :: SetDelegate -> Operation instr OpCreateAccount :: CreateAccount -> Operation instr OpCreateContract :: ( Show (instr (ContractInp cp st) (ContractOut st)), SingI cp, SingI st , Typeable t, Typeable cp, Typeable st) => CreateContract instr t cp st -> Operation instr deriving instance Show (Operation instr) instance Eq (Operation instr) where op1 == op2 = case (op1, op2) of (OpTransferTokens tt1, OpTransferTokens tt2) -> eqParam1 tt1 tt2 (OpTransferTokens _, _) -> False (OpSetDelegate sd1, OpSetDelegate sd2) -> sd1 == sd2 (OpSetDelegate _, _) -> False (OpCreateAccount ca1, OpCreateAccount ca2) -> ca1 == ca2 (OpCreateAccount _, _) -> False (OpCreateContract cc1, OpCreateContract cc2) -> eqParam3 cc1 cc2 (OpCreateContract _, _) -> False data TransferTokens instr p = TransferTokens { ttContractParameter :: !(Val instr p) , ttAmount :: !Mutez , ttContract :: !(Val instr ('TContract p)) } deriving (Show, Eq) data SetDelegate = SetDelegate { sdMbKeyHash :: !(Maybe KeyHash) } deriving (Show, Eq) data CreateAccount = CreateAccount { caManager :: !KeyHash , caDelegate :: !(Maybe KeyHash) , caSpendable :: !Bool , caBalance :: !Mutez } deriving (Show, Eq) data CreateContract instr t cp st = ( Show (instr (ContractInp cp st) (ContractOut st)) , Eq (instr (ContractInp cp st) (ContractOut st)) ) => CreateContract { ccManager :: !KeyHash , ccDelegate :: !(Maybe KeyHash) , ccSpendable :: !Bool , ccDelegatable :: !Bool , ccBalance :: !Mutez , ccStorageVal :: !(Val instr t) , ccContractCode :: !(instr (ContractInp cp st) (ContractOut st)) } deriving instance Show (CreateContract instr t cp st) deriving instance Eq (CreateContract instr t cp st) type ContractInp param st = '[ 'TPair param st ] type ContractOut st = '[ 'TPair ('TList 'TOperation) st ] -- | Representation of Michelson value. -- -- Type parameter @instr@ stands for Michelson instruction -- type, i.e. data type to represent an instruction of language. data Val instr t where VC :: CVal t -> Val instr ('Tc t) VKey :: PublicKey -> Val instr 'TKey VUnit :: Val instr 'TUnit VSignature :: Signature -> Val instr 'TSignature VOption :: Maybe (Val instr t) -> Val instr ('TOption t) VList :: [Val instr t] -> Val instr ('TList t) VSet :: Set (CVal t) -> Val instr ('TSet t) VOp :: Operation instr -> Val instr 'TOperation VContract :: Address -> Val instr ('TContract p) VPair :: (Val instr l, Val instr r) -> Val instr ('TPair l r) VOr :: Either (Val instr l) (Val instr r) -> Val instr ('TOr l r) VLam :: ( Show (instr '[inp] '[out]) , Eq (instr '[inp] '[out]) ) => instr (inp ': '[]) (out ': '[]) -> Val instr ('TLambda inp out) VMap :: Map (CVal k) (Val instr v) -> Val instr ('TMap k v) VBigMap :: Map (CVal k) (Val instr v) -> Val instr ('TBigMap k v) deriving instance Show (Val instr t) deriving instance Eq (Val instr t) -- TODO: actually we should handle big maps with something close -- to following: -- -- VBigMap :: BigMap op ref k v -> Val cp ('TBigMap k v) -- -- data ValueOp v -- = New v -- | Upd v -- | Rem -- | NotExisted -- -- data BigMap op ref k v = BigMap -- { bmRef :: ref k v, bmChanges :: Map (CVal k) (ValueOp (Val cp v)) } -- | Converts a complex Haskell structure into @Val@ representation. class ToVal a where toVal :: a -> Val instr (ToT a) -- | Converts a @Val@ value into complex Haskell type. class FromVal t where fromVal :: Val instr (ToT t) -> t -- ToVal / FromVal instances -- @gromak: we can write the following code instead of these -- instances below, but I am not sure whether it's a good idea. -- Note: if it breaks compilation for you, try to clean and -- rebuild from scratch. It seems to compile fine. -- instance {-# OVERLAPPABLE #-} ('Tc (ToCT t) ~ ToT t, FromCVal t) => FromVal t where -- fromVal (VC cval) = fromCVal cval instance FromVal Integer where fromVal (VC cval) = fromCVal cval instance FromVal Natural where fromVal (VC cval) = fromCVal cval instance FromVal Text where fromVal (VC cval) = fromCVal cval instance FromVal Bool where fromVal (VC cval) = fromCVal cval instance FromVal ByteString where fromVal (VC cval) = fromCVal cval instance FromVal Mutez where fromVal (VC cval) = fromCVal cval instance FromVal KeyHash where fromVal (VC cval) = fromCVal cval instance FromVal Timestamp where fromVal (VC cval) = fromCVal cval instance FromVal Address where fromVal (VC cval) = fromCVal cval instance FromVal () where fromVal VUnit = () instance FromVal a => FromVal [a] where fromVal (VList lVals) = map fromVal lVals instance FromVal a => FromVal (Maybe a) where fromVal (VOption Nothing) = Nothing fromVal (VOption (Just val)) = Just $ fromVal val instance (FromVal a, FromVal b) => FromVal (Either a b) where fromVal (VOr (Left l)) = Left $ fromVal l fromVal (VOr (Right r)) = Right $ fromVal r instance (FromVal a, FromVal b) => FromVal (a, b) where fromVal (VPair (a, b)) = (fromVal a, fromVal b) instance (Ord k, FromCVal k) => FromVal (Set k) where fromVal (VSet s) = Set.map fromCVal s instance (Ord k, FromCVal k, FromVal a) => FromVal (Map k a) where fromVal (VMap m) = Map.map fromVal $ Map.mapKeys fromCVal m instance ToVal () where toVal _ = VUnit instance ToVal Integer where toVal = VC . toCVal instance ToVal Int where toVal = VC . toCVal instance ToVal Word64 where toVal = VC . toCVal instance ToVal Natural where toVal = VC . toCVal instance ToVal Text where toVal = VC . toCVal instance ToVal ByteString where toVal = VC . toCVal instance ToVal Bool where toVal = VC . toCVal instance ToVal Mutez where toVal = VC . toCVal instance ToVal KeyHash where toVal = VC . toCVal instance ToVal Timestamp where toVal = VC . toCVal instance ToVal Address where toVal = VC . toCVal instance ToVal a => ToVal (Maybe a) where toVal Nothing = VOption Nothing toVal (Just a) = VOption (Just $ toVal a) instance (ToVal a, ToVal b) => ToVal (Either a b) where toVal (Left l) = VOr $ Left $ toVal l toVal (Right r) = VOr $ Right $ toVal r instance (ToVal a, ToVal b) => ToVal (a, b) where toVal (l, r) = VPair (toVal l, toVal r) instance ToVal x => ToVal [x] where toVal = VList . map toVal instance ToCVal k => ToVal (Set k) where toVal = VSet . Set.map toCVal -- Note: the instance produces Map not BigMap instance (ToCVal k, ToVal a) => ToVal (Map k a) where toVal = VMap . Map.mapKeys toCVal . Map.map toVal