packages feed

indigo-0.6.0: src/Indigo/Frontend/Expr.hs

-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

-- | All the basic 'Expr'essions used in Indigo code.
--
-- Note: infix operators acting on structure follow a naming convention:
--
-- 1. the last character identifies the structure type:
--
--      - @:@ for containers ('Map', 'BigMap', 'Set', 'List')
--      - @\@@ for storage operations (@MEM@, @GET@, @UPDATE@)
--      - @!@ for 'HasField'
--      - @~@ fot 'Util.Named'
--
-- 2. the preceding characters identify the action:
--
--      - @#@ for get, lookup or from
--      - @!@ for set, update or to
--      - @+@ for insert
--      - @++@ for insertNew
--      - @-@ for remove
--      - @?@ for mem or elem
--
-- The only exception to this convention is '(.:)' (for 'cons')

module Indigo.Frontend.Expr
  ( -- * Basic
    constExpr, varExpr, cast

  -- * Math
  , add, sub, mul, div, mod, neg, abs, even, odd
  , (+), (-), (*), (/), (%)

  -- * Comparison
  , eq, neq, lt, gt, le, ge
  , (==), (/=), (<), (>), (<=), (>=)

  -- * Conversion
  , isNat, toInt, nonZero, coerce, forcedCoerce

  -- * Bits and boolean
  , lsl, lsr, and, or, xor, not
  , (<<<), (>>>), (&&), (||), (^)

  -- * Serialization
  , pack, unpack
  , packRaw, unpackRaw

  -- * Pairs
  , pair, car, cdr, fst, snd

  -- * Maybe
  , some, none

  -- * Either
  , right, left

  -- * Bytes and string
  , slice, concat, (<>)

  -- * List
  , concatAll, nil, cons, (.:)

  -- * Containers
  , get, update, insert, remove, mem, size
  , (#:), (!:), (+:), (-:), (?:)
  , empty, emptyBigMap, emptyMap, emptySet

  -- * Storages
  , stGet, stUpdate, stInsert, stInsertNew, stDelete, stMem
  , (#@), (!@), (+@), (++@), (-@), (?@)

  -- * Sum types
  , wrap, unwrap

  -- * HasField
  , (!!), (#!)

  -- * Record and Named
  , name, unName, (!~), (#~)
  , construct, constructRec

  -- * Contract
  , contract
  , self
  , selfAddress
  , contractAddress
  , contractCallingUnsafe
  , contractCallingString
  , runFutureContract
  , implicitAccount
  , convertEpAddressToContract
  , makeView
  , makeVoid

  -- * Auxiliary
  , now
  , amount
  , sender
  , blake2b
  , sha256
  , sha512
  , sha3
  , keccak
  , hashKey
  , chainId
  , balance
  , level
  , votingPower
  , totalVotingPower
  , checkSignature
  ) where

import Data.Vinyl.Core (RMap(..), RecordToList(..))
import Fmt (Buildable)

import Indigo.Backend.Prelude (fromInteger)
import Indigo.Common.Expr
import Indigo.Common.Field
import Indigo.Common.Var (Var)
import Indigo.Lorentz hiding (forcedCoerce)
import Indigo.Prelude
import Morley.Michelson.Text (unMText)
import Morley.Michelson.Typed.Arith qualified as M
import Morley.Michelson.Typed.Haskell.Instr.Sum (CtorOnlyField, InstrUnwrapC, InstrWrapOneC)
import Morley.Michelson.Untyped.Entrypoints (buildEpName)
import Morley.Util.TypeTuple

----------------------------------------------------------------------------
-- Basic
----------------------------------------------------------------------------

constExpr :: forall a . NiceConstant a => a -> Expr a
constExpr a = C a

-- | Create an expression holding a variable.
varExpr :: KnownValue a => Var a -> Expr a
varExpr = V

cast :: (ex :~> a) => ex -> Expr a
cast = Cast . toExpr

----------------------------------------------------------------------------
-- Math
----------------------------------------------------------------------------

infixl 6 +
add, (+)
  :: IsArithExpr exN exM M.Add n m r
  => exN -> exM
  -> Expr r
add n m = Add (toExpr n) (toExpr m)
(+) = add

infixl 6 -
sub, (-)
  :: IsArithExpr exN exM M.Sub n m r
  => exN -> exM
  -> Expr r
sub n m = Sub (toExpr n) (toExpr m)
(-) = sub

infixl 7 *
mul, (*)
  :: IsArithExpr exN exM M.Mul n m r
  => exN -> exM
  -> Expr r
mul n m = Mul (toExpr n) (toExpr m)
(*) = mul

infixl 7 /
div, (/)
  :: forall reminder exN exM n m ratio. IsDivExpr exN exM n m ratio reminder
  => exN -> exM
  -> Expr ratio
div n m = Div (toExpr n) (toExpr m) (Proxy :: Proxy reminder)
(/) = div @reminder

infixl 7 %
mod, (%)
  :: forall ratio exN exM n m reminder. IsModExpr exN exM n m ratio reminder
  => exN -> exM
  -> Expr reminder
mod n m = Mod (toExpr n) (toExpr m) (Proxy :: Proxy ratio)
(%) = mod @ratio

abs
  :: IsUnaryArithExpr exN M.Abs n
  => exN
  -> Expr (UnaryArithResHs M.Abs n)
abs = Abs . toExpr

neg
  :: IsUnaryArithExpr exN M.Neg n
  => exN
  -> Expr (UnaryArithResHs M.Neg n)
neg = Neg . toExpr

class ParityExpr n m where
  even :: (ArithOpHs M.EDiv n m r, exN :~> n) => exN -> Expr Bool
  odd  :: (ArithOpHs M.EDiv n m r, exN :~> n) => exN -> Expr Bool

instance ParityExpr Integer Integer where
  even = eq (0 :: Natural) . (`mod` (2 :: Natural))
  odd = neq (0 :: Natural) . (`mod` (2 :: Natural))

instance ParityExpr Natural Natural where
  even = eq (0 :: Natural) . (`mod` (2 :: Natural))
  odd = neq (0 :: Natural) . (`mod` (2 :: Natural))

instance ParityExpr Mutez Mutez where
  even = eq zeroMutez . (`mod` [tz|2u|])
  odd = neq zeroMutez . (`mod` [tz|2u|])

----------------------------------------------------------------------------
-- Comparison
----------------------------------------------------------------------------

infix 4 ==
eq, (==)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
eq a b = Eq' (toExpr a) (toExpr b)
(==) = eq

infix 4 /=
neq, (/=)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
neq a b = Neq (toExpr a) (toExpr b)
(/=) = neq

infix 4 <
lt, (<)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
lt a b = Lt (toExpr a) (toExpr b)
(<) = lt

infix 4 >
gt, (>)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
gt a b = Gt (toExpr a) (toExpr b)
(>) = gt

infix 4 <=
le, (<=)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
le a b = Le (toExpr a) (toExpr b)
(<=) = le

infix 4 >=
ge, (>=)
  :: (NiceComparable n, c :~> n, c1 :~> n)
  => c -> c1
  -> Expr Bool
ge a b = Ge (toExpr a) (toExpr b)
(>=) = ge

----------------------------------------------------------------------------
-- Conversion
----------------------------------------------------------------------------

isNat :: (ex :~> Integer) => ex -> Expr (Maybe Natural)
isNat = IsNat . toExpr

toInt :: (ex :~> Natural) => ex -> Expr Integer
toInt = Int' . toExpr

nonZero :: (ex :~> n, NonZero n, KnownValue (Maybe n)) => ex -> Expr (Maybe n)
nonZero = NonZero . toExpr

-- | Convert between types that have the same Michelson representation and an
-- explicit permission for that in the face of 'CanCastTo' constraint.
coerce :: forall b a ex. (Castable_ a b, KnownValue b, ex :~> a) => ex -> Expr b
coerce = Coerce . toExpr

-- | Convert between expressions of types that have the same Michelson
-- representation.
forcedCoerce
  :: forall b a ex. (MichelsonCoercible a b, KnownValue b, ex :~> a)
  => ex -> Expr b
forcedCoerce = ForcedCoerce . toExpr

----------------------------------------------------------------------------
-- Bits and boolean
----------------------------------------------------------------------------

infixl 8 <<<
lsl, (<<<)
  :: IsArithExpr exN exM M.Lsl n m r
  => exN -> exM
  -> Expr r
lsl a b = Lsl (toExpr a) (toExpr b)
(<<<) = lsl

infixl 8 >>>
lsr, (>>>)
  :: IsArithExpr exN exM M.Lsr n m r
  => exN -> exM
  -> Expr r
lsr a b = Lsr (toExpr a) (toExpr b)
(>>>) = lsr

infixr 2 ||
or, (||)
  :: IsArithExpr exN exM M.Or n m r
  => exN -> exM
  -> Expr r
or a b = Or (toExpr a) (toExpr b)
(||) = or

infixr 3 &&
and, (&&)
  :: IsArithExpr exN exM M.And n m r
  => exN -> exM
  -> Expr r
and a b = And (toExpr a) (toExpr b)
(&&) = and

infixr 2 ^
xor, (^)
  :: IsArithExpr exN exM M.Xor n m r
  => exN -> exM
  -> Expr r
xor a b = Xor (toExpr a) (toExpr b)
(^) = xor

not
  :: IsUnaryArithExpr exN M.Not n
  => exN
  -> Expr (UnaryArithResHs M.Not n)
not = Not . toExpr

----------------------------------------------------------------------------
-- Serialization
----------------------------------------------------------------------------

pack :: (ex :~> a, NicePackedValue a) => ex -> Expr (Packed a)
pack = Pack . toExpr

unpack :: (NiceUnpackedValue a, exb :~> Packed a) => exb -> Expr (Maybe a)
unpack = Unpack . toExpr

packRaw :: (ex :~> a, NicePackedValue a) => ex -> Expr ByteString
packRaw = PackRaw . toExpr

unpackRaw :: (NiceUnpackedValue a, exb :~> ByteString) => exb -> Expr (Maybe a)
unpackRaw = UnpackRaw . toExpr

----------------------------------------------------------------------------
-- Pairs
----------------------------------------------------------------------------

pair :: (ex1 :~> n, ex2 :~> m, KnownValue (n, m)) => ex1 -> ex2 -> Expr (n, m)
pair a b = Pair (toExpr a) (toExpr b)

car, fst :: (op :~> (n, m), KnownValue n) => op -> Expr n
car = fst
fst = Fst . toExpr

cdr, snd :: (op :~> (n, m), KnownValue m) => op -> Expr m
cdr = snd
snd = Snd . toExpr

----------------------------------------------------------------------------
-- Maybe
----------------------------------------------------------------------------

some :: (ex :~> t, KnownValue (Maybe t)) => ex -> Expr (Maybe t)
some = Some . toExpr

none :: KnownValue t => Expr (Maybe t)
none = None

----------------------------------------------------------------------------
-- Either
----------------------------------------------------------------------------

right :: (ex :~> x, KnownValue y, KnownValue (Either y x)) => ex -> Expr (Either y x)
right = Right' . toExpr

left :: (ex :~> y, KnownValue x, KnownValue (Either y x)) => ex -> Expr (Either y x)
left = Left' . toExpr

----------------------------------------------------------------------------
-- Bytes and string
----------------------------------------------------------------------------

slice
  :: ( an :~> Natural
     , bn :~> Natural
     , IsSliceExpr ex c
     )
  => (an, bn) -> ex
  -> Expr (Maybe c)
slice (a, b) ex = Slice (toExpr a) (toExpr b) (toExpr ex)

infixr 6 <>
concat, (<>)
  :: IsConcatExpr exN1 exN2 n
  => exN1 -> exN2
  -> Expr n
concat a b = Concat (toExpr a) (toExpr b)
(<>) = concat

----------------------------------------------------------------------------
-- List
----------------------------------------------------------------------------

infixr 5 .:
cons, (.:) :: (ex1 :~> a, ex2 :~> List a) => ex1 -> ex2 -> Expr (List a)
cons el lst = Cons (toExpr el) (toExpr lst)
(.:) = cons

concatAll :: IsConcatListExpr exN n => exN -> Expr n
concatAll = Concat' . toExpr

nil :: KnownValue a => Expr (List a)
nil = Nil

----------------------------------------------------------------------------
-- Containers
----------------------------------------------------------------------------

class ExprMagma c where
  empty :: (NiceComparable (UpdOpKeyHs c), KnownValue c) => Expr c

instance KnownValue v => ExprMagma (BigMap k v) where
  empty = EmptyBigMap

instance KnownValue v => ExprMagma (Map k v) where
  empty = EmptyMap

instance ExprMagma (Set k) where
  empty = EmptySet

-- | Expression class to insert an element into a data structure.
--
-- Note that while this is based on 'update' and 'UpdOpHs', it is necessary to
-- have different instances to allow for different 'update' parameter types,
-- ('Set' uses a 'Bool' instead of a 'Maybe'), just like 'ExprRemovable'.
--
-- Moreover, this class is parameterized with an @insParam@ as well in order to
-- have both key-value pairs ('Map' and 'BigMap') as well as key only ('Set').
class UpdOpHs c => ExprInsertable c insParam where
  insert :: ex :~> c => insParam -> ex -> Expr c

instance (NiceComparable k, exKey :~> k, exValue :~> v)
    => ExprInsertable (BigMap k v) (exKey, exValue) where
  insert (k, v) c = update (k, some v) c

instance (NiceComparable k, exKey :~> k, exValue :~> v)
    => ExprInsertable (Map k v) (exKey, exValue) where
  insert (k, v) c = update (k, some v) c

instance (NiceComparable a, exKey :~> a) => ExprInsertable (Set a) exKey where
  insert k c = update (k, True) c

-- | Expression class to remove an element from a data structure.
--
-- Note that while this is based on 'update' and 'UpdOpHs', it is necessary to
-- have different instances to allow for different 'update' parameter types,
-- ('Set' uses a 'Bool' instead of a 'Maybe').
class UpdOpHs c => ExprRemovable c where
  remove
    :: (exStruct :~> c, exKey :~> UpdOpKeyHs c)
    => exKey -> exStruct -> Expr c

instance (NiceComparable k, KnownValue v) => ExprRemovable (BigMap k v) where
  remove k c = update (k, none) c

instance (NiceComparable k, KnownValue v) => ExprRemovable (Map k v) where
  remove k c = update (k, none) c

instance NiceComparable a => ExprRemovable (Set a) where
  remove k c = update (k, False) c

get
  :: IsGetExpr exKey exMap map
  => exKey -> exMap
  -> Expr (Maybe (GetOpValHs map))
get k m = Get (toExpr k) (toExpr m)

update
  :: IsUpdExpr exKey exVal exMap map
  => (exKey, exVal) -> exMap
  -> Expr map
update (k, v) s = Update (toExpr s) (toExpr k) (toExpr v)

mem
  :: IsMemExpr exKey exN n
  => exKey -> exN
  -> Expr Bool
mem key n = Mem (toExpr key) (toExpr n)

size
  :: IsSizeExpr exN n
  => exN -> Expr Natural
size = Size . toExpr

infixl 8 #:
(#:)
  :: IsGetExpr exKey exMap map
  => exMap -> exKey
  -> Expr (Maybe (GetOpValHs map))
(#:) = flip get

infixl 8 !:
(!:)
  :: IsUpdExpr exKey exVal exMap map
  => exMap -> (exKey, exVal)
  -> Expr map
(!:) = flip update

infixl 8 +:
(+:)
  :: ( ExprInsertable c exParam
     , exStructure :~> c
     )
     => exStructure -> exParam
     -> Expr c
(+:) = flip insert

infixl 8 -:
(-:)
  :: ( ExprRemovable c
     , exStruct :~> c
     , exKey :~> UpdOpKeyHs c
     )
  => exStruct -> exKey
  -> Expr c
(-:) = flip remove

infixl 8 ?:
(?:)
  :: IsMemExpr exKey exN n
  => exN -> exKey
  -> Expr Bool
(?:) = flip mem

emptyBigMap
  :: (KnownValue value, NiceComparable key, KnownValue (BigMap key value))
  => Expr (BigMap key value)
emptyBigMap = empty

emptyMap
  :: (KnownValue value, NiceComparable key, KnownValue (Map key value))
  => Expr (Map key value)
emptyMap = empty

emptySet
  :: (NiceComparable key, KnownValue (Set key))
  => Expr (Set key)
emptySet = empty

----------------------------------------------------------------------------
-- Storages
----------------------------------------------------------------------------

infixr 8 #@
stGet, (#@)
  :: ( StoreHasSubmap store name key value
     , KnownValue value
     , exKey   :~> key
     , exStore :~> store
     )
  => exStore -> (Label name, exKey)
  -> Expr (Maybe value)
stGet store (uName, key) = StGet uName (toExpr key) (toExpr store)
(#@) = stGet

infixl 8 !@
stUpdate, (!@)
  :: ( StoreHasSubmap store name key value
     , exKey   :~> key
     , exVal   :~> Maybe value
     , exStore :~> store
     )
  => exStore -> (Label name, exKey, exVal)
  -> Expr store
stUpdate store (uName, key, val) =
  StUpdate uName (toExpr key) (toExpr val) (toExpr store)
(!@) = stUpdate

infixr 8 +@
stInsert, (+@)
  :: ( StoreHasSubmap store name key value
     , exKey   :~> key
     , exVal   :~> value
     , exStore :~> store
     )
  => exStore -> (Label name, exKey, exVal)
  -> Expr store
stInsert store (uName, key, val) =
  StInsert uName (toExpr key) (toExpr val) (toExpr store)
(+@) = stInsert

infixr 8 ++@
stInsertNew, (++@)
  :: ( StoreHasSubmap store name key value
     , Dupable key
     , IsError err
     , Buildable err
     , exKey   :~> key
     , exVal   :~> value
     , exStore :~> store
     )
  => exStore
  -> (Label name, err, exKey, exVal)
  -> Expr store
stInsertNew store (uName, err, key, val) =
  StInsertNew uName err (toExpr key) (toExpr val) (toExpr store)
(++@) = stInsertNew

infixl 8 -@
stDelete, (-@)
  :: ( StoreHasSubmap store name key value
     , KnownValue value
     , exKey   :~> key
     , exStore :~> store
     )
  => exStore -> (Label name, exKey)
  -> Expr store
stDelete store (uName, key) = StDelete uName (toExpr key) (toExpr store)
(-@) = stDelete

infixl 8 ?@
stMem, (?@)
  :: ( StoreHasSubmap store name key value
     , KnownValue value
     , exKey   :~> key
     , exStore :~> store
     )
  => exStore -> (Label name, exKey)
  -> Expr Bool
stMem store (uName, key) = StMem uName (toExpr key) (toExpr store)
(?@) = stMem

----------------------------------------------------------------------------
-- Sum types
----------------------------------------------------------------------------

wrap
  :: ( InstrWrapOneC dt name
     , exField :~> CtorOnlyField name dt
     , KnownValue dt
     )
  => Label name
  -> exField
  -> Expr dt
wrap l = Wrap l . toExpr

unwrap
  :: ( InstrUnwrapC dt name
     , exDt :~> dt
     , KnownValue (CtorOnlyField name dt)
     )
  => Label name
  -> exDt
  -> Expr (CtorOnlyField name dt)
unwrap l = Unwrap l . toExpr

----------------------------------------------------------------------------
-- HasField
----------------------------------------------------------------------------

infixl 8 #!
(#!)
  :: (HasField dt name ftype, exDt :~> dt)
  => exDt
  -> Label name
  -> Expr ftype
(#!) (toExpr -> (ObjMan fa)) fName = ObjMan (ToField fa fName)
(#!) exDt fName = ObjMan (ToField (Object $ toExpr exDt) fName)

infixl 8 !!
(!!)
  :: ( HasField dt name ftype
     , exDt :~> dt
     , exFld :~> ftype
     )
  => exDt
  -> (Label name, exFld)
  -> Expr dt
(!!) (toExpr -> (ObjMan fa)) (fName, eFld) = ObjMan (SetField fa fName (toExpr eFld))
dt !! (fName, eFld) = ObjMan (SetField (Object $ toExpr dt) fName (toExpr eFld))

----------------------------------------------------------------------------
-- Record and Named
----------------------------------------------------------------------------

name :: (ex :~> t, KnownValue (name :! t)) => Label name -> ex -> Expr (name :! t)
name lName = Name lName . toExpr

unName :: (ex :~> (name :! t), KnownValue t) => Label name -> ex -> Expr t
unName lName = UnName lName . toExpr

infixl 8 !~
(!~)
  :: (ex :~> t, KnownValue (name :! t))
  => ex -> Label name
  -> Expr (name :! t)
(!~) = flip name

infixl 8 #~
(#~)
  :: (ex :~> (name :! t), KnownValue t)
  => ex -> Label name
  -> Expr t
(#~) = flip unName

-- TODO: we should try to make this have a set of 'IsExpr' as input instead of 'Expr'
construct
  :: ( InstrConstructC dt, KnownValue dt
     , RMap (ConstructorFieldTypes dt)
     , RecordToList (ConstructorFieldTypes dt)
     , fields ~ Rec Expr (ConstructorFieldTypes dt)
     , RecFromTuple fields
     )
  => IsoRecTuple fields -> Expr dt
construct = Construct Proxy. recFromTuple

constructRec
  :: ( InstrConstructC dt
     , RMap (ConstructorFieldTypes dt)
     , RecordToList (ConstructorFieldTypes dt)
     , KnownValue dt
     )
  => Rec Expr (ConstructorFieldTypes dt)
  -> Expr dt
constructRec = Construct Proxy

----------------------------------------------------------------------------
-- Contract
----------------------------------------------------------------------------

contract
  :: forall p vd addr exAddr.
     ( NiceParameterFull p
     , NoExplicitDefaultEntrypoint p
     , IsoValue (ContractRef p)
     , ToTAddress p vd addr
     , ToT addr ~ ToT Address
     , exAddr :~> addr
     )
  => exAddr -> Expr (Maybe (ContractRef p))
contract = Contract (Proxy @vd) . toExpr

self
  :: ( NiceParameterFull p
     , NoExplicitDefaultEntrypoint p
     , IsoValue (ContractRef p)
     , IsNotInView
     )
  => Expr (ContractRef p)
self = Self

selfAddress :: Expr Address
selfAddress = SelfAddress

contractAddress :: (exc :~> ContractRef p) => exc -> Expr Address
contractAddress = ContractAddress . toExpr

contractCallingUnsafe
  :: ( NiceParameter arg
     , IsoValue (ContractRef arg)
     , exAddr :~> Address
     )
  => EpName -> exAddr -> Expr (Maybe (ContractRef arg))
contractCallingUnsafe epName = ContractCallingUnsafe epName . toExpr

contractCallingString
  :: ( NiceParameter arg
     , IsoValue (ContractRef arg)
     , exAddr :~> Address
     )
  => MText -> exAddr -> Expr (Maybe (ContractRef arg))
contractCallingString =
    contractCallingUnsafe
  . unsafe . buildEpName
  . unMText

runFutureContract
  :: ( NiceParameter p
     , IsoValue (ContractRef p)
     , conExpr :~> FutureContract p
     )
  => conExpr -> Expr (Maybe (ContractRef p))
runFutureContract = RunFutureContract . toExpr

implicitAccount
  :: (exkh :~> KeyHash)
  => exkh
  -> Expr (ContractRef ())
implicitAccount = ImplicitAccount . toExpr

convertEpAddressToContract
  :: ( NiceParameter p
     , IsoValue (ContractRef p)
     , epExpr :~> EpAddress
     )
  => epExpr -> Expr (Maybe (ContractRef p))
convertEpAddressToContract = ConvertEpAddressToContract . toExpr

makeView
  :: ( KnownValue (View_ a r)
     , exa :~> a
     , exCRef :~> ContractRef r
     )
  => exa -> exCRef -> Expr (View_ a r)
makeView a cRef = MakeView (toExpr a) (toExpr cRef)

makeVoid
  :: ( KnownValue (Void_ a b)
     , exa :~> a
     , exCRef :~> Lambda b b
     )
  => exa -> exCRef -> Expr (Void_ a b)
makeVoid a cRef = MakeVoid (toExpr a) (toExpr cRef)

----------------------------------------------------------------------------
-- Auxiliary
----------------------------------------------------------------------------

now :: Expr Timestamp
now = Now

amount :: Expr Mutez
amount = Amount

sender :: Expr Address
sender = Sender

checkSignature
  :: ( pkExpr :~> PublicKey
     , sigExpr :~> TSignature bs
     , hashExpr :~> bs
     , BytesLike bs
     )
  => pkExpr -> sigExpr -> hashExpr
  -> Expr Bool
checkSignature pk sig hash = CheckSignature (toExpr pk) (toExpr sig) (toExpr hash)

sha256 :: (hashExpr :~> bs, BytesLike bs) => hashExpr -> Expr (Hash Sha256 bs)
sha256 = Sha256 . toExpr

sha512 :: (hashExpr :~> bs, BytesLike bs) => hashExpr -> Expr (Hash Sha512 bs)
sha512 = Sha512 . toExpr

blake2b :: (hashExpr :~> bs, BytesLike bs) => hashExpr -> Expr (Hash Blake2b bs)
blake2b = Blake2b . toExpr

sha3 :: (hashExpr :~> bs, BytesLike bs) => hashExpr -> Expr (Hash Sha3 bs)
sha3 = Sha3 . toExpr

keccak :: (hashExpr :~> bs, BytesLike bs) => hashExpr -> Expr (Hash Keccak bs)
keccak = Keccak . toExpr

hashKey :: (keyExpr :~> PublicKey) => keyExpr -> Expr KeyHash
hashKey = HashKey . toExpr

chainId :: Expr ChainId
chainId = ChainId

balance :: Expr Mutez
balance = Balance

level :: Expr Natural
level = Level

votingPower :: (keyExpr :~> KeyHash) => keyExpr -> Expr Natural
votingPower = VotingPower . toExpr

totalVotingPower :: Expr Natural
totalVotingPower = TotalVotingPower