morley-1.20.0: Developer tools for the Michelson Language
Safe HaskellSafe-Inferred
LanguageHaskell2010

Morley.AsRPC

Description

This module contains a type family for converting a type to its RPC representation, and TemplateHaskell functions for deriving RPC representations for custom types.

Synopsis

Documentation

type family TAsRPC t where ... Source #

A type-level function that maps a Michelson type to its Tezos RPC representation.

For example, when we retrieve a contract's storage using the Tezos RPC, all its big_maps will be replaced by nat, representing a big_map ID.

>>> :k! TAsRPC ('TBigMap 'TInt 'TString)
...
= 'TNat
>>> :k! TAsRPC ('TList ('TBigMap 'TInt 'TString))
...
= 'TList 'TNat
>>> :k! TAsRPC ('TPair 'TString ('TPair 'TAddress ('TBigMap 'TInt 'TString)))
...
= 'TPair 'TString ('TPair 'TAddress 'TNat)

NB: As far as we are aware, details of RPC representation of Michelson types are not documented. We know empirically that big_maps are represented as their ids, and are the only type with an explicitly different representation.

Whether TAsRPC needs to propagate into type parameters then depends on whether a value can hold big_map values.

  • Values of type option a, list a, pair a b, and or a b can contain big_map values, so their RPC representations are option (TAsRPC a), list (TAsRPC a), pair (TAsRPC a) (TAsRPC b) and or (TAsRPC a) (TAsRPC b).
  • The keys of a map k v cannot be big_maps, but the values can, so its RPC representation is map k (TAsRPC v).
  • Values of type set a cannot contain big_maps, so its RPC representation is just set a.
  • Values of type contract a cannot contain big_maps either, because it's just a wrapper for an address and an entrypoint name, so its RPC representation is just contract a. The same reasoning applies to ticket a and lambda a b.

class TAsRPC (ToT t) ~ ToT (AsRPC t) => HasRPCRepr (t :: Type) Source #

A type-level function that maps a type to its Tezos RPC representation.

For example, when we retrieve a contract's storage using the Tezos RPC, all its BigMaps will be replaced by BigMapIds.

So if a contract has a storage of type T, when we call the Tezos RPC to retrieve it, we must deserialize the micheline expression to the type AsRPC T.

AsRPC (BigMap Integer MText) ~ BigMapId Integer MText
AsRPC [BigMap Integer MText] ~ [BigMapId Integer MText]
AsRPC (MText, (Address, BigMap Integer MText)) ~ (MText, (Address, BigMapId Integer MText))

The following law must hold:

TAsRPC (ToT t) ~ ToT (AsRPC t)

In other words, ToT and AsRPC/TAsRPC must be commutative.

   Storage ----------(applying ToT)-------------> ToT Storage
      |                                                |
      |                                                |
      |                                                |
(applying AsRPC)                                (applying TAsRPC)
      |                                                |
      |                                                |
      |                                                |
      |                                                V
      |                                        TAsRPC (ToT Storage)
      V                                                ~
AsRPC Storage ------(applying ToT)-----------> ToT (AsRPC Storage)

This law ensures that we can go from some type Storage to AsRPC Storage by composing fromVal . valueAsRPC . toVal.

   Storage ------------(toVal)--------------> Value (ToT Storage)
      |                                                |
      |                                                |
      |                                                |
(fromVal . valueAsRPC . toVal)                    (valueAsRPC)
      |                                                |
      |                                                |
      |                                                |
      |                                                V
      |                                   Value (TAsRPC (ToT Storage))
      V                                                ~
AsRPC Storage <--------(fromVal)--------- Value (ToT (AsRPC Storage))

Associated Types

type AsRPC t :: Type Source #

Instances

Instances details
HasRPCRepr ByteString Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC ByteString Source #

HasRPCRepr MText Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC MText Source #

HasRPCRepr Operation Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Operation Source #

HasRPCRepr EpAddress Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC EpAddress Source #

HasRPCRepr Address Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Address Source #

HasRPCRepr ChainId Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC ChainId Source #

HasRPCRepr Mutez Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Mutez Source #

HasRPCRepr Timestamp Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Timestamp Source #

HasRPCRepr KeyHash Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC KeyHash Source #

HasRPCRepr PublicKey Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC PublicKey Source #

HasRPCRepr Signature Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Signature Source #

HasRPCRepr Bls12381Fr Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Bls12381Fr Source #

HasRPCRepr Bls12381G1 Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Bls12381G1 Source #

HasRPCRepr Bls12381G2 Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Bls12381G2 Source #

HasRPCRepr Chest Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Chest Source #

HasRPCRepr ChestKey Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC ChestKey Source #

HasRPCRepr Integer Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Integer Source #

HasRPCRepr Natural Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Natural Source #

HasRPCRepr () Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC () Source #

HasRPCRepr Bool Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC Bool Source #

HasRPCRepr a => HasRPCRepr (Identity a) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Identity a) Source #

HasRPCRepr (Set a) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Set a) Source #

HasRPCRepr (Value t) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Value t) Source #

HasRPCRepr (ContractRef arg) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (ContractRef arg) Source #

HasRPCRepr a => HasRPCRepr (Maybe a) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Maybe a) Source #

HasRPCRepr a => HasRPCRepr [a] Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC [a] Source #

(HasRPCRepr l, HasRPCRepr r) => HasRPCRepr (Either l r) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Either l r) Source #

HasRPCRepr v => HasRPCRepr (Map k v) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (Map k v) Source #

HasRPCRepr (BigMap k v) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (BigMap k v) Source #

(HasRPCRepr a, HasRPCRepr b) => HasRPCRepr (a, b) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b) Source #

HasRPCRepr a => HasRPCRepr (NamedF Identity a name) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (NamedF Identity a name) Source #

HasRPCRepr a => HasRPCRepr (NamedF Maybe a name) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (NamedF Maybe a name) Source #

Each '[HasRPCRepr] '[a, b, c] => HasRPCRepr (a, b, c) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b, c) Source #

Each '[HasRPCRepr] '[a, b, c, d] => HasRPCRepr (a, b, c, d) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b, c, d) Source #

Each '[HasRPCRepr] '[a, b, c, d, e] => HasRPCRepr (a, b, c, d, e) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b, c, d, e) Source #

Each '[HasRPCRepr] '[a, b, c, d, e, f] => HasRPCRepr (a, b, c, d, e, f) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b, c, d, e, f) Source #

Each '[HasRPCRepr] '[a, b, c, d, e, f, g] => HasRPCRepr (a, b, c, d, e, f, g) Source # 
Instance details

Defined in Morley.AsRPC

Associated Types

type AsRPC (a, b, c, d, e, f, g) Source #

deriveRPCWithOptions :: String -> DeriveRPCOptions -> Q [Dec] Source #

Derive an RPC representation for a type, as well as instances for Generic, IsoValue, HasRPCRepr and optionally HasAnnotation.

>>> :{
data ExampleStorage a b = ExampleStorage
  { esField1 :: Integer
  , esField2 :: [BigMap Integer MText]
  , esField3 :: a
  }
  deriving stock Generic
  deriving anyclass IsoValue
--
deriveRPC "ExampleStorage"
:}

Will generate:

>>> :i ExampleStorageRPC
...
data ExampleStorageRPC a b
  = ExampleStorageRPC {esField1RPC :: !(AsRPC Integer),
                       esField2RPC :: !(AsRPC [BigMap Integer MText]),
                       esField3RPC :: !(AsRPC a)}
...
instance forall a k (b :: k).
         IsoValue (AsRPC a) =>
         IsoValue (ExampleStorageRPC a b)
...
instance forall a k (b :: k). Generic (ExampleStorageRPC a b)
...
>>> :i HasRPCRepr
...
instance forall a k (b :: k).
         HasRPCRepr a =>
         HasRPCRepr (ExampleStorage a b)
...
>>> :i AsRPC
...
type instance forall k a (b :: k). AsRPC (ExampleStorage a b)
  = ExampleStorageRPC a b
...

When droHasAnnotation is True (the default), it will also generate a HasAnnotation (from Lorentz) instance like:

>>> :i HasAnnotation
...
instance forall a k (b :: k).
         With '[HasAnnotation, HasRPCRepr] (ExampleStorage a b) =>
         HasAnnotation (ExampleStorageRPC a b)
...

Note that if the type doesn't contain type variables or only contains phantom type variables, HasRPCRepr constraint is omitted, as it would be redundant.

HasAnnotation and its methods must be in scope.

Void types will generate a type synonym instead, e.g.

>>> :{
data MyVoidType
  deriving stock Generic
  deriving anyclass IsoValue
--
deriveRPC "MyVoidType"
:}

will produce

>>> :i AsRPC
...
type instance AsRPC MyVoidType = MyVoidTypeRPC
...
>>> :i MyVoidTypeRPC
...
type MyVoidTypeRPC = MyVoidType
...

When droRecursive is True, recursively enumerate data, newtype and type declarations, and derive an RPC representation for each type that doesn't yet have one. This will however silently skip over void types that do not have an IsoValue instance, which is usually what you want, but be mindful of this.

You can also pass in a list of types for which you _don't_ want an RPC representation to be derived in droRecursiveSkipTypes. You may need this if you're using non-void types that don't have an IsoValue instance as phantom types somewhere. The algorithm isn't smart enough to figure out those don't need RPC representation and will try to derive it anyway.

>>> :{
data B = B deriving (Generic, IsoValue)
data C = C deriving (Generic, IsoValue)
data D = D deriving (Generic, IsoValue)
data E a = E deriving (Generic, IsoValue)
--
instance HasRPCRepr D where type AsRPC D = ()
--
data A = A B (E C) D deriving (Generic, IsoValue)
deriveRPCWithOptions "A" def{droRecursive=True, droRecursiveSkipTypes=["C"]}
:}

In this example, this will generate an RPC representation for A and B,

>>> :i ARPC
...
data ARPC = ...
...
>>> :i BRPC
...
data BRPC = ...
...

but not for C (because we explicitly said we don't want one) or D (because it already has one).

>>> :i CRPC
...
... Not in scope: ...
...
>>> :i DRPC
...
... Not in scope: ...
...

When using with droRecursive = False, if some types do not have HasRPCRepr, IsoValue or Generic instances, but need to, an error will be raised:

>>> :{
data B = B deriving (Generic, IsoValue)
data A = A B deriving (Generic, IsoValue)
--
deriveRPCWithOptions "A" def{droRecursive = False}
:}
...
... error:
... Type ... must implement 'HasRPCRepr'.
>>> :{
data B = B deriving (Generic, IsoValue)
data A = A B deriving (Generic, IsoValue)
--
deriveRPCWithOptions "B" def{droRecursive = False}
deriveRPCWithOptions "A" def{droRecursive = False}
:}
>>> :i AsRPC
...
type instance AsRPC A = ARPC ...
type instance AsRPC B = BRPC ...
...

This check isn't very smart, so it might miss some corner cases.

data DeriveRPCOptions Source #

Constructors

DeriveRPCOptions 

Fields

  • droRecursive :: Bool

    Recursively enumerate data, newtype and type declarations, and derives an RPC representation for each type that doesn't yet have one. True by default.

  • droRecursiveSkipTypes :: [String]

    List of types for which you _don't_ want an RPC representation to be derived. This is ignored if droRecursive is False.

  • droHasAnnotation :: Bool

    Derive HasAnnotation. The class and its methods must be in scope, otherwise a compilation error is raised. True by default.

  • droStrategy :: GenericStrategy

    Custom Generic deriving strategy. haskellBalanced by default.

Instances

Instances details
Default DeriveRPCOptions Source # 
Instance details

Defined in Morley.AsRPC

Conversions

valueAsRPC :: HasCallStack => Value t -> Value (TAsRPC t) Source #

Replace all big_maps in a value with the respective big_map IDs.

Throws an error if it finds a big_map without an ID.

replaceBigMapIds Source #

Arguments

:: forall t m. Monad m 
=> (forall k v. (SingI k, SingI v) => Natural -> m (Value ('TBigMap k v)))

A function for looking up a bigmap using its ID.

-> Sing t 
-> Value (TAsRPC t) 
-> m (Value t) 

Replaces all bigmap IDs with their corresponding bigmap values. This is the inverse of valueAsRPC.

notesAsRPC :: Notes t -> Notes (TAsRPC t) Source #

Replace all big_map annotations in a value with nat annotations.

Entailments

rpcSingIEvi :: forall t. SingI t => Dict (SingI (TAsRPC t)) Source #

A proof that if a singleton exists for t, then so it does for TAsRPC t.

rpcHasNoOpEvi :: forall (t :: T). (SingI t, ForbidOp t) => Dict (ForbidOp (TAsRPC t)) Source #

A proof that if t does not contain any operations, then neither does TAsRPC t.

rpcHasNoBigMapEvi :: forall (t :: T). (SingI t, ForbidBigMap t) => Dict (ForbidBigMap (TAsRPC t)) Source #

A proof that AsRPC (Value t) does not contain big_maps.

rpcHasNoNestedBigMapsEvi :: forall (t :: T). (SingI t, ForbidNestedBigMaps t) => Dict (ForbidNestedBigMaps (TAsRPC t)) Source #

A proof that AsRPC (Value t) does not contain nested big_maps.

rpcHasNoContractEvi :: forall (t :: T). (SingI t, ForbidContract t) => Dict (ForbidContract (TAsRPC t)) Source #

A proof that if t does not contain any contract values, then neither does TAsRPC t.

rpcStorageScopeEvi :: forall (t :: T). StorageScope t => Dict (StorageScope (TAsRPC t)) Source #

A proof that if t is a valid storage type, then so is TAsRPC t.