module Lorentz.Instr
( nop
, drop
, dropN
, dup
, swap
, digPeano
, dig
, dug
, push
, some
, none
, unit
, ifNone
, pair
, car
, cdr
, left
, right
, ifLeft
, nil
, cons
, size
, emptySet
, emptyMap
, emptyBigMap
, map
, iter
, mem
, get
, update
, failingWhenPresent
, updateNew
, if_
, ifCons
, loop
, loopLeft
, lambda
, exec
, execute
, apply
, dip
, ConstraintDIPNLorentz
, dipNPeano
, dipN
, failWith
, cast
, pack
, unpack
, concat
, concat'
, slice, isNat, add, sub, rsub, mul, ediv, abs
, neg
, lsl
, lsr
, or
, and
, xor
, not
, compare
, eq0
, neq0
, lt0
, gt0
, le0
, ge0
, int
, toTAddress_
, self
, selfCalling
, contract
, contractCalling
, contractCallingUnsafe
, runFutureContract
, epAddressToContract
, transferTokens
, setDelegate
, createContract
, implicitAccount
, now
, amount
, balance
, checkSignature
, sha256
, sha512
, blake2B
, hashKey
, stepsToQuota
, source
, sender
, address
, chainId
, framed
, LorentzFunctor (..)
, nonZero
) where
import Prelude hiding
(EQ, GT, LT, abs, and, compare, concat, drop, get, map, not, or, some, swap, xor)
import Data.Constraint (Dict(..), (\\))
import qualified Data.Kind as Kind
import Data.Singletons (SingI, sing)
import qualified GHC.TypeNats as GHC (Nat)
import Lorentz.Arith
import Lorentz.Base
import Lorentz.Constraints
import Lorentz.EntryPoints
import Lorentz.Polymorphic
import Lorentz.Run (compileLorentzContract)
import Lorentz.Value
import Lorentz.Zip
import Michelson.Typed
(pattern CAR, pattern CDR, ConstraintDIG, ConstraintDIG', ConstraintDIPN, ConstraintDIPN',
ConstraintDUG, ConstraintDUG', pattern DefEpName, EntryPointCallT(..), Instr(..), RemFail(..),
SomeEntryPointCallT(..), ToTs, Value'(..), sepcName, starNotes)
import Michelson.Typed.Arith
import Michelson.Typed.Haskell.Value
import Util.Peano
import Util.Type
nop :: s :-> s
nop = I Nop
drop :: a & s :-> s
drop = I DROP
dropN ::
forall (n :: GHC.Nat) (s :: [Kind.Type]).
( SingI (ToPeano n), KnownPeano (ToPeano n)
, RequireLongerOrSameLength (ToTs s) (ToPeano n)
, Drop (ToPeano n) (ToTs s) ~ ToTs (Drop (ToPeano n) s)
) => s :-> Drop (ToPeano n) s
dropN = I (DROPN $ sing @(ToPeano n))
where
_example :: '[ Integer, Integer, Integer ] :-> '[]
_example = dropN @3
dup :: a & s :-> a & a & s
dup = I DUP
swap :: a & b & s :-> b & a & s
swap = I SWAP
type ConstraintDIGLorentz (n :: Peano) (inp :: [Kind.Type]) (out :: [Kind.Type])
(a :: Kind.Type) =
( ConstraintDIG n (ToTs inp) (ToTs out) (ToT a)
, ConstraintDIG' Kind.Type n inp out a
)
type ConstraintDUGLorentz (n :: Peano) (inp :: [Kind.Type]) (out :: [Kind.Type])
(a :: Kind.Type) =
( ConstraintDUG n (ToTs inp) (ToTs out) (ToT a)
, ConstraintDUG' Kind.Type n inp out a
)
digPeano ::
forall (n :: Peano) inp out a.
( ConstraintDIGLorentz n inp out a
) => inp :-> out
digPeano = I (DIG $ sing @n)
dig ::
forall (n :: GHC.Nat) inp out a.
( ConstraintDIGLorentz (ToPeano n) inp out a
) => inp :-> out
dig = digPeano @(ToPeano n)
where
_example ::
'[ Integer, Integer, Integer, Bool ] :->
'[ Bool, Integer, Integer, Integer ]
_example = dig @3
dug ::
forall (n :: GHC.Nat) inp out a.
( ConstraintDUGLorentz (ToPeano n) inp out a
) => inp :-> out
dug = I (DUG $ sing @(ToPeano n))
where
_example ::
'[ Bool, Integer, Integer, Integer ] :->
'[ Integer, Integer, Integer, Bool ]
_example = dug @3
push :: forall t s . NiceConstant t => t -> (s :-> t & s)
push a = I $ PUSH (toVal a) \\ niceConstantEvi @t
some :: a & s :-> Maybe a & s
some = I SOME
none :: forall a s . KnownValue a => s :-> (Maybe a & s)
none = I NONE
unit :: s :-> () & s
unit = I UNIT
ifNone
:: (s :-> s') -> (a & s :-> s') -> (Maybe a & s :-> s')
ifNone = iGenericIf IF_NONE
pair :: a & b & s :-> (a, b) & s
pair = I PAIR
car :: (a, b) & s :-> a & s
car = I CAR
cdr :: (a, b) & s :-> b & s
cdr = I CDR
left :: forall a b s. KnownValue b => a & s :-> Either a b & s
left = I LEFT
right :: forall a b s. KnownValue a => b & s :-> Either a b & s
right = I RIGHT
ifLeft
:: (a & s :-> s') -> (b & s :-> s') -> (Either a b & s :-> s')
ifLeft = iGenericIf IF_LEFT
nil :: KnownValue p => s :-> List p & s
nil = I NIL
cons :: a & List a & s :-> List a & s
cons = I CONS
ifCons
:: (a & List a & s :-> s') -> (s :-> s') -> (List a & s :-> s')
ifCons = iGenericIf IF_CONS
size :: SizeOpHs c => c & s :-> Natural & s
size = I SIZE
emptySet :: (KnownCValue e) => s :-> Set e & s
emptySet = I EMPTY_SET
emptyMap :: (KnownCValue k, KnownValue v)
=> s :-> Map k v & s
emptyMap = I EMPTY_MAP
emptyBigMap :: (KnownCValue k, KnownValue v)
=> s :-> BigMap k v & s
emptyBigMap = I EMPTY_BIG_MAP
map
:: (MapOpHs c, IsoMapOpRes c b, HasCallStack)
=> (MapOpInpHs c & s :-> b & s) -> (c & s :-> MapOpResHs c b & s)
map (iNonFailingCode -> action) = I (MAP action)
iter
:: (IterOpHs c, HasCallStack)
=> (IterOpElHs c & s :-> s) -> (c & s :-> s)
iter (iNonFailingCode -> action) = I (ITER action)
mem :: MemOpHs c => MemOpKeyHs c & c & s :-> Bool & s
mem = I MEM
get :: GetOpHs c => GetOpKeyHs c & c & s :-> Maybe (GetOpValHs c) & s
get = I GET
update :: UpdOpHs c => UpdOpKeyHs c & UpdOpParamsHs c & c & s :-> c & s
update = I UPDATE
if_ :: (s :-> s') -> (s :-> s') -> (Bool & s :-> s')
if_ = iGenericIf IF
loop :: (s :-> Bool & s) -> (Bool & s :-> s)
loop (iAnyCode -> b) = I (LOOP b)
loopLeft
:: (a & s :-> Either a b & s) -> (Either a b & s :-> b & s)
loopLeft (iAnyCode -> b) = I (LOOP_LEFT b)
lambda
:: (ZipInstrs [i, o], KnownValue (ZippedStack i), KnownValue (ZippedStack o))
=> (i :-> o) -> (s :-> (i :-> o) & s)
lambda instr = case zippingStack instr of
I l -> I (LAMBDA . VLam $ RfNormal l)
FI l -> I (LAMBDA . VLam $ RfAlwaysFails l)
exec :: a & Lambda a b & s :-> b & s
exec = I EXEC
execute
:: forall i o s.
(Each [KnownList, ZipInstr] [i, o])
=> ((i :-> o) : (i ++ s)) :-> (o ++ s)
execute = framed @s $
dip (zipInstr @i) # swap # I EXEC # unzipInstr @o
where
_example
:: ([Integer, Natural] :-> [(), ()]) : Integer : Natural : s
:-> () : () : s
_example = execute
apply
:: forall a b c s.
(NiceConstant a)
=> a & Lambda (a, b) c & s :-> Lambda b c & s
apply = I $ APPLY \\ niceConstantEvi @a
dip :: forall a s s'. HasCallStack => (s :-> s') -> (a & s :-> a & s')
dip (iNonFailingCode -> a) = I (DIP a)
type ConstraintDIPNLorentz (n :: Peano) (inp :: [Kind.Type]) (out :: [Kind.Type])
(s :: [Kind.Type]) (s' :: [Kind.Type]) =
( ConstraintDIPN n (ToTs inp) (ToTs out) (ToTs s) (ToTs s')
, ConstraintDIPN' Kind.Type n inp out s s'
)
dipNPeano ::
forall (n :: Peano) (inp :: [Kind.Type]) (out :: [Kind.Type]) (s :: [Kind.Type]) (s' :: [Kind.Type]).
( ConstraintDIPNLorentz n inp out s s'
) => s :-> s' -> inp :-> out
dipNPeano (iNonFailingCode -> a) = I (DIPN (sing @n) a)
dipN ::
forall (n :: GHC.Nat) (inp :: [Kind.Type]) (out :: [Kind.Type]) (s :: [Kind.Type]) (s' :: [Kind.Type]).
( ConstraintDIPNLorentz (ToPeano n) inp out s s'
) => s :-> s' -> inp :-> out
dipN = dipNPeano @(ToPeano n)
where
_example :: '[ Integer, Integer, Integer ] :-> '[ Integer, Integer, Integer, () ]
_example = dipN @3 unit
failWith :: (KnownValue a) => a & s :-> t
failWith = FI FAILWITH
cast :: KnownValue a => (a & s :-> a & s)
cast = I CAST
pack
:: forall a s. (NicePackedValue a)
=> a & s :-> ByteString & s
pack = I $ PACK \\ nicePackedValueEvi @a
unpack
:: forall a s. (NiceUnpackedValue a)
=> ByteString & s :-> Maybe a & s
unpack = I $ UNPACK \\ niceUnpackedValueEvi @a
concat :: ConcatOpHs c => c & c & s :-> c & s
concat = I CONCAT
concat' :: ConcatOpHs c => List c & s :-> c & s
concat' = I CONCAT'
slice :: SliceOpHs c => Natural & Natural & c & s :-> Maybe c & s
slice = I SLICE
isNat :: Integer & s :-> Maybe Natural & s
isNat = I ISNAT
add
:: ArithOpHs Add n m
=> n & m & s :-> ArithResHs Add n m & s
add = I ADD
sub
:: ArithOpHs Sub n m
=> n & m & s :-> ArithResHs Sub n m & s
sub = I SUB
rsub
:: ArithOpHs Sub n m
=> m & n & s :-> ArithResHs Sub n m & s
rsub = swap # sub
mul
:: ArithOpHs Mul n m
=> n & m & s :-> ArithResHs Mul n m & s
mul = I MUL
ediv :: EDivOpHs n m
=> n & m & s
:-> Maybe ((EDivOpResHs n m, EModOpResHs n m)) & s
ediv = I EDIV
abs :: UnaryArithOpHs Abs n => n & s :-> UnaryArithResHs Abs n & s
abs = I ABS
neg :: UnaryArithOpHs Neg n => n & s :-> UnaryArithResHs Neg n & s
neg = I NEG
lsl
:: ArithOpHs Lsl n m
=> n & m & s :-> ArithResHs Lsl n m & s
lsl = I LSL
lsr
:: ArithOpHs Lsr n m
=> n & m & s :-> ArithResHs Lsr n m & s
lsr = I LSR
or
:: ArithOpHs Or n m
=> n & m & s :-> ArithResHs Or n m & s
or = I OR
and
:: ArithOpHs And n m
=> n & m & s :-> ArithResHs And n m & s
and = I AND
xor
:: (ArithOpHs Xor n m)
=> n & m & s :-> ArithResHs Xor n m & s
xor = I XOR
not :: UnaryArithOpHs Not n => n & s :-> UnaryArithResHs Not n & s
not = I NOT
compare :: NiceComparable n
=> n & n & s :-> Integer & s
compare = I COMPARE
eq0 :: UnaryArithOpHs Eq' n => n & s :-> UnaryArithResHs Eq' n & s
eq0 = I EQ
neq0 :: UnaryArithOpHs Neq n => n & s :-> UnaryArithResHs Neq n & s
neq0 = I NEQ
lt0 :: UnaryArithOpHs Lt n => n & s :-> UnaryArithResHs Lt n & s
lt0 = I LT
gt0 :: UnaryArithOpHs Gt n => n & s :-> UnaryArithResHs Gt n & s
gt0 = I GT
le0 :: UnaryArithOpHs Le n => n & s :-> UnaryArithResHs Le n & s
le0 = I LE
ge0 :: UnaryArithOpHs Ge n => n & s :-> UnaryArithResHs Ge n & s
ge0 = I GE
int :: Natural & s :-> Integer & s
int = I INT
toTAddress_
:: (ToTAddress_ cp addr)
=> addr : s :-> TAddress cp : s
toTAddress_ = I Nop
type ToTAddress_ cp addr = (ToTAddress cp addr, ToT addr ~ ToT Address)
self
:: forall p s.
(NiceParameterFull p, ForbidExplicitDefaultEntryPoint p)
=> s :-> ContractRef p & s
self = I (SELF $ sepcCallRootChecked @p) \\ niceParameterEvi @p
selfCalling
:: forall p mname s.
(NiceParameterFull p)
=> EntryPointRef mname
-> s :-> ContractRef (GetEntryPointArgCustom p mname) & s
selfCalling epRef = I $
withDict (niceParameterEvi @p) $
case parameterEntryPointCallCustom @p epRef of
epc@EntryPointCall{} -> SELF (SomeEpc epc)
contract
:: forall p addr s.
( NiceParameterFull p, ForbidExplicitDefaultEntryPoint p
, ToTAddress_ p addr
)
=> addr & s :-> Maybe (ContractRef p) & s
contract = I (CONTRACT starNotes epName) \\ niceParameterEvi @p
where
epName = sepcName (sepcCallRootChecked @p)
contractCalling
:: forall cp epRef epArg addr s.
(HasEntryPointArg cp epRef epArg, ToTAddress_ cp addr)
=> epRef
-> addr & s :-> Maybe (ContractRef epArg) & s
contractCalling epRef = I $
case useHasEntryPointArg @cp @epRef @epArg epRef of
(Dict, epName) -> CONTRACT starNotes epName
contractCallingUnsafe
:: forall arg s.
(NiceParameter arg)
=> EpName
-> Address & s :-> Maybe (ContractRef arg) & s
contractCallingUnsafe epName = contractCalling (TrustEpName epName)
runFutureContract
:: forall p s. (NiceParameter p)
=> FutureContract p & s :-> Maybe (ContractRef p) & s
runFutureContract =
I Nop # epAddressToContract
epAddressToContract
:: forall p s. (NiceParameter p)
=> EpAddress & s :-> Maybe (ContractRef p) & s
epAddressToContract =
I (CONTRACT starNotes DefEpName) \\ niceParameterEvi @p
transferTokens
:: forall p s. (NiceParameter p)
=> p & Mutez & ContractRef p & s :-> Operation & s
transferTokens = I $ TRANSFER_TOKENS \\ niceParameterEvi @p
setDelegate :: Maybe KeyHash & s :-> Operation & s
setDelegate = I SET_DELEGATE
createContract
:: forall p g s. (NiceStorage g, NiceParameterFull p)
=> Contract p g
-> Maybe KeyHash & Mutez & g & s
:-> Operation & Address & s
createContract cntrc =
I $ CREATE_CONTRACT (compileLorentzContract cntrc)
\\ niceParameterEvi @p
\\ niceStorageEvi @g
implicitAccount :: KeyHash & s :-> ContractRef () & s
implicitAccount = I IMPLICIT_ACCOUNT
now :: s :-> Timestamp & s
now = I NOW
amount :: s :-> Mutez & s
amount = I AMOUNT
balance :: s :-> Mutez & s
balance = I BALANCE
checkSignature :: PublicKey & Signature & ByteString & s :-> Bool & s
checkSignature = I CHECK_SIGNATURE
sha256 :: ByteString & s :-> ByteString & s
sha256 = I SHA256
sha512 :: ByteString & s :-> ByteString & s
sha512 = I SHA512
blake2B :: ByteString & s :-> ByteString & s
blake2B = I BLAKE2B
hashKey :: PublicKey & s :-> KeyHash & s
hashKey = I HASH_KEY
{-# WARNING stepsToQuota "STEPS_TO_QUOTA instruction is deprecated in Michelson 005" #-}
stepsToQuota :: s :-> Natural & s
stepsToQuota = I STEPS_TO_QUOTA
{-# WARNING source
"Using `source` is considered a bad practice.\n\
\ Consider using `sender` instead until further investigation" #-}
source :: s :-> Address & s
source = I SOURCE
sender :: s :-> Address & s
sender = I SENDER
address :: ContractRef a & s :-> Address & s
address = I ADDRESS
chainId :: s :-> ChainId & s
chainId = I CHAIN_ID
framed
:: forall s i o.
(KnownList i, KnownList o)
=> (i :-> o) -> ((i ++ s) :-> (o ++ s))
framed (iNonFailingCode -> i) =
I $ FrameInstr (Proxy @(ToTs s)) i
\\ totsKnownLemma @i
\\ totsKnownLemma @o
\\ totsAppendLemma @i @s
\\ totsAppendLemma @o @s
failingWhenPresent
:: forall c k s v st e.
( MemOpHs c, k ~ MemOpKeyHs c
, KnownValue e
, st ~ (k & v & c & s)
)
=> (forall s0. k : s0 :-> e : s0)
-> st :-> st
failingWhenPresent mkErr =
dip (dip dup # swap) # swap # dip dup # swap # mem #
if_ (mkErr # failWith) nop
updateNew
:: forall c k s e.
( UpdOpHs c, MemOpHs c, k ~ UpdOpKeyHs c, k ~ MemOpKeyHs c
, KnownValue e
)
=> (forall s0. k : s0 :-> e : s0)
-> k & UpdOpParamsHs c & c & s :-> c & s
updateNew mkErr = failingWhenPresent mkErr # update
class LorentzFunctor (c :: Kind.Type -> Kind.Type) where
lmap :: KnownValue b => (a : s :-> b : s) -> (c a : s :-> c b : s)
instance LorentzFunctor Maybe where
lmap f = ifNone none (f # some)
class NonZero t where
nonZero :: t : s :-> Maybe t : s
instance NonZero Integer where
nonZero = dup # eq0 # if_ (drop # none) some
instance NonZero Natural where
nonZero = dup # int # eq0 # if_ (drop # none) some